<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Minh Nguyen]]></title><description><![CDATA[Sydney Full Stack Web Developer]]></description><link>https://mnguyen.io</link><generator>GatsbyJS</generator><lastBuildDate>Tue, 26 Dec 2023 12:47:29 GMT</lastBuildDate><item><title><![CDATA[March 2021 design iteration of my site]]></title><description><![CDATA[I’ve been documenting the current website codebase to understand it better.
Guess that’s what happens when you pick up a system that you can…]]></description><link>https://mnguyen.io/blog/march-2021-design-iteration-of-my-site/</link><guid isPermaLink="false">https://mnguyen.io/blog/march-2021-design-iteration-of-my-site/</guid><pubDate>Tue, 23 Mar 2021 07:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been documenting the current website codebase to understand it better.
Guess that’s what happens when you pick up a system that you can easily start
with, and get to learn over time as you need it.&lt;/p&gt;
&lt;p&gt;I’m trying to structure this documentation off the &lt;a href=&quot;https://documentation.divio.com/introduction/&quot;&gt;Documentation System by
Divio&lt;/a&gt;, which breaks the act of documenting down into 4
distinct sections: &lt;em&gt;tutorials&lt;/em&gt;, &lt;em&gt;how-to guides&lt;/em&gt;, &lt;em&gt;references&lt;/em&gt;, and &lt;em&gt;explanations&lt;/em&gt;. I
might go further into this in a future blog post, so keep an eye out for that.&lt;/p&gt;
&lt;p&gt;From the changes which are visible, I’ve made changes to the design
which increases the width of the content section, provided your monitor
reports &lt;strong&gt;at least 1920px width&lt;/strong&gt;, which makes it better to view at higher
resolutions. It was getting just a bit too narrow on my ultrawide monitor.&lt;/p&gt;
&lt;p&gt;Secondly, you might have noticed at the end of articles that there’s &lt;strong&gt;a new
footer at the bottom of each blog article&lt;/strong&gt;. That will let you navigate to the
next or previous article by chronological order. There’s also a section for
comments, so readers can leave comments and questions, and I can
respond to those without having to make a new post.&lt;/p&gt;
&lt;p&gt;Lastly, I’ve made the link to the RSS feed &lt;strong&gt;a lot more visible&lt;/strong&gt;, both in the
main navigation and the footer component. There’s a bit of a small revolution
in terms of how people ingest content and the mechanisms to do so, but RSS is
pretty reliable. There’s plenty of programs/services that you can use, so I
won’t detail them here, but if you find yourself reading a lot of articles
online, it’s definitely a plus.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to use MailHog in Lando]]></title><description><![CDATA[If you’ve ever needed a service to capture e-mails, MailHog is a pretty good choice. MailHog contains an SMTP server which you send messages…]]></description><link>https://mnguyen.io/blog/how-to-use-mailhog-in-lando/</link><guid isPermaLink="false">https://mnguyen.io/blog/how-to-use-mailhog-in-lando/</guid><pubDate>Mon, 08 Feb 2021 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’ve ever needed a service to capture e-mails, &lt;a href=&quot;https://github.com/mailhog/MailHog&quot;&gt;MailHog&lt;/a&gt; is a pretty good choice. MailHog contains an SMTP server which you send messages to, simulating your production SMTP service, and provides a HTTP interface so you can see what’s being sent.&lt;/p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/acf78645fc5e7beecbfa6c1b1a622386/3fff8/charlotte-harrison-HSlyMfI_tFg-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 149.75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAgH/xAAXAQADAQAAAAAAAAAAAAAAAAACAwQB/9oADAMBAAIQAxAAAAGWuJgujGmq5pGwtyLDi//EABsQAAMAAwEBAAAAAAAAAAAAAAABAhESMQMh/9oACAEBAAEFAtsnqsDR8NiuqqNqKbymMrv/xAAaEQEAAwADAAAAAAAAAAAAAAABAAIRBCEy/9oACAEDAQE/ATj3e4mOQtXCX9M//8QAGBEAAgMAAAAAAAAAAAAAAAAAAAEQERL/2gAIAQIBAT8B1FCP/8QAHRAAAAUFAAAAAAAAAAAAAAAAAAEQITECESCh4f/aAAgBAQAGPwKi5iGNIHUYTrH/xAAdEAEAAgIDAQEAAAAAAAAAAAABACERUTGBkUGx/9oACAEBAAE/IVP5HyPXBt7ltcQKU7Yp5/UbhjUAGQVqOvHmSiLEWk//2gAMAwEAAgADAAAAEBfPMf/EABkRAQEBAAMAAAAAAAAAAAAAAAEAESExcf/aAAgBAwEBPxAAEzLsuYLvrPUL/8QAGBEAAwEBAAAAAAAAAAAAAAAAAAEhETH/2gAIAQIBAT8QyhPaOuCQ/8QAGhABAQEBAQEBAAAAAAAAAAAAAREAITFhwf/aAAgBAQABPxA4oFOHjAMkgr34znKrxmJ0jBVCsxgww5eGAhYhg+YBEB6XR/izgpV6nDJHDw9yAgNwxR5v/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/acf78645fc5e7beecbfa6c1b1a622386/7f61c/charlotte-harrison-HSlyMfI_tFg-unsplash.webp 400w,
/static/acf78645fc5e7beecbfa6c1b1a622386/d00b9/charlotte-harrison-HSlyMfI_tFg-unsplash.webp 800w,
/static/acf78645fc5e7beecbfa6c1b1a622386/fad48/charlotte-harrison-HSlyMfI_tFg-unsplash.webp 1600w,
/static/acf78645fc5e7beecbfa6c1b1a622386/46261/charlotte-harrison-HSlyMfI_tFg-unsplash.webp 2400w,
/static/acf78645fc5e7beecbfa6c1b1a622386/919bf/charlotte-harrison-HSlyMfI_tFg-unsplash.webp 3200w,
/static/acf78645fc5e7beecbfa6c1b1a622386/06b54/charlotte-harrison-HSlyMfI_tFg-unsplash.webp 3836w&quot;
              sizes=&quot;(max-width: 1600px) 100vw, 1600px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/acf78645fc5e7beecbfa6c1b1a622386/066f9/charlotte-harrison-HSlyMfI_tFg-unsplash.jpg 400w,
/static/acf78645fc5e7beecbfa6c1b1a622386/4b190/charlotte-harrison-HSlyMfI_tFg-unsplash.jpg 800w,
/static/acf78645fc5e7beecbfa6c1b1a622386/b17f8/charlotte-harrison-HSlyMfI_tFg-unsplash.jpg 1600w,
/static/acf78645fc5e7beecbfa6c1b1a622386/df51d/charlotte-harrison-HSlyMfI_tFg-unsplash.jpg 2400w,
/static/acf78645fc5e7beecbfa6c1b1a622386/01fc7/charlotte-harrison-HSlyMfI_tFg-unsplash.jpg 3200w,
/static/acf78645fc5e7beecbfa6c1b1a622386/3fff8/charlotte-harrison-HSlyMfI_tFg-unsplash.jpg 3836w&quot;
            sizes=&quot;(max-width: 1600px) 100vw, 1600px&quot;
            type=&quot;image/jpeg&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/acf78645fc5e7beecbfa6c1b1a622386/b17f8/charlotte-harrison-HSlyMfI_tFg-unsplash.jpg&quot;
            alt=&quot;A post box with frost around its edges&quot;
            title=&quot;A post box with frost around its edges&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@charlottelharrison?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Charlotte Harrison&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/postbox?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It isn’t a substitute for your production mail service or e-mail client, so you’ll still need to plug it all in for testing, and make sure to check in a variety of e-mail clients. This is good if you need to debug why e-mail clients are rendering your messages strangely and need to experiment.&lt;/p&gt;
&lt;p&gt;With that in mind, I’ll show you how to add a MailHog service in &lt;a href=&quot;https://lando.dev&quot;&gt;Lando&lt;/a&gt; via the Landofile &lt;code class=&quot;language-text&quot;&gt;.lando.yml&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;You know how to run Lando&lt;/li&gt;
&lt;li&gt;You have an application which sends messages via SMTP&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Setting up your Landofile&lt;/h2&gt;
&lt;p&gt;In your Landofile (&lt;code class=&quot;language-text&quot;&gt;.lando.yml&lt;/code&gt;), add a new section for services. If your Landofile already has one, you can append to it instead. Below I define a new service called &lt;code class=&quot;language-text&quot;&gt;mail&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .lando.yml&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# ...the rest of the YAML config sits above here&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;mail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mailhog&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’re almost ready to go, but we need to provide information about which services need to be able to access MailHog. To do that, define a key labelled &lt;code class=&quot;language-text&quot;&gt;hogfrom&lt;/code&gt;, and list all our services. In this case, &lt;code class=&quot;language-text&quot;&gt;appserver&lt;/code&gt; is responsible for sending our message:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .lando.yml&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# ...the rest of the YAML config sits above here&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;mail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mailhog
    &lt;span class=&quot;token key atrule&quot;&gt;hogfrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; appserver&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Run &lt;code class=&quot;language-text&quot;&gt;lando rebuild&lt;/code&gt;, which should rebuild your stack, including the new MailHog service. In the output where you see a list of URLs you can access your app from, you should now see a &lt;code class=&quot;language-text&quot;&gt;localhost&lt;/code&gt; URL that you can open to access the MailHog interface.&lt;/p&gt;
&lt;h2&gt;Configuring your web app&lt;/h2&gt;
&lt;p&gt;In your web app, you will need to change the SMTP configuration so it points at MailHog. In Drupal, this can be done by overriding the system configuration in &lt;code class=&quot;language-text&quot;&gt;settings.local.php&lt;/code&gt;. This may differ depending on your specific application, so I can’t help with that.&lt;/p&gt;
&lt;p&gt;In terms of credentials and URLs, here is what you can use to connect to MailHog’s SMTP server:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hostname: &lt;code class=&quot;language-text&quot;&gt;mail&lt;/code&gt;—same as the name we gave the service above&lt;/li&gt;
&lt;li&gt;Port: 1025&lt;/li&gt;
&lt;li&gt;Username: as desired&lt;/li&gt;
&lt;li&gt;Password: as desired&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Some questions&lt;/h2&gt;
&lt;h3&gt;Couldn’t I just run MailHog outside of Lando or Docker?&lt;/h3&gt;
&lt;p&gt;Sure, but Lando exists as a way to lock down those tools so your colleagues don’t have to figure out how to install MailHog, or ask you how to install it.&lt;/p&gt;
&lt;h3&gt;Wasn’t MailHog development suspended?&lt;/h3&gt;
&lt;p&gt;It was for some time, but development picked up again and a new release &lt;a href=&quot;https://github.com/mailhog/MailHog/releases/tag/v1.0.1&quot;&gt;1.0.1 was put out August 12 2020&lt;/a&gt;. I was a bit surprised as well, since the last official release 1.0.0 was in 2017.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to install ClamAV in Lando for Drupal]]></title><description><![CDATA[ClamAV is an antivirus software service which allows servers to scan for viruses. While it is notable for use in scanning for viruses on…]]></description><link>https://mnguyen.io/blog/how-to-install-clamav-in-lando-for-drupal/</link><guid isPermaLink="false">https://mnguyen.io/blog/how-to-install-clamav-in-lando-for-drupal/</guid><pubDate>Tue, 02 Feb 2021 23:00:00 GMT</pubDate><content:encoded>&lt;p&gt;ClamAV is an antivirus software service which allows servers to scan for viruses. While it is notable for use in scanning for viruses on mail servers, we can also use it in our web applications to scan file uploads.&lt;/p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/fef89/n-bandaru-Oh4drRbSYks-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAQAF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAAdWCaZj/xAAXEAADAQAAAAAAAAAAAAAAAAAAARAx/9oACAEBAAEFAqxaf//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABUQAQEAAAAAAAAAAAAAAAAAABAx/9oACAEBAAY/Amv/xAAbEAABBAMAAAAAAAAAAAAAAAABABARQSFRYf/aAAgBAQABPyE8bNFBJBkIrbn/2gAMAwEAAgADAAAAEKAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAACH/2gAIAQIBAT8QV//EABwQAQADAAIDAAAAAAAAAAAAAAEAESExQXGB8f/aAAgBAQABPxC14PcxKXTsj8lxRxXsOeUSq2cT/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/7f61c/n-bandaru-Oh4drRbSYks-unsplash.webp 400w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/d00b9/n-bandaru-Oh4drRbSYks-unsplash.webp 800w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/fad48/n-bandaru-Oh4drRbSYks-unsplash.webp 1600w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/46261/n-bandaru-Oh4drRbSYks-unsplash.webp 2400w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/919bf/n-bandaru-Oh4drRbSYks-unsplash.webp 3200w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/ce234/n-bandaru-Oh4drRbSYks-unsplash.webp 4280w&quot;
              sizes=&quot;(max-width: 1600px) 100vw, 1600px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/066f9/n-bandaru-Oh4drRbSYks-unsplash.jpg 400w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/4b190/n-bandaru-Oh4drRbSYks-unsplash.jpg 800w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/b17f8/n-bandaru-Oh4drRbSYks-unsplash.jpg 1600w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/df51d/n-bandaru-Oh4drRbSYks-unsplash.jpg 2400w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/01fc7/n-bandaru-Oh4drRbSYks-unsplash.jpg 3200w,
/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/fef89/n-bandaru-Oh4drRbSYks-unsplash.jpg 4280w&quot;
            sizes=&quot;(max-width: 1600px) 100vw, 1600px&quot;
            type=&quot;image/jpeg&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/2dd5e97ef06abb5c9f996cee7ce9f2e6/b17f8/n-bandaru-Oh4drRbSYks-unsplash.jpg&quot;
            alt=&quot;A solitary hermit crab on some sand&quot;
            title=&quot;A solitary hermit crab on some sand&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nbandana?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;N Bandaru&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/shell?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’m doing some local development on a Drupal based site, which makes use of &lt;a href=&quot;https://www.drupal.org/project/clamav&quot;&gt;ClamAV through a contributed module&lt;/a&gt; to scan files uploaded to the site.&lt;/p&gt;
&lt;p&gt;Having the module enabled but not having ClamAV on the system throws an error:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 838px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/bfa3a48eea426e8650bce6d1895a8f91/a1dd2/drupal-clamav-upload-error.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 44.75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABIElEQVQoz6WSy07DMBBF/f9fxoIFCyQo0LQNakgb8nBsx++5yHEoBVQBYqSje8fyjC172LFpwPmAaVJwzv6Ag7UGMUakoIXzYOPQo+ta9H2PcRwhpICUInvxQVpLmg733udqyi0pxgxFMHNzBbMvIcsCYvsE+c6ugCw3EJtH6EMF27/CtkfYtjnTBrZr4AVHkCPipMD87TWCEnOhKB4gt0lXEOvVnOt6D9PUmePLolX2S+55n5sqCcZ3BTQfQGZCmBSCVoh6AjkL8g7k/aKXic4iWjN7Vq7XKO7uoatnTGUBU+8RhhYU/LeHpwt8+hTedWgONZzWiM4hpJulZvR16++CjUKiHwZIpU5EIkSK83j8BSICqzozj0gI4TQK9A/eADdlu6mags47AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/bfa3a48eea426e8650bce6d1895a8f91/7f61c/drupal-clamav-upload-error.webp 400w,
/static/bfa3a48eea426e8650bce6d1895a8f91/d00b9/drupal-clamav-upload-error.webp 800w,
/static/bfa3a48eea426e8650bce6d1895a8f91/7820a/drupal-clamav-upload-error.webp 838w&quot;
              sizes=&quot;(max-width: 838px) 100vw, 838px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/bfa3a48eea426e8650bce6d1895a8f91/e17e5/drupal-clamav-upload-error.png 400w,
/static/bfa3a48eea426e8650bce6d1895a8f91/5a190/drupal-clamav-upload-error.png 800w,
/static/bfa3a48eea426e8650bce6d1895a8f91/a1dd2/drupal-clamav-upload-error.png 838w&quot;
            sizes=&quot;(max-width: 838px) 100vw, 838px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/bfa3a48eea426e8650bce6d1895a8f91/a1dd2/drupal-clamav-upload-error.png&quot;
            alt=&quot;Error message from Drupal whilst uploading a file, reading &amp;#39;The anti-virus scanner could not check the file, so the file cannot be uploaded.&amp;#39;&quot;
            title=&quot;Error message from Drupal whilst uploading a file, reading &amp;#39;The anti-virus scanner could not check the file, so the file cannot be uploaded.&amp;#39;&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You could just uninstall the ClamAV module and work without it, but that introduces a potential gap in your test coverage—the behaviour of the site operates differently without the module installed, which could lead to issues that you don’t discover until later.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;You know how to run &lt;a href=&quot;https://lando.dev/&quot;&gt;Lando&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Your application is configured to scan file uploads e.g. in Drupal, the &lt;a href=&quot;https://www.drupal.org/project/clamav&quot;&gt;ClamAV module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Setting up your Landofile&lt;/h2&gt;
&lt;p&gt;In your Landofile (&lt;code class=&quot;language-text&quot;&gt;.lando.yml&lt;/code&gt;), we will use the services section to modify the main application service—in our case labelled &lt;code class=&quot;language-text&quot;&gt;appserver&lt;/code&gt; to install ClamAV:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .lando.yml&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# ...the rest of the YAML config sits above here&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;appserver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;build_as_root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; apt&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;get update &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;y
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; apt&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;get install clamav clamav&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;daemon &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;y
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; echo &quot;TCPSocket 3310&quot; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; /etc/clamav/clamd.conf
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; freshclam
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; update&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;rc.d clamav&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;daemon enable
    &lt;span class=&quot;token key atrule&quot;&gt;run_as_root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; service clamav&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;daemon start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This sets up the commands to run that installs ClamAV, sets up the ability to connect to the service on port &lt;code class=&quot;language-text&quot;&gt;3310&lt;/code&gt;, update the database definitions necessary to scan files, and then enable the ClamAV service.&lt;/p&gt;
&lt;p&gt;Note here that we are using &lt;code class=&quot;language-text&quot;&gt;apt-get&lt;/code&gt; to install the packages as the base container images that Lando uses are from Debian. You may need to adjust if your base distribution is different.&lt;/p&gt;
&lt;p&gt;Once the changes are made, rebuild the service with &lt;code class=&quot;language-text&quot;&gt;lando rebuild&lt;/code&gt;. This will relaunch your application, install ClamAV into your local container, and start it.&lt;/p&gt;
&lt;p&gt;I can now load up my environment and confirm that ClamAV is successfully loaded, and that file uploads work:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 789px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/70dfc84c2f993385858954dcf8c43386/44fd6/drupal-clamav-upload-success.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 42.25%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABAElEQVQoz5WRTUrEQBCF+1wyt1K8iRvBI7hx5QkEYdCFiCtBiUFiEtL/Sf8kT6rGSEYzoA8+iq6ufnT3E0PvobWCMRp1XUNKCWMMlJLcV0p97xO0ppmcM0jTNGEp8fzyiu3dPYqiQIiRB4mU0h7LPtXZ6Jfh2fkFjjYbHJ+coh/C6tAhrc2Jp8cHXF9dYnt7gxQj/ioyW0NYZ9FJibZt0TUNck6IMSyITEo7qEf1kITWGuVbgfqj4s+mAKw18N5zOHMwtDcHRIE55xiao2qt5f8Vzmk0nYbxA0LY3YgOVdU7G9MzxnH8Yvqx3oefHKOHDSNMH+GcZVNjFMqyYMP/6hOlhGuCtKEFXgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/70dfc84c2f993385858954dcf8c43386/7f61c/drupal-clamav-upload-success.webp 400w,
/static/70dfc84c2f993385858954dcf8c43386/2009c/drupal-clamav-upload-success.webp 789w&quot;
              sizes=&quot;(max-width: 789px) 100vw, 789px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/70dfc84c2f993385858954dcf8c43386/e17e5/drupal-clamav-upload-success.png 400w,
/static/70dfc84c2f993385858954dcf8c43386/44fd6/drupal-clamav-upload-success.png 789w&quot;
            sizes=&quot;(max-width: 789px) 100vw, 789px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/70dfc84c2f993385858954dcf8c43386/44fd6/drupal-clamav-upload-success.png&quot;
            alt=&quot;File upload success&quot;
            title=&quot;File upload success&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Furthermore, we can use the &lt;a href=&quot;https://en.wikipedia.org/wiki/EICAR_test_file&quot;&gt;EICAR test file&lt;/a&gt; to confirm that it does block viruses from being uploaded:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 717px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/59f3aee853e6c0422040c8f353e5b8d1/0ad97/drupal-clamav-upload-blocked.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 42%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABA0lEQVQoz52M20rEQBBE5/+/ylcREVFE95b7ZRfNJpnJTHYzM0cSCWQxL1pwqO7qokV+OnKII4I4ZheG7IKAr68TUtb/QlyVwpgL5urRF8dl8EzyHpy79SVjtoLo7+/Qr4/oMqULt3TRDhXuUNEeFR/okuDH0xB52GCOGdemYpD1KmJ4eYDqxNCc0UWKKbPJdRYvPEFn0cT42BxzbCexqv2FOJcFwcc7VZpgZcPQNlPZmQ5vLavyHu/sKuJc5Lw9PVNuN/RJgI729EWKrT7xveavElJKijynrmuc91hrcc5NPjMMw828ZJmNszDG0LYt42Ot9eQjY6aUmpj3+bbszL35/g3vTWiGb5mQGQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/59f3aee853e6c0422040c8f353e5b8d1/7f61c/drupal-clamav-upload-blocked.webp 400w,
/static/59f3aee853e6c0422040c8f353e5b8d1/4bde0/drupal-clamav-upload-blocked.webp 717w&quot;
              sizes=&quot;(max-width: 717px) 100vw, 717px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/59f3aee853e6c0422040c8f353e5b8d1/e17e5/drupal-clamav-upload-blocked.png 400w,
/static/59f3aee853e6c0422040c8f353e5b8d1/0ad97/drupal-clamav-upload-blocked.png 717w&quot;
            sizes=&quot;(max-width: 717px) 100vw, 717px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/59f3aee853e6c0422040c8f353e5b8d1/0ad97/drupal-clamav-upload-blocked.png&quot;
            alt=&quot;A file we try to upload, but was blocked by the anti-virus&quot;
            title=&quot;A file we try to upload, but was blocked by the anti-virus&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Possible future changes&lt;/h2&gt;
&lt;p&gt;I could set out these changes in a custom service, or alternatively use a prebuilt container for ClamAV. Of course, the current hosting environment assumes ClamAV running on &lt;code class=&quot;language-text&quot;&gt;localhost&lt;/code&gt; on a TCP port so it’s not practical to modify it for that yet.&lt;/p&gt;
&lt;p&gt;Hopefully this has been a useful guide in how to have ClamAV set up for your Drupal site. If you’re not running Drupal, hopefully you’ll find it useful if you’re integrating ClamAV for your own applications and infrastructure.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Annotating my pages with microformats2 and h-entry]]></title><description><![CDATA[h-entry is an open microformat for datestamped content on the web. I was looking
at ways to make my site a bit more open to syndication, and…]]></description><link>https://mnguyen.io/blog/annotating-pages-microformats2-h-entry/</link><guid isPermaLink="false">https://mnguyen.io/blog/annotating-pages-microformats2-h-entry/</guid><pubDate>Wed, 30 Sep 2020 10:26:00 GMT</pubDate><content:encoded>&lt;p&gt;h-entry is an open microformat for datestamped content on the web. I was looking
at ways to make my site a bit more open to syndication, and also as an
alternative to RSS/Atom feeds. I haven’t seen major browsers pick up on these
formats, but the main focus are IndieWeb readers, and I’m all for them.&lt;/p&gt;
&lt;p&gt;Now, please note that this post isn’t much of a guide to implementing h-entry or
other parts of the microformats2 spec on your site, as it is a summary of I went
about implementing it for this website.&lt;/p&gt;
&lt;h3&gt;What it looks like&lt;/h3&gt;
&lt;p&gt;h-entry looks something like this, after parsing a HTML page:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;h-entry&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;My blog post&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;John Smith&quot;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;published&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;2020-01-01 12:00:00&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;summary&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;A short summary of my blog post, and what you can do.&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Starting paragraph of my blog post.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;html&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;p&gt;Starting paragraph of my blog post.&amp;lt;/p&gt;&quot;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In short, there’s basically all of the information about the post, in a
JSON object that could be easily be used as part of a different app. With that
in mind, how does a parser go about doing this?&lt;/p&gt;
&lt;h3&gt;Elements of h-entry&lt;/h3&gt;
&lt;p&gt;h-entry itself is a what is known as a root class name. We can use it to
define a h-entry, and it has a series of properties that the parser will
determine, based on knowing that. Other root class names include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;h-adr&lt;/li&gt;
&lt;li&gt;h-event&lt;/li&gt;
&lt;li&gt;h-geo&lt;/li&gt;
&lt;li&gt;h-item&lt;/li&gt;
&lt;li&gt;h-product&lt;/li&gt;
&lt;li&gt;h-recipe&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find a more detailed list of these on the &lt;a href=&quot;https://microformats.org/wiki/microformats2&quot;&gt;microformats2
page&lt;/a&gt;, along with examples and
detailed descriptions.&lt;/p&gt;
&lt;p&gt;Back to h-entry, we can establish this simply by naming it as a class:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;h-entry&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
...
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and that’s it, our article is now parseable as it is, though it might
not be very useful by itself. This is where we add some core h-entry
properties!&lt;/p&gt;
&lt;h3&gt;h-entry properties&lt;/h3&gt;
&lt;p&gt;There’s quite an amount of these, so I’ll only go with the
properties that I used for this site.&lt;/p&gt;
&lt;h4&gt;p-name&lt;/h4&gt;
&lt;p&gt;This represents the entry name or title. For the title, we just need to add
this class to the element that contains it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;p-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{post.frontmatter.title}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;e-content&lt;/h4&gt;
&lt;p&gt;The full content of the entry in question i.e. the full body of the blog post:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;e-content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;...&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;dt-published&lt;/h4&gt;
&lt;p&gt;The datestamp of when the entry was published:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;time&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;dt-published&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2020-09-29&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;29 September, 2020&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Implementing h-entry within a Gatsby content type&lt;/h3&gt;
&lt;p&gt;Let’s get topical! For this, I’m using
&lt;a href=&quot;/blog/my-gatsby-setup/&quot;&gt;Gatsby&lt;/a&gt; as my site generator, so in order to get this
working for my blog post, I need to modify the template for the blog
post’s render function (located in &lt;code class=&quot;language-text&quot;&gt;/src/templates/blog-post.js&lt;/code&gt;), which
returns JSX as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; post &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;markdownRemark
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Layout&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SEO&lt;/span&gt; title&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; description&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;excerpt&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;h-entry&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1 style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;marginBottom&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;0.5rem&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;p-name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;draft &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Draft&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;time className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dt-published&quot;&lt;/span&gt; dateTime&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;htmldate&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;time&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e-content&quot;&lt;/span&gt; dangerouslySetInnerHTML&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; __html&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;html &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Layout&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can see that the 2 &lt;code class=&quot;language-text&quot;&gt;section&lt;/code&gt;, the &lt;code class=&quot;language-text&quot;&gt;h1&lt;/code&gt;, and the &lt;code class=&quot;language-text&quot;&gt;time&lt;/code&gt; elements are
updated as above to have the microformat2 elements defined via the &lt;code class=&quot;language-text&quot;&gt;className&lt;/code&gt;
attribute. While I was able to get it working on these generic HTML elements,
I wasn’t able to get it working for the &lt;code class=&quot;language-text&quot;&gt;time&lt;/code&gt; element, which was
previously a separate element called &lt;code class=&quot;language-text&quot;&gt;&amp;lt;DateTime&amp;gt;&lt;/code&gt;. I couldn’t figure it
out, so I reverted to using the base element that it represented.&lt;/p&gt;
&lt;h2&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://microformats.org/wiki/microformats2&quot;&gt;microformats2 on microformats.org&lt;/a&gt;: has a lot of information about microformat types that I’ve only just touched on in this post.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://microformats.org/wiki/h-entry&quot;&gt;h-entry on microformats.org&lt;/a&gt;: provides information specific about h-entry, including some other optional properties I didn’t use in this post.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://indieweb.org/h-entry&quot;&gt;h-entry on indieweb.org&lt;/a&gt;: has some extra reasoning why you should use h-entry, as well as examples and use cases spanning from it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Implementing a microformat isn’t difficult, and can provide new ways for people to access your content. Give it a go!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Running NixOS in Production]]></title><description><![CDATA[NixOS logo I’ve moved some items from my previous site infrastructure over to a VPS powered running NixOS in the past weekend. What made me…]]></description><link>https://mnguyen.io/blog/running-nixos-in-production/</link><guid isPermaLink="false">https://mnguyen.io/blog/running-nixos-in-production/</guid><pubDate>Thu, 17 Sep 2020 08:16:00 GMT</pubDate><content:encoded>&lt;figure&gt;
&lt;p&gt;&lt;img src=&quot;/files/91e49ba4259b9d2e13357e23d2290bdc/nixos-social-preview.svg&quot; alt=&quot;NixOS logo&quot;&gt;&lt;/p&gt;
&lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;&lt;p&gt;
  &lt;a href=&quot;https://github.com/NixOS/nixos-artwork/tree/master/logo&quot; rel=&quot;noopener&quot;&gt;NixOS logo&lt;/a&gt; created by Tim Cuthbertson (&lt;a href=&quot;https://twitter.com/timbertson&quot; rel=&quot;noopener&quot;&gt;@timbertson&lt;/a&gt;), licenced under &lt;a class=&quot;link--breakless&quot; href=&quot;https://creativecommons.org/licenses/by/4.0/&quot; rel=&quot;noopener&quot;&gt;CC-BY&amp;nbsp;4.0&lt;/a&gt;.
&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve moved some items from my previous site infrastructure over to a VPS powered running NixOS in the past weekend. What made me do it? There were a few reasons that came to mind for it.&lt;/p&gt;
&lt;!-- Why I did it
    - My previous environment was an Ubuntu Xenial (16.04) environment that has progressively broken down in terms of packaging
    - I remember only a few things about setting it up, I don&apos;t know everything that went into its setup
    - NixOS provides a declarative language which allows me to define configuration as code
    - I already manage CentOS environments, I wanted to try something new
    - I wanted to know how application deployment and management works in NixOS
 --&gt;
&lt;p&gt;The first is that I’m sort of done running on OpenVZ—the performance is pretty bare compared to other options out there. There’s only a few choices for operating systems to run on it. Ubuntu 16.04 (Xenial) is okay to work with, but on the limited resources, things always took a lot longer than they should have, whether it was running &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost&lt;/a&gt; or trying to build this site on Gatsby.&lt;/p&gt;
&lt;p&gt;Another reason for doing this is that I don’t remember a lot of the things I did setting up the site. Could I tell you I installed &lt;a href=&quot;https://certbot.eff.org/&quot;&gt;Certbot&lt;/a&gt;? Nope. Could I recite the hundred word set of compiler arguments to make I compiled &lt;a href=&quot;https://www.modpagespeed.com/doc/build_ngx_pagespeed_from_source&quot;&gt;nginx with Pagespeed&lt;/a&gt; support? Nope. Would I know how to update PHP from 7.2 once it reaches &lt;a href=&quot;https://www.php.net/supported-versions.php&quot;&gt;end of life&lt;/a&gt;? Nope—I’d have to look that one up (and I already have to do that in my day to day work!).&lt;/p&gt;
&lt;p&gt;I could have picked any other OS to operate, like Debian or CentOS. But I ended up on NixOS for the following reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I wanted to learn more about NixOS, and how to run through application deployment and management to see how it stacks up against other methods.&lt;/li&gt;
&lt;li&gt;The idea of declaring my system configuration as code I could deploy was interesting to me, since I spend a lot of time running through package installation and configuration in my day-to-day—making that process easier would definitely give me time to do other things.&lt;/li&gt;
&lt;/ol&gt;
&lt;!-- Details
  - I had Nix installed on my Archlinux machine
  - I followed a guide which built images from a haskell script, but it didn&apos;t work so I created a monstrosity of an elixir file instead
  - Issues with the syntax of the Nix configuration would lead it to try and proceed (@TODO)
  - Running Caddy 2
  - Move from Matomo to Fathom analytics - mainly reasons around the DB layer and not wanting to support the PHP platform as much
  - That&apos;s my day job already
  - Maybe a link to the repo would be good?
  - Suggest readers could get in touch about fixing some things up
  - Note that Caddy 2 is in an interesting situation right now in packaging, so it should stablise soon --&gt;
&lt;h2&gt;Some of the details&lt;/h2&gt;
&lt;p&gt;For some context, I have Nix installed on my Arch Linux system (there’s a useful guide to install it &lt;a href=&quot;https://wiki.archlinux.org/index.php/Nix&quot;&gt;on their wiki&lt;/a&gt;). From there, it was a matter of putting together a few pieces of configuration. The build script itself is powered by Elixir—mainly a result of the fact I couldn’t get the Haskell script in the guide I was following to work.&lt;/p&gt;
&lt;p&gt;The VPS is an Amazon EC2 instance, which was created using the &lt;a href=&quot;https://nixos.org/download.html&quot;&gt;instructions provided by NixOS&lt;/a&gt; to launch a provided Amazon Machine Image (AMI).&lt;/p&gt;
&lt;p&gt;The first stop is &lt;code class=&quot;language-text&quot;&gt;server.nix&lt;/code&gt;, which is built like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;nix&quot;&gt;&lt;pre class=&quot;language-nix&quot;&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
  nixos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token url&quot;&gt;nixpkgs/nixos&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    configuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;./configuration.nix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
  nixos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;system&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;configuration.nix&lt;/code&gt; contains the bulk of the configuration which is set up on the system:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;nix&quot;&gt;&lt;pre class=&quot;language-nix&quot;&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pkgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
  unstable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;nixos&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;unstable&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  imports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token url&quot;&gt;nixpkgs/nixos/modules/virtualisation/amazon-image.nix&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;./users.nix&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;./firewall.nix&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;./webserver.nix&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hvm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  networking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mnguyen-nix-demo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  environment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;systemPackages &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    unstable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caddy2
    pkgs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fish
    pkgs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;htop
    pkgs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mosh
    pkgs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vim
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  programs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fish&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;# sudo without requiring password&lt;/span&gt;
  security&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sudo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wheelNeedsPassword &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;## Enable BBR module&lt;/span&gt;
  boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kernelModules &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tcp_bbr&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;## Network hardening and performance&lt;/span&gt;
  boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kernel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sysctl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Disable magic SysRq key&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;kernel.sysrq&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Ignore ICMP broadcasts to avoid participating in Smurf attacks&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.icmp_echo_ignore_broadcasts&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Ignore bad ICMP errors&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.icmp_ignore_bogus_error_responses&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Reverse-path filter for spoof protection&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.conf.default.rp_filter&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.conf.all.rp_filter&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# SYN flood protection&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.tcp_syncookies&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Do not accept ICMP redirects (prevent MITM attacks)&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.conf.all.accept_redirects&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.conf.default.accept_redirects&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.conf.all.secure_redirects&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.conf.default.secure_redirects&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv6.conf.all.accept_redirects&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv6.conf.default.accept_redirects&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Do not send ICMP redirects (we are not a router)&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.conf.all.send_redirects&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Do not accept IP source route packets (we are not a router)&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.conf.all.accept_source_route&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv6.conf.all.accept_source_route&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Protect against tcp time-wait assassination hazards&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.tcp_rfc1337&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# TCP Fast Open (TFO)&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.tcp_fastopen&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;## Bufferbloat mitigations&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Requires &gt;= 4.9 &amp;amp; kernel module&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.ipv4.tcp_congestion_control&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bbr&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Requires &gt;= 4.19&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;net.core.default_qdisc&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cake&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;# disable passwordless SSH&lt;/span&gt;
  services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;openssh&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;passwordAuthentication &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;# Let trusted users upload unsigned packages&lt;/span&gt;
  nix&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trustedUsers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@wheel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;# Clean up packages after a while&lt;/span&gt;
  nix&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    automatic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dates &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;weekly UTC&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;# Disable reinitialisation of AMI on restart or power cycle&lt;/span&gt;
  systemd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;amazon&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;init&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  swapDevices &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      device &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/swapfile&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      priority &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  systemd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fathom &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    description &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fathom Server&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    requires &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;network.target&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    after &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;network.target&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    wantedBy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;multi-user.target&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    serviceConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      Type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;simple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      User &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;minh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Restart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;on-failure&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      RestartSec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      WorkingDirectory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/var/lib/fathom&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      ExecStart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/home/minh/bin/fathom --config=/etc/fathom.env server&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;imports&lt;/code&gt; pulls in specific NixOS configuration for EC2 which it’s running on, and I’ve started work separating out configuration to separate files, &lt;code class=&quot;language-text&quot;&gt;./users.nix&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;./firewall.nix&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;./webserver.nix&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Packages&lt;/h3&gt;
&lt;p&gt;You can see near the top of &lt;code class=&quot;language-text&quot;&gt;configuration.nix&lt;/code&gt; there’s a variable called &lt;code class=&quot;language-text&quot;&gt;environment.systemPackages&lt;/code&gt;. This lists all the additional software packages I want installed. In this case, I have &lt;a href=&quot;https://fishshell.com/&quot;&gt;fish&lt;/a&gt;, &lt;a href=&quot;https://htop.dev/&quot;&gt;htop&lt;/a&gt;, &lt;a href=&quot;https://mosh.org/&quot;&gt;mosh&lt;/a&gt;, and &lt;a href=&quot;https://www.vim.org/&quot;&gt;vim&lt;/a&gt; installed from the standard repo, as well as &lt;a href=&quot;https://caddyserver.com/&quot;&gt;Caddy 2&lt;/a&gt; from the unstable NixOS branch.&lt;/p&gt;
&lt;h3&gt;Swap&lt;/h3&gt;
&lt;p&gt;I don’t have any swap on the system, so the variable &lt;code class=&quot;language-text&quot;&gt;swapdevices&lt;/code&gt; is set to create a swap file at &lt;code class=&quot;language-text&quot;&gt;/swapfile&lt;/code&gt;. The size is defined in megabytes, so this file is 1 gigabyte in size.&lt;/p&gt;
&lt;h3&gt;Firewall&lt;/h3&gt;
&lt;p&gt;NixOS comes with a firewall setup out of the box to only be open for SSH on port 22. To change it up, we can set &lt;code class=&quot;language-text&quot;&gt;networking.firewall.allowedTCPPorts&lt;/code&gt; as a list of ports we want to be open.&lt;/p&gt;
&lt;p&gt;I also want to move the default SSH port to something else, this is defined by &lt;code class=&quot;language-text&quot;&gt;services.openssh.listenAddresses&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the end, my &lt;code class=&quot;language-text&quot;&gt;firewall.nix&lt;/code&gt; file looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;nix&quot;&gt;&lt;pre class=&quot;language-nix&quot;&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pkgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# SSHD Port reassignment&lt;/span&gt;
  services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;openssh&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;listenAddresses &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; addr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;37586&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;# Allowed TCP range&lt;/span&gt;
  networking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firewall&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;allowedTCPPorts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;37586&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;# Allow Mosh connections&lt;/span&gt;
  networking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firewall&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;allowedUDPPortRanges &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; from &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; to &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60010&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Caddy server&lt;/h3&gt;
&lt;p&gt;Moving on, I set up the web server within &lt;code class=&quot;language-text&quot;&gt;webserver.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;nix&quot;&gt;&lt;pre class=&quot;language-nix&quot;&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pkgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
  unstable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;nixos&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;unstable&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  caddyDir &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/var/lib/caddy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  caddyConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writeText &lt;span class=&quot;token string&quot;&gt;&quot;Caddyfile&quot;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;&apos;{
  storage file_system {
    root /var/lib/caddy
  }
}
mnguyen.io {
  root * /srv/www/mnguyen.io
  file_server
  header / {
    X-Content-Type-Options &quot;nosniff&quot;
    X-Frame-Options &quot;sameorigin&quot;
    Referrer-Policy &quot;no-referrer-when-downgrade&quot;
    X-UA-Compatible &quot;IE=edge,chrome=1&quot;
    X-XSS-Protection &quot;1; mode=block&quot;
    Strict-Transport-Security &quot;max-age=31536000; includeSubDomains; preload&quot;
    Content-Security-Policy &quot;default-src &apos;self&apos;; connect-src https://analytics.mnguyen.io &apos;self&apos;; font-src &apos;self&apos; data:; img-src https://analytics.mnguyen.io &apos;self&apos; data:; script-src https://analytics.mnguyen.io &apos;self&apos; &apos;unsafe-inline&apos;; style-src &apos;unsafe-inline&apos;; worker-src &apos;self&apos;; prefetch-src &apos;self&apos;; report-uri https://mnguyen.report-uri.com/r/d/csp/enforce; report-to https://mnguyen.report-uri.com/r/d/csp/enforce&quot;
  }
}

www.mnguyen.io {
  redir https://mnguyen.io{uri}
}

analytics.mnguyen.io {
  reverse_proxy localhost:9000
}
&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  systemd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caddy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    description &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Caddy web server&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    after &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;network-online.target&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    wants &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;network-online.target&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    wantedBy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;multi-user.target&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    serviceConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      User &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;caddy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Group &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;caddy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      ExecStart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;
        &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token antiquotation variable&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;unstable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caddy2&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/bin/caddy run --config &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token antiquotation variable&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;caddyConfig&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; --adapter caddyfile
      &apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      ExecReload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;
        &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token antiquotation variable&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;unstable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caddy2&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/bin/caddy reload --config &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token antiquotation variable&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;caddyConfig&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; --adapter caddyfile
      &apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      TimeoutStopSec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      LimitNOFILE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1048576&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      LimitNPROC &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      PrivateTmp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      ProtectSystem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;full&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      AmbientCapabilities &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cap_net_bind_service&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caddy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    group &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;caddy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    uid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caddy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    home &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; caddyDir&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    createHome &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    extraGroups &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;users&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;groups&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caddy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caddy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What this does is set up the &lt;code class=&quot;language-text&quot;&gt;Caddyfile&lt;/code&gt; that Caddy 2 will be using, as well as the systemd service which sets up the command, sets the capabilities of the service so it can run at lower port numbers (below 1024 to be precise), and sets up a dedicated &lt;code class=&quot;language-text&quot;&gt;caddy&lt;/code&gt; user which it will run under.&lt;/p&gt;
&lt;h3&gt;Users&lt;/h3&gt;
&lt;p&gt;Speaking of which, users in NixOS can be defined in a few lines. This is what can go into &lt;code class=&quot;language-text&quot;&gt;users.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;nix&quot;&gt;&lt;pre class=&quot;language-nix&quot;&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pkgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;minh &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    isNormalUser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    extraGroups &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;wheel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    shell &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fish&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# password = &quot;my secure password&quot;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# hashedPassword = &quot;$6$qTK.7QsrnONOr$ZsAfPlnEPLtpiO9j1qp/POkDga2LtK1UOD0nrG497CegYEq5e.E6iHf5tDqwfLViBSWEsw8sn5t885p6HyRgS1&quot;;&lt;/span&gt;

    openssh&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizedKeys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;ssh-rsa PUBLICKEYHERE&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The flag &lt;code class=&quot;language-text&quot;&gt;isNormalUser&lt;/code&gt; tells NixOS to give us a home directory at &lt;code class=&quot;language-text&quot;&gt;/home/minh&lt;/code&gt;. I then set up &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt; access by adding this user to the &lt;code class=&quot;language-text&quot;&gt;wheel&lt;/code&gt; group, set the shell to fish, and set the allowed SSH key that is allowed to access this user on the system—I cannot sign in with a password unless it’s explicitly set.&lt;/p&gt;
&lt;p&gt;If I did want to set a password, I could use the insecure option &lt;code class=&quot;language-text&quot;&gt;password&lt;/code&gt; which is a string, or slightly more secure &lt;code class=&quot;language-text&quot;&gt;passwordHash&lt;/code&gt; (which uses a hash generated from the command &lt;code class=&quot;language-text&quot;&gt;mkpasswd -m sha-512&lt;/code&gt;, detailed on the &lt;a href=&quot;https://nixos.org/manual/nixos/stable/options.html#opt-users.users._name__.hashedPassword&quot;&gt;passwordHash options page&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;Fathom analytics&lt;/h3&gt;
&lt;p&gt;I pulled the last public available release of &lt;a href=&quot;https://github.com/usefathom/fathom/&quot;&gt;Fathom Lite from their repository&lt;/a&gt;, and created a systemd service file to run it. I was worried for a bit that it wouldn’t run, as there were a lot of discussions going on the community forums about having &lt;a href=&quot;https://discourse.nixos.org/t/how-to-make-nixos-so-easy-that-people-can-be-productive-up-front-without-having-to-first-learn-the-nix-language/5625&quot;&gt;to patch or otherwise emulate a standard Linux system to make binaries work&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thankfully, Fathom isn’t one of those programs, and it worked flawlessly without any other work. It’s not packaged for NixOS, so this is probably the least NixOS part of this system.&lt;/p&gt;
&lt;h2&gt;Building NixOS&lt;/h2&gt;
&lt;p&gt;There are 2 commands to build our NixOS packages and send it to our remote system, then there’s 2 other commands to switch profiles and activate our new setup:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;nix-build&lt;/code&gt;: which builds the NixOS packages&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;nix-copy-closure&lt;/code&gt;: sends the NixOS packages to our remote&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;nix-env&lt;/code&gt;: Set the Nix profile to our uploaded packages&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;switch-to-configuration&lt;/code&gt;: Switch the system configuration to our new configuration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These all come together in an Elixir script:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elixir&quot;&gt;&lt;pre class=&quot;language-elixir&quot;&gt;&lt;code class=&quot;language-elixir&quot;&gt;server_raw &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; File&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read!&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;server_address.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
server_processed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;replace&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;server_raw&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;defmodule&lt;/span&gt; Build &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; upload_to_system&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;path_str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _status&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path
    fixed_path_str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;replace&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path_str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    System&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;nix-copy-closure&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--to&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--use-substitutes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; address&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fixed_path_str&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    Build&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activate_nix&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path_str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; activate_nix&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
    profile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/nix/var/nix/profiles/system&quot;&lt;/span&gt;
    System&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ssh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#{&lt;/span&gt;address&lt;span class=&quot;token delimiter punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sudo nix-env --profile &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#{&lt;/span&gt;profile&lt;span class=&quot;token delimiter punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; --set &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#{&lt;/span&gt;path&lt;span class=&quot;token delimiter punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    System&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ssh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#{&lt;/span&gt;address&lt;span class=&quot;token delimiter punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sudo &lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#{&lt;/span&gt;profile&lt;span class=&quot;token delimiter punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/bin/switch-to-configuration switch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;

System&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;nix-build&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;server.nix&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--no-out-link&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&gt;&lt;/span&gt; Build&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;upload_to_system&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;server_processed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running the script runs all of those commands sequentially, and executes all the above. One thing I note about this is that the script hangs if there’s an issue with any of the configuration files, which could lead to a server that’s unresponsive. You may need to power cycle your remote instance if that happens.&lt;/p&gt;
&lt;h2&gt;Concluding remarks&lt;/h2&gt;
&lt;p&gt;I learned quite a bit about NixOS, but like most things involved quite a bit of trial and error. Thankfully, having this sort of configuration means I can easily rebuild the system (such as when I found myself unable to connect via SSH when I changed the port but didn’t realise the firewall needed to be changed as well).&lt;/p&gt;
&lt;p&gt;If you’re interested in NixOS, I’d encourage you to take a look.&lt;/p&gt;
&lt;h2&gt;Useful links&lt;/h2&gt;
&lt;p&gt;In case you wanted to delve further into some of the resources I looked up while I was getting this set up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://typeclasses.com/nixos-on-aws&quot;&gt;Deploying NixOS to Amazon EC2&lt;/a&gt; by Type Classes: This was very useful starting out to understand how to build NixOS locally, and how to ship it off to a different installation.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.lafuente.me/posts/local-dns-and-web-server/&quot;&gt;Running a local dns and web server&lt;/a&gt; by José Luis Lafuente: I found the section to define the custom systemd service very useful (just a heads up you want to set &lt;code class=&quot;language-text&quot;&gt;home&lt;/code&gt; for the user in that config to the Caddy data directory—mine was &lt;code class=&quot;language-text&quot;&gt;/var/lib/caddy&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[My Gatsby setup]]></title><description><![CDATA[Gatsby logo Gatsby is a framework which employs React to build sites just like the one you see here. There’s quite a few parts to it, so I…]]></description><link>https://mnguyen.io/blog/my-gatsby-setup/</link><guid isPermaLink="false">https://mnguyen.io/blog/my-gatsby-setup/</guid><pubDate>Sun, 14 Jun 2020 11:17:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;/files/b0be31336c89d5815a6d831185447d04/Gatsby.svg&quot; alt=&quot;Gatsby logo&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatsbyjs.org/&quot;&gt;Gatsby&lt;/a&gt; is a framework which employs React to build sites just like the one you see here. There’s quite a few parts to it, so I’ll go over the setup in this post, and the things that I’ve added to make the experience pleasant, both for users (to read and explore) and myself (to work on and iterate).&lt;/p&gt;
&lt;h2&gt;Base styles and components&lt;/h2&gt;
&lt;p&gt;While there’s a few ways of setting up styles on the site, I have 2 primary methods of styling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A global CSS file which contains styling which is common across components.&lt;/li&gt;
&lt;li&gt;CSS-in-JS, styles in components that are specific to individual components, such as layout, header, buttons.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having tried both, it does feel a bit easier to separate concerns with styling—it’s a lot more difficult to have collisions with class naming. There’s an endless debate as to whether CSS-in-JS is the right approach or not, but that’s another article for another time.&lt;/p&gt;
&lt;p&gt;As for the components themselves, they’re mostly straightforward to work with. Below is a sample from my &lt;code class=&quot;language-text&quot;&gt;DateTime&lt;/code&gt; component which is used in the articles section:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// file: src/components/datetime.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;DateTime&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;time datetime&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datetime&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dateformatted&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;time&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; DateTime&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This can then be used by other components like so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// file: src/components/recent_posts.js&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;RecentPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;DateTime datetime&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;htmldate&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; dateformatted&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; RecentPosts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m sure I could make even better use of React, but the fact is that I don’t think I have that bigger picture just yet. Maybe I’ll make it possible to have a dark-mode toggle switch or something. One day.&lt;/p&gt;
&lt;h2&gt;Article rendering&lt;/h2&gt;
&lt;p&gt;Articles use &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-transformer-remark/&quot;&gt;gatsby-transformer-remark&lt;/a&gt;, which provides the ability to parse markdown files, and it exposes a way for additional plugins to do their thing.&lt;/p&gt;
&lt;p&gt;I use the &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-remark-smartypants/&quot;&gt;gatsby-remark-smartypants&lt;/a&gt; plugin to modify the output a little, including directional quotes, em-dashes, ellipses—things that make the reading experience a bit more pleasant.&lt;/p&gt;
&lt;p&gt;Code blocks use &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-remark-prismjs/&quot;&gt;gatsby-remark-prismjs&lt;/a&gt;, enabling syntax highlighting for code blocks like you see above. It has a variety of themes—I’ve opted to use &lt;a href=&quot;https://github.com/PrismJS/prism-themes/blob/master/themes/prism-a11y-dark.css&quot;&gt;a11y Dark&lt;/a&gt; for code blocks, due to the fact that it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Looks nice—the colours help distinguish between different bits of code.&lt;/li&gt;
&lt;li&gt;Contrasts nicely with the text blocks that go around it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Images use &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-remark-images/&quot;&gt;gatsby-remark-images&lt;/a&gt; with the &lt;code class=&quot;language-text&quot;&gt;tracedSVG&lt;/code&gt; option so it’s possible to show a SVG placeholder, and then lazy load in images when the user scrolls it into view.&lt;/p&gt;
&lt;h2&gt;Typography&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-plugin-typography/&quot;&gt;gatsby-plugin-typography&lt;/a&gt; provides &lt;a href=&quot;https://kyleamathews.github.io/typography.js/&quot;&gt;Typography.js&lt;/a&gt; an easy way to define font choices and sizes, which are used for headings and content. I use &lt;a href=&quot;https://www.npmjs.com/package/typeface-lato&quot;&gt;Lato&lt;/a&gt; for the header fonts, as it became part of my branding and I thought it suitable here.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 553px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b2091535c5274e61439eae01dbd762c4/74cfa/lato-sample.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 34.25%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAAsTAAALEwEAmpwYAAAA/ElEQVQoz61Sv8uCUBTtDxeaBNGpQVwUMUhwclQHFR0MIRd/ICrq4OKkk1aEno9eBBEFDd+BwxneuZd7z7ubZVnw5LquX/nqefc+3+7Y4B9xb745nU5I0xR5nuN6vWKaJszzjHEcUVUV0cvlgr7vYVkWbrcbiqJA0zRE4ziGbdtIkuQx4Xa7BcMwoGka+/0eqqqCZVnIsgxRFMHzPFFJkrDb7aDrOjiOQxRFOBwOMAwDFEVB07RHw7qu0XUdwjDE8XiEaZrwPA9ZliEIAjK5oigQBAFt28JxHLiuSzbxfZ/UlGVJfPccf8rwfD5jGIbfMnz95W984v0iPvn+AJYlA9emQhtKAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/b2091535c5274e61439eae01dbd762c4/7f61c/lato-sample.webp 400w,
/static/b2091535c5274e61439eae01dbd762c4/e58ce/lato-sample.webp 553w&quot;
              sizes=&quot;(max-width: 553px) 100vw, 553px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/b2091535c5274e61439eae01dbd762c4/e17e5/lato-sample.png 400w,
/static/b2091535c5274e61439eae01dbd762c4/74cfa/lato-sample.png 553w&quot;
            sizes=&quot;(max-width: 553px) 100vw, 553px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/b2091535c5274e61439eae01dbd762c4/74cfa/lato-sample.png&quot;
            alt=&quot;A font sample of Lato&quot;
            title=&quot;A font sample of Lato&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/typeface-literata&quot;&gt;Literata&lt;/a&gt; was used for the main content, as I encountered it in the Android app of Google Play Books and I found it very easy to read.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 982px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3d9c1c5bf6c5c40707ac205ac4d477b5/84a90/literata-sample.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 34%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAC4jAAAuIwF4pT92AAABEklEQVQoz52RT6uCQBTF/f7fpYULUTTRwoRSEDVaWSsrpRbhn9LUzuNcMN72vQuH4dy5d+Y3d5Qsy3C/33G9XlGWpSiOY7xeL5xOJ8lTt9sNx+NRai+Xi9Qx93g8cD6fUdc1GMpqtcJ2u4VpmvB9H5vNBqqqYr/fI01TrNdr2LaNJElgWZbUeJ4nYh+9YRhyiRz4fr8xTROezyfatsU4jqiqStR1neQYfd9/11nDMHzz7KNXFosFSBmGIZbLpVBQmqbBcRy4rosoinA4HLDb7YSI5KTmq9gTBAF0XUdRFFA4K5J8Ph+Qlp5UTdPISk96kvz2c81cxxcJIenmm0nJuXDjv6HkeS4/xqHOvzfPhdR/1Q8iJAW6pRghiQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/3d9c1c5bf6c5c40707ac205ac4d477b5/7f61c/literata-sample.webp 400w,
/static/3d9c1c5bf6c5c40707ac205ac4d477b5/d00b9/literata-sample.webp 800w,
/static/3d9c1c5bf6c5c40707ac205ac4d477b5/4c092/literata-sample.webp 982w&quot;
              sizes=&quot;(max-width: 982px) 100vw, 982px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/3d9c1c5bf6c5c40707ac205ac4d477b5/e17e5/literata-sample.png 400w,
/static/3d9c1c5bf6c5c40707ac205ac4d477b5/5a190/literata-sample.png 800w,
/static/3d9c1c5bf6c5c40707ac205ac4d477b5/84a90/literata-sample.png 982w&quot;
            sizes=&quot;(max-width: 982px) 100vw, 982px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/3d9c1c5bf6c5c40707ac205ac4d477b5/84a90/literata-sample.png&quot;
            alt=&quot;A font sample of Literata&quot;
            title=&quot;A font sample of Literata&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Other things&lt;/h2&gt;
&lt;p&gt;Because this is a static generated site, we have to fit in a few more things which would normally be done by the CMS templating engine into the build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-plugin-manifest/&quot;&gt;gatsby-plugin-manifest&lt;/a&gt;: Creates a manifest file for progressive web app (PWA) support, used in conjunction with &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-plugin-offline/&quot;&gt;gatsby-plugin-offline&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-plugin-robots-txt/&quot;&gt;gatsby-plugin-robots-txt&lt;/a&gt;: Generate a robots.txt at build—I’ve configured it to indicate the presence of the &lt;code class=&quot;language-text&quot;&gt;sitemap.xml&lt;/code&gt; file which is generated by &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-plugin-sitemap/&quot;&gt;gatsby-plugin-sitemap&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-plugin-feed/&quot;&gt;gatsby-plugin-feed&lt;/a&gt;: Provides support to subscribe to a RSS feed containing all my written articles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Closing thoughts&lt;/h2&gt;
&lt;p&gt;Is it over-engineered? Perhaps—at the end of the day, I’m just using text files to produce and publish HTML pages.&lt;/p&gt;
&lt;p&gt;However, it is a valuable learning experiment to play around and tinker, and I’m still learning things as I go.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Winter visit to the Blue Mountains]]></title><description><![CDATA[We went to the Blue Mountains region as celebration for my recent birthday. The Blue Mountains were only a short distance away from home…]]></description><link>https://mnguyen.io/blog/winter-2019-visit-blue-mountains/</link><guid isPermaLink="false">https://mnguyen.io/blog/winter-2019-visit-blue-mountains/</guid><pubDate>Sun, 11 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We went to the Blue Mountains region as celebration for my recent birthday. The Blue Mountains were only a short distance away from home, and we kind of wanted to get out of the house for a change. As we were making the road trip up, we noticed that the originally sunny weather had faded away, and it had gotten much more chilly as we ascended. The national weather bureau had reported that snow was possible over this weekend.&lt;/p&gt;
&lt;p&gt;In the afternoon, we headed out to a couple of lookout points. Hargraves Lookout was quite an impressive, albeit a windy sight.&lt;/p&gt;
&lt;p&gt;We made a visit to another trail over at Govetts Leap lookout. It was remarkable to me how the rockface was shaped over the Earth’s lifetime, and how long the whole process was.&lt;/p&gt;
&lt;p&gt;Dinner was enjoyed at the Golf Club, which cooked a very nice steak. The car did chime up on the way over, warning us that the outside temperature had dipped to 3°C.&lt;/p&gt;
&lt;p&gt;This was mainly due to the fact that there really isn’t much thought put into adding anti-freeze—most places in Australia don’t dip below 0°C (32°F). Not that we expected it to be a huge problem anyway, since we weren’t exactly aiming to let the car cool down completely, and the valley was low enough not to freeze over.&lt;/p&gt;
&lt;p&gt;Saturday morning was quite cold. We had put on the wood burner the previous night, and had some luck keeping the flames up, but it had died down just as we were getting to bed. Overnight, the cabin had cooled down despite running the air conditioning unit at full blast.&lt;/p&gt;
&lt;p&gt;Not having had breakfast, we made our way up the hill into town when we first saw some snow cover. It was a surreal experience.&lt;/p&gt;
&lt;p&gt;Making the decision to return to Hargraves Lookout was a good choice—snow had only fallen in a few locations, and the lookout was one of those places.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Automatic updates for packages in CentOS]]></title><description><![CDATA[This guide sets up a tool called  which can handle unmanaged updates on your behalf at a scheduled interval. While this guide is for CentOS…]]></description><link>https://mnguyen.io/blog/automatic-updates-for-packages-in-centos/</link><guid isPermaLink="false">https://mnguyen.io/blog/automatic-updates-for-packages-in-centos/</guid><pubDate>Sat, 06 Apr 2019 08:11:00 GMT</pubDate><content:encoded>&lt;p&gt;This guide sets up a tool called &lt;code class=&quot;language-text&quot;&gt;yum-cron&lt;/code&gt; which can handle unmanaged updates on your behalf at a scheduled interval. While this guide is for CentOS, you could apply it to other similar distros, such as Amazon Linux 2, Fedora, or Red Hat.&lt;/p&gt;
&lt;h2&gt;Things before you begin&lt;/h2&gt;
&lt;p&gt;You should have one of the above distros of Linux, which is connected to the internet. &lt;code class=&quot;language-text&quot;&gt;crond&lt;/code&gt; should also be installed and its associated service should be enabled and started.&lt;/p&gt;
&lt;p&gt;If you’re going to enable automatic updates, be aware this does carry some risk—I wouldn’t recommend it if you have mission critical software or services running on your machine. Consider running automatic updates on a staging machine and schedule running updates yourself.&lt;/p&gt;
&lt;h2&gt;Overview&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Install the &lt;code class=&quot;language-text&quot;&gt;yum-cron&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;Configure &lt;code class=&quot;language-text&quot;&gt;yum-cron&lt;/code&gt; to your needs/wants&lt;/li&gt;
&lt;li&gt;Enable and start the &lt;code class=&quot;language-text&quot;&gt;yum-cron&lt;/code&gt; service&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Installing the package&lt;/h2&gt;
&lt;p&gt;First off, you should make sure that your system is up to date. On the assumption that you can elevate permissions through &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt;, you can do that by running &lt;code class=&quot;language-text&quot;&gt;sudo yum update&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;Once that’s done, you should be able to install &lt;code class=&quot;language-text&quot;&gt;yum-cron&lt;/code&gt; with the command &lt;code class=&quot;language-text&quot;&gt;sudo yum install yum-cron&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For the next part, check the contents of your &lt;code class=&quot;language-text&quot;&gt;/etc/yum/&lt;/code&gt; directory. Here’s mine for reference:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; /etc/yum -l
total &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;
drwxr-xr-x &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; Nov  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; 01:53 fssnap.d
drwxr-xr-x &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root   &lt;span class=&quot;token number&quot;&gt;36&lt;/span&gt; Nov  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; 01:53 pluginconf.d
drwxr-xr-x &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root   &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt; Apr  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; 07:23 protected.d
drwxr-xr-x &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root   &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; Apr  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; 07:16 vars
-rw-r--r-- &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root  &lt;span class=&quot;token number&quot;&gt;444&lt;/span&gt; Nov  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; 01:53 version-groups.conf
-rw-r--r-- &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root &lt;span class=&quot;token number&quot;&gt;2565&lt;/span&gt; Nov  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; 01:53 yum-cron-hourly.conf
-rw-r--r-- &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root &lt;span class=&quot;token number&quot;&gt;2603&lt;/span&gt; Nov  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; 01:53 yum-cron.conf&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This means I can configure &lt;code class=&quot;language-text&quot;&gt;yum-cron&lt;/code&gt; either on a hourly basis by modifying &lt;code class=&quot;language-text&quot;&gt;yum-cron-hourly.conf&lt;/code&gt;, or on a daily basis if I edit &lt;code class=&quot;language-text&quot;&gt;yum-cron.conf&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Configuring yum-cron&lt;/h2&gt;
&lt;p&gt;Once you’ve picked the file you want to configure, open it up in an editor of your choice. Here’s what the top part of yum-cron.conf looks like for me:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;commands&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#  What kind of update to use:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# default                            = yum upgrade&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# security                           = yum --security upgrade&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# security-severity:Critical         = yum --sec-severity=Critical upgrade&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# minimal                            = yum --bugfix update-minimal&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# minimal-security                   = yum --security update-minimal&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# minimal-security-severity:Critical =  --sec-severity=Critical update-minimal&lt;/span&gt;
update_cmd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; default

&lt;span class=&quot;token comment&quot;&gt;# Whether a message should be emitted when updates are available,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# were downloaded, or applied.&lt;/span&gt;
update_messages &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;yes&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Whether updates should be downloaded when they are available.&lt;/span&gt;
download_updates &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;yes&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Whether updates should be applied when they are available.  Note&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# that download_updates must also be yes for the update to be applied.&lt;/span&gt;
apply_updates &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; no&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, for most systems I manage, I usually do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code class=&quot;language-text&quot;&gt;update_cmd&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;security&lt;/code&gt;—this allows packages to be automatically updated if they have a security update available&lt;/li&gt;
&lt;li&gt;Set &lt;code class=&quot;language-text&quot;&gt;apply_updates&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;yes&lt;/code&gt;—that way updates are installed without any manual process&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Save your file, and you should be ready to go!&lt;/p&gt;
&lt;h2&gt;Running the yum-cron service&lt;/h2&gt;
&lt;p&gt;Now that you’ve done all that, you actually don’t need to do anything else. &lt;code class=&quot;language-text&quot;&gt;crond.service&lt;/code&gt; takes care of the rest, since the &lt;code class=&quot;language-text&quot;&gt;yum-cron&lt;/code&gt; package installs some cron services which will run. You can verify this by examining the cron directories in &lt;code class=&quot;language-text&quot;&gt;/etc/&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; -d /etc/*/ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cron&apos;&lt;/span&gt;
/etc/cron.d/
/etc/cron.daily/
/etc/cron.hourly/
/etc/cron.monthly/
/etc/cron.weekly/

$ &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; -l /etc/cron.daily
total &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;
-rwxr-xr-x &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root &lt;span class=&quot;token number&quot;&gt;332&lt;/span&gt; Nov  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; 01:53 0yum-daily.cron
-rwx------ &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; root root &lt;span class=&quot;token number&quot;&gt;219&lt;/span&gt; Oct &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;19&lt;/span&gt;:12 &lt;span class=&quot;token function&quot;&gt;logrotate&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;In conclusion&lt;/h2&gt;
&lt;p&gt;By installing a service like &lt;code class=&quot;language-text&quot;&gt;yum-cron&lt;/code&gt;, you can keep your systems up to date without having to do it yourself. This isn’t suitable for all situations, but for most cases, it is.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Embed instant.page into your Webpack bundle]]></title><description><![CDATA[A new library has been making the rounds on Hacker News which is titled “Make your site’s page instant in one minute”. It works by taking…]]></description><link>https://mnguyen.io/blog/embed-instantpage-into-webpack/</link><guid isPermaLink="false">https://mnguyen.io/blog/embed-instantpage-into-webpack/</guid><pubDate>Fri, 15 Feb 2019 10:41:00 GMT</pubDate><content:encoded>&lt;p&gt;A new library has been making the rounds on Hacker News which is titled “&lt;a href=&quot;https://instant.page&quot;&gt;Make your site’s page instant in one minute&lt;/a&gt;”. It works by taking advantage of browser prefetching by applying tags somewhat like below just as you’re hovering above, or touching a link:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;!docroot&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;prefetch&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/target_url&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;More details on how it works can be found on the &lt;a href=&quot;https://instant.page/tech&quot;&gt;instant.page website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the things I like about this is that it’s progressive enhancement—it loads the content a bit faster for the browsers that support it, and pages still load even if it doesn’t support it.&lt;/p&gt;
&lt;p&gt;While you can call it just by linking to the script in your HTML, I’ll show you in this post how I embedded this library using NPM and Webpack so you don’t have to call Cloudflare if you don’t want to.&lt;/p&gt;
&lt;h2&gt;The webpack.config.js file&lt;/h2&gt;
&lt;p&gt;My &lt;code class=&quot;language-text&quot;&gt;webpack.config.js&lt;/code&gt; file for the site’s theme is included below:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// webpack.config.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;path&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  module&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    rules&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      test&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\.min\.js$&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      use&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;script-loader&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  entry&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./src/js/main.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  output&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    filename&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;main.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;assets/js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Adding instant.page to package.json&lt;/h2&gt;
&lt;p&gt;To add instant.page to your &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;, we need to pull the project in. Because it’s a public repository, this process is quite straightforward—just run the below command, and it’ll add instant.page to &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; directory:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; git+https://github.com/instantpage/instant.page.git&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once that’s done, you’re ready to rock.&lt;/p&gt;
&lt;h2&gt;Add instant.page to your JS bundle&lt;/h2&gt;
&lt;p&gt;In my case, adding instant.page was quite easy—I inserted an import statement into the JS file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// /src/js/main.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;instant.page&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can alternatively copy the script located in &lt;code class=&quot;language-text&quot;&gt;/node_modules/instant.page/instantpage.js&lt;/code&gt; to your assets directory, and just include it as a script in your HTML if you’d like.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Retina Screenshots with Firefox]]></title><description><![CDATA[When developing prototypes, you might need to send screenshots of web dev work you’re doing to a client, or demonstrating a bug or feature…]]></description><link>https://mnguyen.io/blog/retina-screenshots-in-firefox/</link><guid isPermaLink="false">https://mnguyen.io/blog/retina-screenshots-in-firefox/</guid><pubDate>Mon, 24 Sep 2018 11:41:00 GMT</pubDate><content:encoded>&lt;p&gt;When developing prototypes, you might need to send screenshots of web dev work you’re doing to a client, or demonstrating a bug or feature.&lt;/p&gt;
&lt;p&gt;By the end of this, you should be able to get a screenshot of a web page at any ratio with decent pixel density, using Firefox Screenshots. Don’t worry, you don’t need a retina display to make it work.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://screenshots.firefox.com/&quot;&gt;Firefox Screenshots&lt;/a&gt; is a relatively new feature in Firefox, which lets you take screenshots of web pages and lets you copy, save or share your screenshots online. It was originally developed as a user experiment under Mozilla’s Test Pilot Program, but has since been implemented into the browser. Mozilla has a bit more information &lt;a href=&quot;https://wiki.mozilla.org/Firefox/Screenshots&quot;&gt;on their wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just note that because this is software being run in the browser, you can’t use it to get high density screenshots of other software running on your system.&lt;/p&gt;
&lt;h2&gt;Getting a Screenshot&lt;/h2&gt;
&lt;p&gt;First, you should review the &lt;a href=&quot;https://www.mozilla.org/en-US/about/legal/terms/services/&quot;&gt;Mozilla Cloud Services Terms&lt;/a&gt; to make sure that the terms are fair for you, as Firefox Screenshots does send data back.&lt;/p&gt;
&lt;p&gt;Assuming that you are in agreement, you can quickly grab a screenshot, either though the address bar menu, or by right clicking, and choosing ’Take a Screenshot’:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/4efa04fad7d756624e78abdd0ed4af9e/cd039/AddressBarScreenshot-fs8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 38.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAABEUlEQVQY03WR3VLCMBBG+/5P4zXe4YyWDopUa2n5KWDbtJSENGkmJbumDigMKp75LnYvzu7MrmMMGAMAgEcA8VACmhMA0DRykaQ3Pb/X9/mOp+x9y6qmUc6Xo7WuOZdCSCGlkEKI/SVtKxv1Nt+sMgYA+9NQpztCKR24Lq22JCNlXpSk7K5hrb1sv2UhRJIkWmtRH/YqpT7+gIAAcEVWSuVpWnMueN39g7UWEa/InPMwjCqyLfJKt8YAAtpfMceb/pAR0RgYBWn/3vcep4Nh5HqTcbCer9lsRc9ZrNlrXMxWtOssnJ7jVJsqzcjtXfgwCJ7G8+Fo6nphMMniZBMtynPipHyJiPe85DtKKctywtjuE29zxS61QQvJAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/4efa04fad7d756624e78abdd0ed4af9e/7f61c/AddressBarScreenshot-fs8.webp 400w,
/static/4efa04fad7d756624e78abdd0ed4af9e/2e9dd/AddressBarScreenshot-fs8.webp 555w&quot;
              sizes=&quot;(max-width: 555px) 100vw, 555px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/4efa04fad7d756624e78abdd0ed4af9e/e17e5/AddressBarScreenshot-fs8.png 400w,
/static/4efa04fad7d756624e78abdd0ed4af9e/cd039/AddressBarScreenshot-fs8.png 555w&quot;
            sizes=&quot;(max-width: 555px) 100vw, 555px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/4efa04fad7d756624e78abdd0ed4af9e/cd039/AddressBarScreenshot-fs8.png&quot;
            alt=&quot;AddressBarScreenshot-fs8&quot;
            title=&quot;AddressBarScreenshot-fs8&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Then you can select the area of the screenshot. Some options available:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Save Full Page: basically like stitched screenshots, from the top to the bottom. Good if you’re looking to get the whole design down&lt;/li&gt;
&lt;li&gt;Save Visible: Grabs what your display can see right at that moment.&lt;/li&gt;
&lt;li&gt;An element: As you hover around the page, you’ll see rectangles highlighted. Click the mouse and you’ll get a perfect rectangle around the desired element!&lt;/li&gt;
&lt;li&gt;An arbitary rectangle: Click and drag the mouse to grab the thing you’re after.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Then you can choose to copy to the clipboard, save it, or upload it to Firefox Cloud.&lt;/p&gt;
&lt;h2&gt;Now For The Magic&lt;/h2&gt;
&lt;p&gt;At the moment, you’re currently getting screenshots in the monitor’s native display density, but what you’re really after is getting those crisp screenshots. So what you need to do is to toggle the the Developer Tools (&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + I&lt;/code&gt;), and click this little icon, which toggles Responsive Design Mode:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 445px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/90a782867a67fb24c75a122b6f58c93e/e66bf/FFDev-ResponsiveDesignMode-fs8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 48.25000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAAByklEQVQozy3P227aQBAGYF9WJKmhGATe9a696/Xszh5szME2EJRUpFLTVqkq9THai77/RQVE+vRr5pfmYiKlVM6L0ehuMpkKIQE0aP8wTj7cj+/j6cPHeDS6i+Mx5bnLxVsuX0VJGKeELhZplGb5grBCyNlszlmezGZTqlQY7OZxKex4MuWMJ0kymy8kLzzNiiQZTz6xjMXxOALtQLvgV4UoQVsFKMrKWIfO80IsKZeVITxfElZp/P72UygoCumsZxmPLAaLwRhvjJN2Jeyqqncc/DLNKCsyLkjGM15QVvBc7radFErKdxFijVhb28gSfLXpzH5jT7XuCKGEZGl6SXLNlGTz+SJN6XJJ0pRej427cTa069Oue2nMyuugtdPgUHsNFq40WGMu660JoY1M6K8GdOsfv36f99+e6+c+DEN97Pxwak6gLWistK201dpVGuE6NM0mkue/8vxHfvknVi8G28Y/+uaprp8kU2WmkCNwUKwCrhVTnBYVB8lKTnMhyvefERsARNMe689rt+/soYX1GjaDGQbTb03Xm34LW6/qAx5aaINqHPoIMdw43xz7r8f+1W+PGNbGOIMe0OmL2+ARg8ZLjxjadvcf+39dHjmFTEUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/90a782867a67fb24c75a122b6f58c93e/7f61c/FFDev-ResponsiveDesignMode-fs8.webp 400w,
/static/90a782867a67fb24c75a122b6f58c93e/75680/FFDev-ResponsiveDesignMode-fs8.webp 445w&quot;
              sizes=&quot;(max-width: 445px) 100vw, 445px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/90a782867a67fb24c75a122b6f58c93e/e17e5/FFDev-ResponsiveDesignMode-fs8.png 400w,
/static/90a782867a67fb24c75a122b6f58c93e/e66bf/FFDev-ResponsiveDesignMode-fs8.png 445w&quot;
            sizes=&quot;(max-width: 445px) 100vw, 445px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/90a782867a67fb24c75a122b6f58c93e/e66bf/FFDev-ResponsiveDesignMode-fs8.png&quot;
            alt=&quot;FFDev-ResponsiveDesignMode-fs8&quot;
            title=&quot;FFDev-ResponsiveDesignMode-fs8&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Right away, you’ll see the web page squeeze into a small space—representing the responsive viewport. You can adjust the resolution here, but more interesting is the Device Pixel Ratio (or DPR) list box, which you can set to 1, 2, or 3. This setting is what we want, and it’ll get us those large images!&lt;/p&gt;
&lt;p&gt;These images are rather large for demonstrating, but here’s a scaled down version with some useful labels:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1280px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ff1e2562bebf1dfdece1ee6edfec4704/21b4d/DPRPreview-fs8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.25%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAABPklEQVQoz4VQ2UoDQRDcr9EcsNvnHDvZe4NBiRHFB1H/IATymPiQX5fdHIYYSFHTDTNV3dRE0xBCNqnq6vXtxXvPIpZIiJgPpK6yEUuMzGSNMapWVdM0UsQEgIhVDSElCc5nZVVMAJGPEBbDrp/FRP1gIrQuykQF0TIHawWRAZosrcoCka6aDyAi56OP+VdT5XWel1mWh2BFGBARAbp2w5yH2qfeee+cDyE450S0z6W3NwsoIlAP7A42TSNq+mgns1LSyS7NdfXkxFnxJ7ZF400w7Jx6q6kV7yQ15M7HHcyPn98PbVvXTdvDGAOA+3X77HwVezMY24fSP2pXkbgqi0lRdb/e3UvPo4aFfBqxqMSxJMk5FQBGo/fF82I2TcZjBbgQSByzaDRY74ar7XD18593y839cnP1abjaDta7X/DskwRkZKfnAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/ff1e2562bebf1dfdece1ee6edfec4704/7f61c/DPRPreview-fs8.webp 400w,
/static/ff1e2562bebf1dfdece1ee6edfec4704/d00b9/DPRPreview-fs8.webp 800w,
/static/ff1e2562bebf1dfdece1ee6edfec4704/af3f0/DPRPreview-fs8.webp 1280w&quot;
              sizes=&quot;(max-width: 1280px) 100vw, 1280px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/ff1e2562bebf1dfdece1ee6edfec4704/e17e5/DPRPreview-fs8.png 400w,
/static/ff1e2562bebf1dfdece1ee6edfec4704/5a190/DPRPreview-fs8.png 800w,
/static/ff1e2562bebf1dfdece1ee6edfec4704/21b4d/DPRPreview-fs8.png 1280w&quot;
            sizes=&quot;(max-width: 1280px) 100vw, 1280px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/ff1e2562bebf1dfdece1ee6edfec4704/21b4d/DPRPreview-fs8.png&quot;
            alt=&quot;DPRPreview-fs8&quot;
            title=&quot;DPRPreview-fs8&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;As you can see, for each ratio the image gets proportionally larger, which means there’s far more detail visible!&lt;/p&gt;
&lt;h2&gt;Other Solutions&lt;/h2&gt;
&lt;p&gt;There aren’t many solutions out there that deal with taking screenshots in the way that I’ve shown you here. There is &lt;a href=&quot;https://github.com/nomeata/gtk-vector-screenshot&quot;&gt;gtk-vector-screenshot&lt;/a&gt;, which works with GTK 3 applications, but it hasn’t seen a major release since 2014 (at least as of writing this).&lt;/p&gt;
&lt;p&gt;If there’s any other solutions that you’ve found or made yourself, contact me and I’ll see about adding it to this list!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Getting started with Netlify]]></title><description><![CDATA[Aside: the Git logo by Jason Long is licenced under the Creative Commons Attribution 3.0 Unported Licence. If you’ve seen my portfolio…]]></description><link>https://mnguyen.io/blog/getting-started-with-netlify/</link><guid isPermaLink="false">https://mnguyen.io/blog/getting-started-with-netlify/</guid><pubDate>Thu, 11 Jan 2018 23:00:00 GMT</pubDate><content:encoded>&lt;figure&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/78be91bae9da1eed2476fafb488567b2/29114/netlify-fs8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.25%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAACMElEQVQoz2VSy2sTcRBecs5VMOJR8CAI0rN/g6bEW+0fIN5KT2qJhDxbQ23zqF4sXpS+jEQPVmIpUlvaEJtN0s3uL9lXnvtLk7ibTbrd7mYkicRC5zAwHzPMfPN9BABcGEaRF6DfxxjTDONwOK7bbBaLJRaLAYBuGHAl+v0+ABAAsBPbmrl3621w/uf+gSjwExMTNpvNarWur60BgGkYsqLs8uInGsWLLFOpNCRpMA9AbMS/rN69sX3/9uxNayL++Xsi8cjheGC32ycnnU4nAKQ4fumE9paqwdN2oCp58kwodZzK5gabG612ZObp+zvXNqYfFhCqVqsURdE0nSZJmqJ2UcHPl0JqL6p0wy053FbCfzoh9cyfPckgNDhbPdc/rr4TRWFMpj8kJnW73jxy5SgPRb9MZ/ysMC+UF6XG8mn7dUv+RpKEaZoAwItit6sOGJqmYRj6xQUA7CEUlE6f/zp4HIlOR99MhSNP1jenwlFXllpRz76SGWL0PbXTYVlW07RRaQ73/0DIV6kv1RtuigmwgjuPfAVuNrETKHKLbWU9TRLj7+u6LkkSxliWZU3TjlOpD/F4gKKfJX/PHRz5mKIrS704THooJtpW3GJlO5MlxrqN2Oq6LsuyqqoYYwljrtlc2Nt3Ie5VuebO5ecOk35OWGjJy0fJjiwTl3Ufzf9HhrmpKJF0ZgGxPr7k5cQVTtgiM6Va7Z9JrrrnUgyQc8MoY5yvVHPlcr1e13q9UdtfvIIfvuVcx3QAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/78be91bae9da1eed2476fafb488567b2/7f61c/netlify-fs8.webp 400w,
/static/78be91bae9da1eed2476fafb488567b2/d00b9/netlify-fs8.webp 800w,
/static/78be91bae9da1eed2476fafb488567b2/fad48/netlify-fs8.webp 1600w,
/static/78be91bae9da1eed2476fafb488567b2/882b9/netlify-fs8.webp 1920w&quot;
              sizes=&quot;(max-width: 1600px) 100vw, 1600px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/78be91bae9da1eed2476fafb488567b2/e17e5/netlify-fs8.png 400w,
/static/78be91bae9da1eed2476fafb488567b2/5a190/netlify-fs8.png 800w,
/static/78be91bae9da1eed2476fafb488567b2/29007/netlify-fs8.png 1600w,
/static/78be91bae9da1eed2476fafb488567b2/29114/netlify-fs8.png 1920w&quot;
            sizes=&quot;(max-width: 1600px) 100vw, 1600px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/78be91bae9da1eed2476fafb488567b2/29007/netlify-fs8.png&quot;
            alt=&quot;Diagram depicting a computer, to git, to the internet via Netlify&quot;
            title=&quot;Diagram depicting a computer, to git, to the internet via Netlify&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;
&lt;p&gt;Aside: the &lt;a href=&quot;https://git-scm.com/downloads/logos&quot;&gt;Git logo&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/jasonlong&quot;&gt;Jason Long&lt;/a&gt; is licenced under the &lt;a href=&quot;https://creativecommons.org/licenses/by/3.0/&quot;&gt;Creative Commons Attribution 3.0 Unported Licence&lt;/a&gt;.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you’ve seen my portfolio recently, I’ve made a few additions—specifically, you can now visit the live sites for &lt;a href=&quot;/projects/australian-design-architects/&quot;&gt;Australian Design Architects&lt;/a&gt;, and &lt;a href=&quot;/projects/seoul-international-visitors-centre/&quot;&gt;Seoul International Visitors Centre&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They both use &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt;, and this post will describe how I got things working, by deploying a project via a repository on GitLab. This means that we’ll be setting up a thing called Continuous Integration (CI), which is fancy speak for automatic deployments from an online repository.&lt;/p&gt;
&lt;p&gt;Why Netlify though? Why not GitHub pages, or something on Azure, or Amazon Web Services, or our own VPS?&lt;/p&gt;
&lt;p&gt;I thought that too when I first thought of putting them live. I could just put it on &lt;code class=&quot;language-text&quot;&gt;demo.mnguyen.io&lt;/code&gt;, and let it go. But that means I have to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assign a new subdomain to my domain name: not a huge deal for DNS, but that would mean creating new TLS certificates from &lt;a href=&quot;https://letsencrypt.org&quot;&gt;Let’s Encrypt&lt;/a&gt; which would be mildly irritating&lt;/li&gt;
&lt;li&gt;Upload all the project files onto the VPS: it’ll run through the storage and available bandwidth, and then if I make any updates, I have to upload the changes and run the generator again&lt;/li&gt;
&lt;li&gt;Create new configuration files for Nginx: also not a big deal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of that sounds like a lot of work, and since it’s coming to the end of the year, I wanted to wind back with something more simple so I didn’t get burned out.&lt;/p&gt;
&lt;p&gt;So what does Netlify get us in their free tier? Well, they have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTPS out of the gate, so no-one interferes with what’s sent to your visitors&lt;/li&gt;
&lt;li&gt;We can use our Git repository, and let their infrastructure do the rest&lt;/li&gt;
&lt;li&gt;Preview deploys for branches and pull requests&lt;/li&gt;
&lt;li&gt;Deployments automatically work with their Content Distribution Network (CDN), so visitors always have a fast experience&lt;/li&gt;
&lt;li&gt;We can use it for personal, or commercial services&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Their pricing scheme looks pretty good, catering from individuals, to teams, businesses and the high end stuff—fair for the service that they deliver. You can see the pricing &lt;a href=&quot;https://www.netlify.com/pricing&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The files we’re using&lt;/h2&gt;
&lt;p&gt;The two projects that I’m using are at their core statically generated websites, which means that you pull together all the templates and content together to get files that you can stick on a HTTP server.&lt;/p&gt;
&lt;p&gt;This is good in that this is all you need—no need for a database or any backend language, so as long as the HTTP server is well configured, you’ll be good.&lt;/p&gt;
&lt;p&gt;My two projects are powered by Jekyll, a Ruby based generator that does the hard work of making something coherant from our source files.&lt;/p&gt;
&lt;p&gt;There’s lots of engines you can use to generate your sites, such as Gatsby or Hugo. You should be able to use them all.&lt;/p&gt;
&lt;h2&gt;Preparing the source files&lt;/h2&gt;
&lt;p&gt;Because we have a Git repository for our project, we can use Netlify’s integration with services like GitHub and GitLab to kick things off. It doesn’t only serve as a place to host the code and files, but it also provides an easy way to pull code from different computer environments!&lt;/p&gt;
&lt;p&gt;There’s a few modifications to make to the code repository before it deploys, so I’ll do that now.&lt;/p&gt;
&lt;h3&gt;Configuring Jekyll (and Ruby)&lt;/h3&gt;
&lt;p&gt;We can’t just copy the published files over, since it would basically make the deployment no more useful than FTP, dependant on our environment and our machine.&lt;/p&gt;
&lt;p&gt;What we need to do instead is configure our project, so Netlify’s build system can build the project for itself. This is useful because you aren’t tied down to your own developer environment anymore—you can simply pull the code from your repository and get back to working on it in a near instant.&lt;/p&gt;
&lt;p&gt;So, following &lt;a href=&quot;https://www.netlify.com/blog/2015/10/28/a-step-by-step-guide-jekyll-3.0-on-netlify/#preparing-your-project-for-github&quot;&gt;this guide that they have&lt;/a&gt;, we can set up the required info, first by running &lt;code class=&quot;language-text&quot;&gt;bundle init&lt;/code&gt;, then modifying the resulting &lt;code class=&quot;language-text&quot;&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;gem &amp;quot;jekyll&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can install it to our project:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ bundle &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which then creates a file called &lt;code class=&quot;language-text&quot;&gt;Gemfile.lock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Modify your &lt;code class=&quot;language-text&quot;&gt;.gitignore&lt;/code&gt; so that you exclude the build directory by adding its name to the bottom of the list. You can then commit those changes to your repository, and push it online.&lt;/p&gt;
&lt;h2&gt;Making it go&lt;/h2&gt;
&lt;p&gt;Going to the Netlify dashboard, you can see that you can upload a folder directly. It’s great if you want to throw up a prototype to show off to your team, but if you want to deploy often, nothing beats the CI process with a Git repsository.&lt;/p&gt;
&lt;p&gt;Clicking on the button, you’ll see the choice for 3 different Git providers from which you can pull your repo from. While I’ve put my work on GitLab (mainly due to their free private repos for anyone), you can also tap into your accounts on GitHub or BitBucket if you’d like.&lt;/p&gt;
&lt;p&gt;Sign into your chosen service, grant Netlify permission to access your repos, and select the repo, and off it goes!&lt;/p&gt;
&lt;p&gt;The deployment will make a clone of your repository and deploy it with the given resources. The &lt;code class=&quot;language-text&quot;&gt;Gemfile&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Gemfile.lock&lt;/code&gt; files will grab the right packages, and &lt;code class=&quot;language-text&quot;&gt;.ruby-version&lt;/code&gt; will make sure that it uses the right version of Ruby to go with it.&lt;/p&gt;
&lt;p&gt;With some luck, it’ll give you a link that you can click on, and view online!&lt;/p&gt;
&lt;h2&gt;So in closing&lt;/h2&gt;
&lt;p&gt;I’ve set out a few reasons why you would use a service like Netlify, due to its ease of use compared to other options like hosting it yourself.&lt;/p&gt;
&lt;p&gt;There are a few things that you need to do if you’re using static generators like Jekyll, Hugo, and GatsbyJS—making sure that you’ve set the correct version of your processor. Then you can push it to your Git repository, and then get it processed and put it up live on the internet!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Working with the PATH variable]]></title><description><![CDATA[Unfortunately, this post isn’t about how you can set your sights to the future. Instead, we focus on a thing called the PATH variable, where…]]></description><link>https://mnguyen.io/blog/working-with-path-variable/</link><guid isPermaLink="false">https://mnguyen.io/blog/working-with-path-variable/</guid><pubDate>Thu, 11 Jan 2018 01:23:00 GMT</pubDate><content:encoded>&lt;p&gt;Unfortunately, this post isn’t about how you can set your sights to the future. Instead, we focus on a thing called the PATH variable, where it stands, and how you can modify it to access programs in other places.&lt;/p&gt;
&lt;p&gt;The PATH variable is a list of directories which contain programs to work with. When using the terminal (or command line for you people on Windows), you’ve accessed the PATH variable in order to reach the programs you’re after without knowing it.&lt;/p&gt;
&lt;h2&gt;It is a variable&lt;/h2&gt;
&lt;p&gt;The reason it’s called the PATH variable is that it can be changed, and that’s we’ll focus on in this post. There’s a few differences here and there between operating systems, so I’ll point them out as we see them.&lt;/p&gt;
&lt;p&gt;One important thing to remember is that the order of directories matters in how the system searches the directories for programs to run—the earlier a directory is in the list, &lt;strong&gt;the higher it is prioritised&lt;/strong&gt;. This means if you insert a directory in front, you can end up replacing programs normally provided by the system.&lt;/p&gt;
&lt;h3&gt;Windows land&lt;/h3&gt;
&lt;p&gt;In Windows 10, you can get to the PATH variable by going through the Control Panel, into System, and Advanced System Settings. The button is then visible under the System Properties window:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 658px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/887ae7a558aa84bb337a40cf27b53349/889a4/get_to_path_windows-fs8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 89.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAIAAADUsmlHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB6ElEQVQ4y31TCW7bMBDU/79SoM4H2jekRtEGaeMANRBfsk2K5F5cksVKPlLE7mBEiKKWO5xddh6Is5RStJxQay3vME3rLXSqWmxVAwmzAAAbCAEQgBBFGBFuBxOzSDaIYfraWrNnHO+xtdbVWokEkRFNfGut1Mb9b1k98mqeN/OynZfNmdu5br7ZuH6U/rkbhoDIACSSpx1Vy/Dra5h/8t8f8MdMniY+yNOMf36epvo8g5cvnXMuJYwRiWTU0opmRIogEXiIFIATaUQZEruAA7CPSLkSUfe2enMuOBe9jylhra0WzWKGxRCZ2dxgFuYsMpKNOTOmDiAB0MQQoNY2hSJSCIGQEImQ6DQQIoeEWQsTdJO372GJmab3y+qlCvshLVc7nwghddYAp+U2/VlUMxMAhBByzjri0idaimS1iiB0dSzPv5ktWJhx0jxC5GynNVSutY7BH2SPqqHdAQD0fT824e0zW+YQgnPeew8AIkJE9j9ROSu9nbmoClNWPbXttXdFJI9Vsy3uBV/d/ghCPOwPtgWBuZ1zvpj5nzPXWpd/louX18Xidb3eyHRmIiYSQiYWuzHFZJfSit1Vo6rKWDNETAlSAkBEiN3gBwu6IhNhCh5TuHBwx/1u693x0O8O+53NNutjv/kLFmAXLgrSihUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/887ae7a558aa84bb337a40cf27b53349/7f61c/get_to_path_windows-fs8.webp 400w,
/static/887ae7a558aa84bb337a40cf27b53349/6ad61/get_to_path_windows-fs8.webp 658w&quot;
              sizes=&quot;(max-width: 658px) 100vw, 658px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/887ae7a558aa84bb337a40cf27b53349/e17e5/get_to_path_windows-fs8.png 400w,
/static/887ae7a558aa84bb337a40cf27b53349/889a4/get_to_path_windows-fs8.png 658w&quot;
            sizes=&quot;(max-width: 658px) 100vw, 658px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/887ae7a558aa84bb337a40cf27b53349/889a4/get_to_path_windows-fs8.png&quot;
            alt=&quot;get_to_path_windows-fs8&quot;
            title=&quot;get_to_path_windows-fs8&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Opening up the Environment Variables window itself throws a bit at you, but the important thing to focus on are the User variables above:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 618px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/4096cf953dc255c861a16e417dfd6ed5/6e6fb/windows_environment_variables-fs8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 94.75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAIAAAAf7rriAAAACXBIWXMAAAsTAAALEwEAmpwYAAACYElEQVQ4y5WRSW/TQBTH/bW5UAkJGvWCVPgkbG0PHKAqKpxokx6aEBIndhJ7tueZN5vt2MjjdGMT/PTX6I3s/5u3RP5s350NejXng/b82T+q/PQsKkjKspRulvlqwbMERa6BIORKZL1Q5L+VBhKRLFvGcZauOCEFZ5V3KAuNqip96V3pnLfGWXtf3lqjtQAZgWCfh9Mv1+sY6inzM15dzMj51Xw0y79+W1/FdAlVAtVSlEsoF8IvhI+5z2SppIwoJc9PJo9ex3vHyd5R8vgofXIU7x9Nn74Z778dD95NBsffD05mhx/Whx83L0/XL07XB+9Xr4bMahUBp5s02W7rtm3bpmnb1hlM49lqEcfTSTydbNLFehHvfrihaRopQ9nb4Pkvgll1ZkR9g/lJqgPVjrtASgkAkQQOHeJXACBJk+HlcB7Pk1UyGo1m83mSJpcXl9fjMeMsKoBzLjhjQggZ6JP3cVEUAFAEoHgQKKUilCA4SKmc81XAmK5g70vvyz9hjEXEyGpJCWGUOeeMMc45rbUQon9cye50zlX3qOtaKdX1bFSBqK211pje7H1prfPeNw+30AS2223TNM65blVaFUKIqqrC9+5w1uZZRikFAM4YZ2EoXLCAUso5V9e11joyKMOwARGVVOF5AwChZx8K2VGGEfTl3JlDYkYppYQiakSklIWxAmOMECKEYIznOZGqy47Y7bkfWFfGLTbQB85ZIUQWWiiEoCRnlHDO8ywjhOzMxthbdYOzIba7aw8BzLgkAqVSRVFIKY2xkUWwBv8mrazBjMMqIxvKCxA03whGDMof3yQhjEJrNQsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/4096cf953dc255c861a16e417dfd6ed5/7f61c/windows_environment_variables-fs8.webp 400w,
/static/4096cf953dc255c861a16e417dfd6ed5/fd768/windows_environment_variables-fs8.webp 618w&quot;
              sizes=&quot;(max-width: 618px) 100vw, 618px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/4096cf953dc255c861a16e417dfd6ed5/e17e5/windows_environment_variables-fs8.png 400w,
/static/4096cf953dc255c861a16e417dfd6ed5/6e6fb/windows_environment_variables-fs8.png 618w&quot;
            sizes=&quot;(max-width: 618px) 100vw, 618px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/4096cf953dc255c861a16e417dfd6ed5/6e6fb/windows_environment_variables-fs8.png&quot;
            alt=&quot;windows_environment_variables-fs8&quot;
            title=&quot;windows_environment_variables-fs8&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You can see that the PATH variable has a series of directory paths, separated by a semicolon. Going to edit it opens up a new window which shows everything off nicely:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 538px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b187c550342bcbc00dc09da76e580a08/9516f/windows_10_variable_editor-fs8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 65.49999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABhElEQVQoz5WQ227TQBCG91UQIhbidXgsKie9gAvnAXgPUpqL0kokJPFhd30+rNfgtddJtSdDaBWEANF8+jUajebXPxrQvH+dv3lWXb4s7El68YJcWnI+Ec5EOsd6kpxbcm4Jx5KOJZzJ/t1z+vYVaJYOW9jsatYu7PbDtLua7pfT4fqX9svZsJzxj/ZR1/Zp3i0uAKFfYdbefcEbXEVV78cNzFlY9ihnuOhgzmDBcNlxPfbK1FwndL/yclj0FW1BnYUda2lV8p6NRmkljJJGS6PEsT40SoyjHkfNe5bGobtZYwRJCgHJI63N+BNjHpsT2jyitdHGdD1P4sTd7cIoJlkIygSr08rvaG3upTkIdRDyINS90N+6IYBwvVpDhB/M6F/mP+Gcx1F0d3vr+UGVYZBHwVlmSmlZlbRpaBGfbU6S1HNdhFBdRMeHqSe7OecIwvXn1c71qiwEKfb105OHAUG43W43W/c/3/5rMiGkLApS06ZMQJ3H55w9wCD4dHPj+f6P5O/v98ZY4KyMegAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/b187c550342bcbc00dc09da76e580a08/7f61c/windows_10_variable_editor-fs8.webp 400w,
/static/b187c550342bcbc00dc09da76e580a08/b52d2/windows_10_variable_editor-fs8.webp 538w&quot;
              sizes=&quot;(max-width: 538px) 100vw, 538px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/b187c550342bcbc00dc09da76e580a08/e17e5/windows_10_variable_editor-fs8.png 400w,
/static/b187c550342bcbc00dc09da76e580a08/9516f/windows_10_variable_editor-fs8.png 538w&quot;
            sizes=&quot;(max-width: 538px) 100vw, 538px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/b187c550342bcbc00dc09da76e580a08/9516f/windows_10_variable_editor-fs8.png&quot;
            alt=&quot;windows_10_variable_editor-fs8&quot;
            title=&quot;windows_10_variable_editor-fs8&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This isn’t present in earlier versions of Windows, so you’ll have to type it in yourself by double clicking the value of the PATH variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you want to add to the front of the PATH&lt;/strong&gt;, type the full directory path (or paste it in), and add a semicolon to separate it from the next directory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you want to add it to the end of the PATH&lt;/strong&gt;, add a semicolon to the end, then paste your directory path in.&lt;/p&gt;
&lt;p&gt;For Windows 10 users, just click the New button, then Browse, then navigate using the folder controls and clicking OK. It will then appear in the list.&lt;/p&gt;
&lt;h3&gt;UNIX style/Linux style&lt;/h3&gt;
&lt;p&gt;If you’re a Linux user, a macOS user, or maybe BSD, you don’t get a system dialogue like Windows users. But don’t worry, because it’s much easier to alter the PATH variable. It might look a little messy, but so long as you understand how it works, you’ll be fine.&lt;/p&gt;
&lt;p&gt;To get going, you’ll want to open up your preferred terminal application, and type &lt;code class=&quot;language-text&quot;&gt;echo $PATH&lt;/code&gt; and execute, you’ll probably get something like, but not precisely this (lines have been separated for readability):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token environment constant&quot;&gt;$PATH&lt;/span&gt;
/home/minh/.gem/ruby/2.5.0/bin:
/home/minh/.cargo/bin:
/home/minh/.npm-global/bin:
/usr/local/sbin:
/usr/local/bin:
/usr/bin:
/opt/android-sdk/platform-tools:
/usr/lib/jvm/default/bin:
/usr/bin/site_perl:
/usr/bin/vendor_perl:
/usr/bin/core_perl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As stated earlier, the PATH variable will be searched from start to end when you intend to execute a program.&lt;/p&gt;
&lt;p&gt;So how about adding some directories to that list? It’s easy, just edit the proper file! If you’re using the defaults, chances are the file to edit is &lt;code class=&quot;language-text&quot;&gt;~/.bashrc&lt;/code&gt;. If you’re me with Zsh, the file you want to edit is &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt;. It’ll be similar if you’re using anything else!&lt;/p&gt;
&lt;p&gt;The reason for the &lt;code class=&quot;language-text&quot;&gt;~&lt;/code&gt; is because these configuration files are based in your home directory, files which you can tailor to your needs.&lt;/p&gt;
&lt;p&gt;Anyway, to edit the variable, you’ll want to open up this file in a text editor. We’ll use nano to open it up, with &lt;code class=&quot;language-text&quot;&gt;nano ~/.bashrc&lt;/code&gt;. You’ll likely get a little bit of preconfigured stuff, though we’ll leave it for now. Navigating to the bottom of the file, we can make our new changes.&lt;/p&gt;
&lt;p&gt;For instance, you get a program that’s cool to you. It’s simply called cool, and it exists in &lt;code class=&quot;language-text&quot;&gt;/home/me/myowndirectory&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you want to add this directory to the front of the PATH&lt;/strong&gt;, you can do it by specifying the directory before listing the variable itself, separated by a colon (:).&lt;/p&gt;
&lt;p&gt;What does that look like? It looks something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;PATH=/home/me/myowndirectory:$PATH&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This can be useful in context of how the PATH variable is processed. You can place it at the front if you want to use your version of &lt;code class=&quot;language-text&quot;&gt;cool&lt;/code&gt; over the version provided in &lt;code class=&quot;language-text&quot;&gt;/usr/bin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you want to add it to the end of the PATH&lt;/strong&gt;, simply add it to the end instead:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;PATH=$PATH:/home/me/myowndirectory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What’s important is that &lt;code class=&quot;language-text&quot;&gt;$PATH&lt;/code&gt; is present, as it encompasses all those other directories that are referenced, including the system binaries. If you don’t include it, you can lose access to system utilities like &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;ls&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;rm&lt;/code&gt; to name a few.&lt;/p&gt;
&lt;p&gt;You can save the file by hitting &lt;code class=&quot;language-text&quot;&gt;Ctrl&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;O&lt;/code&gt;, pressing &lt;code class=&quot;language-text&quot;&gt;Y&lt;/code&gt; to confirm, then &lt;code class=&quot;language-text&quot;&gt;Ctrl&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;X&lt;/code&gt; to exit.&lt;/p&gt;
&lt;p&gt;To confirm that your changes worked, you can simply open up another terminal, and running &lt;code class=&quot;language-text&quot;&gt;echo $PATH&lt;/code&gt; again. You should see it in the output at the front or end respectively.&lt;/p&gt;
&lt;p&gt;Alternatively, you can refresh your existing terminal by running the &lt;code class=&quot;language-text&quot;&gt;source&lt;/code&gt; command. Simply type &lt;code class=&quot;language-text&quot;&gt;source ~/.bashrc&lt;/code&gt; to reload the configuration, and you should be able to confirm that it works by following the method above!&lt;/p&gt;
&lt;p&gt;I hope this helps you developers in understanding PATH variables, and I’ll see you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Making Event Planner]]></title><description><![CDATA[So, a few months ago, our class was divided into groups, and were given freedom to pursue our own project of choice. While this sounds like…]]></description><link>https://mnguyen.io/blog/making-event-planner/</link><guid isPermaLink="false">https://mnguyen.io/blog/making-event-planner/</guid><pubDate>Thu, 14 Dec 2017 10:23:00 GMT</pubDate><content:encoded>&lt;p&gt;So, a few months ago, our class was divided into groups, and were given freedom to pursue our own project of choice. While this sounds like quite an exciting thing, I learned whilst working on it a few things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Coming up with a product idea is really tough&lt;/li&gt;
&lt;li&gt;Issues are a great way to make actionable tasks&lt;/li&gt;
&lt;li&gt;Keeping in contact is important&lt;/li&gt;
&lt;li&gt;Sometimes, you have to wrangle technology&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’ll break down how I came to these points when you’re thinking of starting a project of your own. You can check it out &lt;a href=&quot;https://quodivent.azurewebsites.net/&quot;&gt;here&lt;/a&gt;, and check out the code on GitHub &lt;a href=&quot;https://github.com/hipdesignchat/event-planner/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Coming up with a product idea&lt;/h2&gt;
&lt;p&gt;We had been split up into groups, and the first question that came out was,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“So, what are we making?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Turns out that is a really difficult question to ask, and not something that really can be sorted easily by students studying web development, and not marketing.&lt;/p&gt;
&lt;p&gt;We were able come up with a few ideas, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A map that shows useful facilities around cities&lt;/li&gt;
&lt;li&gt;An ingredient database which notifies users when food is about to spoil&lt;/li&gt;
&lt;li&gt;An event planner which users can use to organise, conduct, and pay for events&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, we sort of ran out of ideas. We agreed that we should definitely pick just one of those things listed above, and just run with it. Event Planner won.&lt;/p&gt;
&lt;p&gt;In retrospect, I think the personal ingredient database might be more marketable since it solves a problem I tend to have, it doesn’t seem particularly difficult to implement, but not everyone was for it.&lt;/p&gt;
&lt;h2&gt;Issues make good actionable tasks&lt;/h2&gt;
&lt;p&gt;Of the constraints that we had at the time, it was quite a busy time of the year. With multiple assignments from other subjects, it was important to prioritise certain tasks over others.&lt;/p&gt;
&lt;p&gt;For our group assignment, this could be done intuitively since we could make use of GitHub Issues. This could also be achieved with functionality in GitLab, but for the purpose of the assignment (as well as keeping friction low), we went with GitHub.&lt;/p&gt;
&lt;p&gt;Our project wasn’t exceptionally large, so the main features we made use of in Issues were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assignees&lt;/li&gt;
&lt;li&gt;Labels, and&lt;/li&gt;
&lt;li&gt;Milestones&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Being able to delegate tasks to other group members was essential in guiding their work into problems that need solving, and it also tells us how much work is done by people in the group&lt;/p&gt;
&lt;p&gt;Labels (a.k.a tags) were useful to tell us what sort of problems or tasks we were coming across, and it helped with assigning people to the issues.&lt;/p&gt;
&lt;p&gt;Milestones were useful to prioritise essential features over the fancier features which were nice, but not part of the core set of things to include. This ended up in a document of its own with the specifications.&lt;/p&gt;
&lt;h2&gt;Staying in touch&lt;/h2&gt;
&lt;p&gt;Our group could only meet up reliably about once every week, since some of us weren’t available for class all of the time—one member of our group was a part-time student.&lt;/p&gt;
&lt;p&gt;Communication through GitHub Issues is helpful in talking about specific problems, but for general day to day things, we needed another platform to talk on.&lt;/p&gt;
&lt;p&gt;We ended up going through Slack. It provided a free plan which was adequate for our needs—after all, we were unlikely to need a message history past 10,000 messages, huge file storage, compliance features, or the more deeper administration settings that the paid plans had.&lt;/p&gt;
&lt;p&gt;Slack ended up very handy for immediate communication when we were working. When working on any particular issue, we could talk about problems we had along the way, and everyone could chime in with ideas and potential solutions.&lt;/p&gt;
&lt;h2&gt;Wrangling the technology&lt;/h2&gt;
&lt;p&gt;Laravel is pretty good. But when you’re running short on time in the semester, you really have to hustle to grab everything and pull it together into a coherent project that you can demo.&lt;/p&gt;
&lt;p&gt;The last time I worked on a major project was with a framework called &lt;a href=&quot;https://codeigniter.com/&quot;&gt;CodeIgniter&lt;/a&gt;. Currently maintained by the British Columbia Institute of Technology, its structure is ideal for the concept of MVC (model, view, controller), which is a good way of separating data operations, displaying information to users, and all the logic that glues it together.&lt;/p&gt;
&lt;p&gt;Laravel is similar in that you can use it with MVC. But the structure is different enough to my use of CodeIgniter that not everything that I assumed would be the same was actually the case.&lt;/p&gt;
&lt;p&gt;The best way of learning Laravel is through some video tutorials, which I felt was a downside since I prefer to read the steps and get going at my own pace. With the videos, I typically had to pause and rewind several times before I had a process down.&lt;/p&gt;
&lt;p&gt;Mind you, this is from my perspective; someone who is already into video tutorials would likely have a great time using them.&lt;/p&gt;
&lt;h3&gt;But wait, there’s more!&lt;/h3&gt;
&lt;p&gt;We used Laravel in hope of deploying it to commercial infrastructure, and for that, we decided to go ahead and use Microsoft Azure, using their App Services.&lt;/p&gt;
&lt;p&gt;As a student, we can use basic Azure services, which means we don’t have access to any paid services (which turns out to be a lot of services) such as creating an instance to run our database, more on that later.&lt;/p&gt;
&lt;p&gt;It was a relatively simple job to set up the deployment so we could push our Git repository to the container that was allocated to us. Of course, we needed to automate a few things for it to work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Composer, so we can resolve the back-end dependencies for our app&lt;/li&gt;
&lt;li&gt;Node.js, so we can resolve dependencies for compiling front-end assets&lt;/li&gt;
&lt;li&gt;Execute a PHP command (namely &lt;code class=&quot;language-text&quot;&gt;php artisan migrate&lt;/code&gt;) in order to make clean changes to the database structure&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This all went well, up until the demo day.&lt;/p&gt;
&lt;h3&gt;Day of the Demo&lt;/h3&gt;
&lt;p&gt;It’s typically dangerous to make changes to your software when you’re about to present it. I push the changes from our repository live, and it seems alright for a bit.&lt;/p&gt;
&lt;p&gt;Then we try to fill in some demo data, so the visitors have something to look at. Not much help making an events site without no events to go to, right?&lt;/p&gt;
&lt;p&gt;It throws an error, and then we scramble.&lt;/p&gt;
&lt;p&gt;Turns out that the migration tool couldn’t connect to the &lt;a href=&quot;https://blogs.msdn.microsoft.com/appserviceteam/2017/03/06/announcing-general-availability-for-mysql-in-app/&quot;&gt;MySQL in-app instance&lt;/a&gt;, which meant that the migrations made to creating the categories table did not work at all. So we had to backpedal a significant chunk of code for linking categories with events.&lt;/p&gt;
&lt;h2&gt;At the End of the day&lt;/h2&gt;
&lt;p&gt;I haven’t at this time been able to get any migrations to work on the App Service. Despite the environmental variables being set, the &lt;code class=&quot;language-text&quot;&gt;artisan&lt;/code&gt; script doesn’t seem to utilise them.&lt;/p&gt;
&lt;p&gt;There’s some work to be done on the back-end and front-end stuff, since we weren’t able to get all the features in to make it feature complete. Some of the things to do include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implementing a published flag so unpublished events do not show up&lt;/li&gt;
&lt;li&gt;Fixing a hover effect which doesn’t make the site usable with mobile devices&lt;/li&gt;
&lt;li&gt;Implementing the categories feature more fully&lt;/li&gt;
&lt;li&gt;Better looking search component, since it was basically just a text list&lt;/li&gt;
&lt;li&gt;Letting organisers set an event image&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite all the work to be done, I’m pretty happy with how the group operated and the work that they did. We learned a lot about creating and deploying an application, from development to a live site. Hopefully, this will be useful for you!&lt;/p&gt;
&lt;p&gt;Once again, you can check out the code &lt;a href=&quot;https://github.com/hipdesignchat/event-planner/&quot;&gt;here&lt;/a&gt; and the demo site &lt;a href=&quot;https://quodivent.azurewebsites.net/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Getting changes from upstream in Git]]></title><description><![CDATA[If you’ve ever clicked the fork button on GitHub, you’ll find yourself with a snapshot of the code. You think about working on the changes…]]></description><link>https://mnguyen.io/blog/getting-changes-from-upstream-in-git/</link><guid isPermaLink="false">https://mnguyen.io/blog/getting-changes-from-upstream-in-git/</guid><pubDate>Mon, 16 Oct 2017 04:39:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’ve ever clicked the fork button on GitHub, you’ll find yourself with a snapshot of the code. You think about working on the changes for a bit, but you decide to leave it for the afternoon and come back to it later.&lt;/p&gt;
&lt;p&gt;Then, you look back at the original repository, and suddenly see that those guys have made some changes, committed them, and pushed them online. You can tell, because it’s right there!&lt;/p&gt;
&lt;p&gt;But your copy doesn’t have those changes. What gives?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;gatsby-resp-image-figure&quot; style=&quot;&quot;&gt;
    &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1328px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/add6706cc6e195a4549f66182dfd0cfa/6569d/github-fork-changes-fs8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 48.25000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAABqUlEQVQozyVRi24aQQy8/2spIbwaokaV+tNVlSYpB+HguIPd9WPtfVUL1siy7BlZHjfL55+L7z/m683jejOdryez1eRhMX1cfZnOF+vnzcuv5dPLfP38uN7MVk+T2XLysJg8LL/NVl+ny6Y7Dd0IgOQAARHuGclY1x1P+2786OxxBKRKcEg3Jtlb3TAhMSMzACJ7h4KsGoIXYQQyA5IHZCJfeRKIlb2KSAixGVGuKIZu4EixaCr3QBaoPO/Fq4oG5ZA5lJTrNJfSvP7Z/Xs77Lf99r1rP47H/bn96K7brbavfdu2//r3192tPx525/b9cNgNl8+T3/61b7+b9vO878Z9NzpQh2qcGKeMHq6m74fuWLHbH8+DcY4RBcATsqKzw9CcLsCaLKkhYc2ayx2SimXpLQyOB+dPV7iAXChYnzEUCAVjaSynUrIzo3MAAOLlfmUM0QH1hlIuzHQ1tjrOohpzKTmXlEozQMi5ENUfIBEAsa/iECIin63EVKRqjXNorANAEVWtqubsYs5FRNnXpV4k5+pmzpnYD1ZjKiGmOlP1KiHGlHK6Of4fAS4XpLdUTe0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/add6706cc6e195a4549f66182dfd0cfa/7f61c/github-fork-changes-fs8.webp 400w,
/static/add6706cc6e195a4549f66182dfd0cfa/d00b9/github-fork-changes-fs8.webp 800w,
/static/add6706cc6e195a4549f66182dfd0cfa/9821d/github-fork-changes-fs8.webp 1328w&quot;
              sizes=&quot;(max-width: 1328px) 100vw, 1328px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/add6706cc6e195a4549f66182dfd0cfa/e17e5/github-fork-changes-fs8.png 400w,
/static/add6706cc6e195a4549f66182dfd0cfa/5a190/github-fork-changes-fs8.png 800w,
/static/add6706cc6e195a4549f66182dfd0cfa/6569d/github-fork-changes-fs8.png 1328w&quot;
            sizes=&quot;(max-width: 1328px) 100vw, 1328px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/add6706cc6e195a4549f66182dfd0cfa/6569d/github-fork-changes-fs8.png&quot;
            alt=&quot;Two repositories side by side. On the left is the original where maintainers have made a few new commits. On the right hand side is my fork&quot;
            title=&quot;Here’s an example of where my fork hasn’t yet kept up with the official repo. Note the message on the right: “This branch is 3 commits behind”.&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;&lt;p&gt;Here’s an example of where my fork hasn’t yet kept up with the official repo. Note the message on the right: “This branch is 3 commits behind”.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Regardless of the reasoning behind it, it’s probably a good idea to pull the changes from the original repository before you make your own modifications. I mean, it’s possible to make your own beforehand, but that can make things a lot more messy. Plus, if you want to contribute back to the original project, being able to pull those changes is essential.&lt;/p&gt;
&lt;p&gt;So, if you open up your terminal and browse to your copy of the repository, you will discover that it has one remote, like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;~/my-repo $ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote
origin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes&quot;&gt;Git documentation has this to say about a remote&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remote repositories are versions of your project that are hosted on the Internet or network somewhere. You can have several of them, each of which generally is either read-only or read/write for you. Collaborating with others involves managing these remote repositories and pushing and pulling data to and from them when you need to share work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The origin repo is most likely to be the master repo from your fork. In order to get our updates, we need to add a remote repository to the configuration so we can pull the changes into our repo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;~/my-repo $ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; upstream https://github.com/megacorp/my-repo
~/my-repo $ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote -v
origin    https://github.com/me/my-repo &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fetch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
origin    https://github.com/me/my-repo &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;push&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
upstream  https://github.com/megacorp/my-repo &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fetch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
upstream  https://github.com/megacorp/my-repo &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;push&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

You can substitute &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;upstream&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; any name, but it’s always a good idea to use a descriptive name.

Now we’ve &lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt; that, we can fetch those new changes, with &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; pull upstream master&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; The order matters &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; this case—the first argument &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;upstream&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; is the remote we want to pull from, and the second &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;master&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; is the branch that we want to pull into.

You should now have the latest changes to start working on things&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# But I’ve already committed my files!&lt;/span&gt;
No need to panic&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; You just need to pull as you have before. If you’re lucky, the changes made will automatically merge. But you might run into this message:

```bash
~/my-repo $ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; pull upstream
remote: Counting objects: &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;, done.
remote: Compressing objects: &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;% &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;/2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;, done.
remote: Total &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delta &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;, reused &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delta &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
Unpacking objects: &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;% &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;/3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;, done.
From https://github.com/megacorp/my-repo
   5ccaa0e&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;60e80ce  master     -&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; origin/master
Auto-merging README.md
CONFLICT &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;: Merge conflict &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; README.md
Automatic merge failed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; fix conflicts and &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt; commit the result.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This can happen if you’ve happened to edit the same file as the others. So you’ll need to resolve this conflict before we can keep going. So if we open up &lt;code class=&quot;language-text&quot;&gt;README.md&lt;/code&gt;, you’ll see your file, but it has a few extra things:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;git&quot;&gt;&lt;pre class=&quot;language-git&quot;&gt;&lt;code class=&quot;language-git&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
Readme
=======
This is a readme from Megacorp

&gt;&gt;&gt;&gt;&gt;&gt;&gt; 60e80ce224f9e6ebdfc38a9b0182cd1a35bedb4e&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The lines from &lt;code class=&quot;language-text&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;=======&lt;/code&gt; refers to the changes that are in your repo, and from &lt;code class=&quot;language-text&quot;&gt;=======&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; refers to the changes made upstream.&lt;/p&gt;
&lt;p&gt;So, to fix this, we can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep our changes only&lt;/li&gt;
&lt;li&gt;Keep the changes from upstream, or&lt;/li&gt;
&lt;li&gt;Make a new change entirely&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To go about any of these processes, we have to delete a few lines. The markers for one have to go. Say we want to do option 2, and keep only their changes, the modified file would look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;This is a readme from Megacorp&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note in this case, Megacorp decided to add an extra line at the end of the document.&lt;/p&gt;
&lt;p&gt;Commit our changes, and we’re done!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;~/my-repo $ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; README.md
~/my-repo $ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit -m &lt;span class=&quot;token string&quot;&gt;&quot;Resolve readme conflict with upstream&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;master 4f8c41f&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; Resolve readme conflict with upstream&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hopefully this has helped with getting your work in!&lt;/p&gt;
&lt;h2&gt;Other useful links&lt;/h2&gt;
&lt;p&gt;Here’s some other resources I think will help you resolve your conflicts when pulling in the latest work from a repo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/&quot;&gt;GitHub: Resolving a merge conflict using the command line&lt;/a&gt;: This covers what I’ve written, plus how to handle when a file gets removed entirely from a repository.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://help.github.com/articles/merging-a-pull-request/&quot;&gt;GitHub: Merging a pull request&lt;/a&gt;: This specifically details the process of a pull request, if that’s how your workflow goes. A bit off-topic, but the people upstream will have to handle this!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches&quot;&gt;Pro Git: Git Branching—Remote Branching&lt;/a&gt;: Some more comprehensive reading into how remote branches work. They use &lt;code class=&quot;language-text&quot;&gt;git fetch&lt;/code&gt; instead of &lt;code class=&quot;language-text&quot;&gt;git pull&lt;/code&gt;, as some people may get confused.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/k88hudson/git-flight-rules&quot;&gt;Flight rules for Git&lt;/a&gt;: An excellent primer on how to do common things in Git, as well as ways out of tricky situations you may get into, such as deleting your branch before you’re done.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Everyone’s using their phones]]></title><description><![CDATA[If you’ve ever been on public transport, you’ve probably seen people on their smartphones. In fact, if you’ve walked about, or driven…]]></description><link>https://mnguyen.io/blog/everyone-is-using-their-phones/</link><guid isPermaLink="false">https://mnguyen.io/blog/everyone-is-using-their-phones/</guid><pubDate>Thu, 28 Sep 2017 10:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1440px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8b816670f5853bccd142df77b94b5f59/644c5/central-station-bw.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 44.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHKaphCQ//EABcQAQADAAAAAAAAAAAAAAAAAAEAESD/2gAIAQEAAQUCI1n/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAZEAACAwEAAAAAAAAAAAAAAAAAASAhMYH/2gAIAQEABj8CKT6ZD//EABwQAAIBBQEAAAAAAAAAAAAAAAABERAxQVGhkf/aAAgBAQABPyFFrhHHkEvHIrUZ/9oADAMBAAIAAwAAABAjz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABsQAQADAQADAAAAAAAAAAAAAAEAITEREGHx/9oACAEBAAE/ELz2HcvuyoAcBAbCsJwpX38eA0mp/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/8b816670f5853bccd142df77b94b5f59/7f61c/central-station-bw.webp 400w,
/static/8b816670f5853bccd142df77b94b5f59/d00b9/central-station-bw.webp 800w,
/static/8b816670f5853bccd142df77b94b5f59/f992d/central-station-bw.webp 1440w&quot;
              sizes=&quot;(max-width: 1440px) 100vw, 1440px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/8b816670f5853bccd142df77b94b5f59/066f9/central-station-bw.jpg 400w,
/static/8b816670f5853bccd142df77b94b5f59/4b190/central-station-bw.jpg 800w,
/static/8b816670f5853bccd142df77b94b5f59/644c5/central-station-bw.jpg 1440w&quot;
            sizes=&quot;(max-width: 1440px) 100vw, 1440px&quot;
            type=&quot;image/jpeg&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/8b816670f5853bccd142df77b94b5f59/644c5/central-station-bw.jpg&quot;
            alt=&quot;Platform view of Central Station&quot;
            title=&quot;Platform view of Central Station&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If you’ve ever been on public transport, you’ve probably seen people on their smartphones. In fact, if you’ve walked about, or driven anywhere, you’ve probably seen a person tapping away on their phones, more likely than not.&lt;/p&gt;
&lt;p&gt;People are doing everything, from socialising, to paying bills, watching video, and reading articles on their phones. All this while they’re on their commute—and this is time you used to have reading the newspaper or looking out the window!&lt;/p&gt;
&lt;p&gt;If your website isn’t designed to handle users using different devices, they won’t be happy. Some will put up with it (especially if you’ve got useful information no-one else has), some may tolerate it.&lt;/p&gt;
&lt;p&gt;But other users may become agitated, frustrated, and may end up leaving your site, without the information they were after, without getting what they needed done, without buying the most expensive thing in your shop on their phone because it was just too difficult.&lt;/p&gt;
&lt;p&gt;By not designing your site properly, you can’t assume your users will be able to see what they’re after:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;gatsby-resp-image-figure&quot; style=&quot;&quot;&gt;
    &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1280px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/fb5e05b7e9fff5ac3f112b0137af7b82/eea4a/abc-desktop-mobile.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.25%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMBAgT/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAFdsUDRQf/EABsQAAIDAAMAAAAAAAAAAAAAAAECAAMSERMx/9oACAEBAAEFAlVenKS0BbdHjRns/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHRAAAgIBBQAAAAAAAAAAAAAAAAECETEQITJRov/aAAgBAQAGPwKMnG232cPRJLCZV7GdP//EABsQAQACAwEBAAAAAAAAAAAAAAEAESExQVHR/9oACAEBAAE/Ic+Al4TX6fPyGfWASmhdVA9KKq1tez//2gAMAwEAAgADAAAAENMP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHBABAQACAgMAAAAAAAAAAAAAAREAMSFhQVGh/9oACAEBAAE/EKRoY8Ehp7yAlgBVj5m6CCmjAoKtnF9zAoI64xy5FU1XP//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/fb5e05b7e9fff5ac3f112b0137af7b82/7f61c/abc-desktop-mobile.webp 400w,
/static/fb5e05b7e9fff5ac3f112b0137af7b82/d00b9/abc-desktop-mobile.webp 800w,
/static/fb5e05b7e9fff5ac3f112b0137af7b82/af3f0/abc-desktop-mobile.webp 1280w&quot;
              sizes=&quot;(max-width: 1280px) 100vw, 1280px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/fb5e05b7e9fff5ac3f112b0137af7b82/066f9/abc-desktop-mobile.jpg 400w,
/static/fb5e05b7e9fff5ac3f112b0137af7b82/4b190/abc-desktop-mobile.jpg 800w,
/static/fb5e05b7e9fff5ac3f112b0137af7b82/eea4a/abc-desktop-mobile.jpg 1280w&quot;
            sizes=&quot;(max-width: 1280px) 100vw, 1280px&quot;
            type=&quot;image/jpeg&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/fb5e05b7e9fff5ac3f112b0137af7b82/eea4a/abc-desktop-mobile.jpg&quot;
            alt=&quot;The ABC desktop site simulated on a phone. The content flows off the side of the screen.&quot;
            title=&quot;If you aren’t prepared, your visitors won’t be able to find the Sports section! Luckily, the ABC does do something to remedy this below.&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;&lt;p&gt;If you aren’t prepared, your visitors won’t be able to find the Sports section! Luckily, the ABC does do something to remedy this below.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;But what do you need to do to make things easier for the people that visit your site? There’s a couple of options I’ll investigate:&lt;/p&gt;
&lt;h2&gt;Option 1: Give them their own site!&lt;/h2&gt;
&lt;p&gt;This idea is great if you’re looking to make a fresh start without depending on your existing code. All you have to do is create a new site that is solely dedicated to your mobile users, style it, and redirect them when you detect it! In fact, this is what the ABC (Australian Broadcasting Corporation) does for their website:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;gatsby-resp-image-figure&quot; style=&quot;&quot;&gt;
    &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 360px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5b1a328425e425aa8af39505179dcdcb/158ba/abc-mobile-1.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 177.77777777777777%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAkABQDASIAAhEBAxEB/8QAGgABAAIDAQAAAAAAAAAAAAAAAAIEAQMFBv/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAa+/fZOAkOtdoXzzjAiAD//EAB0QAAICAgMBAAAAAAAAAAAAAAECAAMEMhATFCH/2gAIAQEAAQUCqp7B5Yfhw1VktqUR98HS4gR98JgFcq0bbn//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AV//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AV//xAAgEAABBAEEAwAAAAAAAAAAAAACAAERcRIQICEzMUGB/9oACAEBAAY/AnfJhtdoaFkzPyhxCOfQorRWhmPKK0UuuyPqe9n/xAAgEAEAAgIBBAMAAAAAAAAAAAABABEhQaEgMVFhscHw/9oACAEBAAE/IUqMYj82CwdYmNF2L1EvcK2chOK+ISkDyv6nIQtAbO7BDS3gxW5tdH//2gAMAwEAAgADAAAAEIALDAPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxBf/8QAFhEAAwAAAAAAAAAAAAAAAAAAECBx/9oACAECAQE/EBE//8QAIBABAAICAQQDAAAAAAAAAAAAAQARMWFRECFB8HGBof/aAAgBAQABPxC4CSzq3PaFsWeDy/YuRJXyQzEGg6faPoYe5zfBueq5ZTu1ujywhOvq56rljz8wAWVuCpTeSXp1CYWIHVszmUcHT//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/5b1a328425e425aa8af39505179dcdcb/a3012/abc-mobile-1.webp 360w&quot;
              sizes=&quot;(max-width: 360px) 100vw, 360px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/5b1a328425e425aa8af39505179dcdcb/158ba/abc-mobile-1.jpg 360w&quot;
            sizes=&quot;(max-width: 360px) 100vw, 360px&quot;
            type=&quot;image/jpeg&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/5b1a328425e425aa8af39505179dcdcb/158ba/abc-mobile-1.jpg&quot;
            alt=&quot;The dedicated ABC mobile site&quot;
            title=&quot;A separate site design can be appropriate, if you have the resources.&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;&lt;p&gt;A separate site design can be appropriate, if you have the resources.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;But that means you have to deal with the fact you have not just one, but &lt;strong&gt;two&lt;/strong&gt; site codebases. Two different site structures, two different stylesheets, and two different experiences. If you ever update one of the sites, you’ll have to modify the other as well.&lt;/p&gt;
&lt;p&gt;You might have noticed another problem, and that is the fact you’ve got the site nailed down for desktop and mobile users. But what about those tablet users? Or the super amazing smartwatch? Or that hologram system you’ve never heard about before that is shaped like a car?&lt;/p&gt;
&lt;p&gt;If you’ve gone down this route before, you’re probably regretting it a lot now.&lt;/p&gt;
&lt;p&gt;This brings us to a solution that likely better works for you:&lt;/p&gt;
&lt;h2&gt;Option 2: Responsive Design&lt;/h2&gt;
&lt;p&gt;When the design of the website is optimised to respond to the various differences between devices, it’s called responsive design—meaning a user has a useful experience, no matter what platform they’re coming from.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;gatsby-resp-image-figure&quot; style=&quot;&quot;&gt;
    &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1440px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/090e2cfcd0c121ce8bba864691b838f2/644c5/ars.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 70%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBP/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAd87qXGD/8QAGRABAQADAQAAAAAAAAAAAAAAAQIAAxIR/9oACAEBAAEFArb6naoPuMLk6eTP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHhAAAQMEAwAAAAAAAAAAAAAAAQACERAhYYESIjH/2gAIAQEABj8CMGwwrS7VD29wo5O1T//EABsQAQACAwEBAAAAAAAAAAAAAAEAESExQRBR/9oACAEBAAE/IdNu1HkEZK8pBGI5WpsZQjBB9V5//9oADAMBAAIAAwAAABAQz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAQEBAQEBAAAAAAAAAAAAAAERIQAxQf/aAAgBAQABPxADw9cDC+tfef7ho5Gec+axjn3s6vFHxPbzChWQNbpvOy/Dv//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/090e2cfcd0c121ce8bba864691b838f2/7f61c/ars.webp 400w,
/static/090e2cfcd0c121ce8bba864691b838f2/d00b9/ars.webp 800w,
/static/090e2cfcd0c121ce8bba864691b838f2/f992d/ars.webp 1440w&quot;
              sizes=&quot;(max-width: 1440px) 100vw, 1440px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/090e2cfcd0c121ce8bba864691b838f2/066f9/ars.jpg 400w,
/static/090e2cfcd0c121ce8bba864691b838f2/4b190/ars.jpg 800w,
/static/090e2cfcd0c121ce8bba864691b838f2/644c5/ars.jpg 1440w&quot;
            sizes=&quot;(max-width: 1440px) 100vw, 1440px&quot;
            type=&quot;image/jpeg&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/090e2cfcd0c121ce8bba864691b838f2/644c5/ars.jpg&quot;
            alt=&quot;The Ars Technica website, loaded on three different devices&quot;
            title=&quot;The Ars Technica website uses responsive design to tailor the experience for users of different devices.&quot;
            loading=&quot;lazy&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;&lt;p&gt;The Ars Technica website uses responsive design to tailor the experience for users of different devices.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;For your desktop users, they will have the same experience as they’ve had before, no surprises there.&lt;/p&gt;
&lt;p&gt;But for people visiting on their tablets and smartphones, your site’s design will adapt to suit their devices. What does that entail exactly? Well, there are a few options, depending on what your designer may tell you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make essential actions easy to access&lt;/li&gt;
&lt;li&gt;Place navigation links under a dropdown menu&lt;/li&gt;
&lt;li&gt;Collapse main content and controls into columns&lt;/li&gt;
&lt;li&gt;Serve up smaller pictures for smaller devices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The end result is that your site is easier for people to access and use, particularly those that aren’t desktop users. Tablet users, mobile users, even laptop users can benefit from this!&lt;/p&gt;
&lt;p&gt;But watch out, and make sure that the resulting design should make a user’s life easier, rather than more difficult. Consider what it is that users want from your site, and how they can access it. Don’t just drop things for the sake of dropping things.&lt;/p&gt;
&lt;h2&gt;In conclusion&lt;/h2&gt;
&lt;p&gt;A lot of people are getting online with their smartphones, and it’s expected to grow. If you are still running a desktop-exclusive site design, your visitors won’t be as happy as being given a tailored experience.&lt;/p&gt;
&lt;p&gt;You could make a dedicated site design, but that’s more code, and more time sunk into making and maintaining it. Alternatively, you could integrate responsive design into your site, and make everyone a little more happier at the cost of a little file-size.&lt;/p&gt;
&lt;p&gt;Regardless of your approach, you should make sure that if you’re changing the experience for people on different devices, you shouldn’t take something away that they need. Make it easy to use, and everyone will be happier for it. Including you.&lt;/p&gt;</content:encoded></item></channel></rss>