<?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[John Espiritu]]></title>
        <description><![CDATA[John Espiritu]]></description>
        <link>https://jhnsprtu.com</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Sun, 10 Aug 2025 10:11:28 GMT</lastBuildDate>
        <atom:link href="https://jhnsprtu.com/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Building an App Launcher for Windows XP using C#]]></title>
            <description><![CDATA[I developed a custom app launcher for Windows XP using C#.]]></description>
            <link>https://jhnsprtu.com/blog/app-launcher-winxp</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/app-launcher-winxp</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Sun, 02 Jul 2023 19:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<figure style="display:block;text-align:center">
  <a href="/media/app-launcher1.gif" target="_blank" style="display:inline-block">
    <img src="/media/app-launcher1.gif" />
  </a>
</figure>
<p>Windows XP didn't have a Start Menu search functionality, a feature that was only introduced with Vista and later versions. As a bit of "retro" coding fun, I developed a Windows Form Application for such a feature using C#.</p>
<p>In this article, I discuss how I built it. Please note that it doesn't provide a step-by-step process and assumes that the reader has a background in C# programming.</p>
<h2 id="creatingtheproject">Creating the Project</h2>
<p>I used Visual Studio 2005 because it was my favorite IDE. This version works only with the .NET Framework 2.0. I created a C# Windows Form Application project.</p>
<h2 id="designingtheform">Designing the Form</h2>
<p>The UI has the following controls, arranged in a simple layout: textbox, listbox, checkbox, and button.</p>
<ul>
<li><code>TextBox</code> - where the user will enter the name of the application to run</li>
<li><code>ListBox</code> - list of the applications found in the Start Menu</li>
<li><code>CheckBox</code> - include/exclude uninstaller shortcuts</li>
<li><code>Button</code> - launch the application</li>
</ul>
<figure style="display:block;text-align:center">
  <a href="/media/app-launcher3.png" target="_blank" style="display:inline-block">
    <img src="/media/app-launcher3.png" />
  </a>
</figure>
<h2 id="retrievingthestartmenuitems">Retrieving the Start Menu Items</h2>
<p>The start menu is simply a list of shortcut (.lnk) files that are found in the users' directories under <code>C:\Documents and Settings</code>. These directories are:</p>
<ul>
<li><code>C:\Documents and Settings\All Users\Start Menu</code> – appears for all users (a.k.a "common")</li>
<li><code>C:\Documents and Settings\{Current User}\Start Menu</code> – appears for the current user, path depends on your account's name</li>
</ul>
<p>Simply copying the path from Explorer and defining them as constants isn't ideal. It's more appropriate to use certain APIs to retrieve directory paths accurately.</p>
<p>For the current user, it's straightforward:</p>
<pre><code class="c# language-c#">Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);
</code></pre>
<p>The above managed code approach didn't support the common start menu until .NET 3.5, so the only option was to use unmanaged code. On the <code>Program.cs</code> file, I added:</p>
<pre><code class="c# language-c#">using System.Runtime.InteropServices;
using System.Text;

/* static class Program */

[DllImport("shell32.dll")]
public static extern bool SHGetSpecialFolderPath(IntPtr hwnd, [Out] StringBuilder lpszPath, int nFolder, bool fCreate);

const int CSIDL_COMMON_STARTMENU = 0x16;

public static string GetAllUsersStartMenuDirectory()
{
    StringBuilder path = new StringBuilder(512);
    SHGetSpecialFolderPath(IntPtr.Zero, path, CSIDL_COMMON_STARTMENU, false);
    return path.ToString();
}
</code></pre>
<p>The next step involves compiling a list of applications located within these directories. These items are just shortcuts (i.e. files with the <code>.lnk</code> extension).</p>
<p>Similarly to any directory, they can also reside within subdirectories, therefore recursion is needed. To achieve this:</p>
<pre><code class="c# language-c#">String[] ExtractLinks(String path)
{
    return ExtractLinksRecursive(path, new String[0]);
}

String[] ExtractLinksRecursive(String path, String[] files)
{
    String[] pathFiles = Directory.GetFiles(path, "*.lnk");

    pathFiles = Utils.MergeArrays(pathFiles, files);

    String[] pathDirs = Directory.GetDirectories(path);

    foreach (String dir in pathDirs) {
        String[] dirFilePaths = ExtractLinksRecursive(dir, files);
        if (dirFilePaths.Length &gt; 0) {
            pathFiles = Utils.MergeArrays(pathFiles, dirFilePaths);
        }
    }

    return pathFiles;
}
</code></pre>
<p>These processes involve merging resulting arrays into one. To merge arrays in C#, I created a helper function in <code>Util.cs</code>:</p>
<pre><code class="c# language-c#">/* class Utils */

public static String[] MergeArrays(String[] a, String[] b)
{
    String[] mergedArray = new String[a.Length + b.Length];
    a.CopyTo(mergedArray, 0);
    b.CopyTo(mergedArray, a.Length);
    return mergedArray;
}
</code></pre>
<p>With the essential functions ready, I put these together in a method that gets called in the constructor. I used the <code>SortedDictionary</code> class so the apps are listed in ascending order.</p>
<pre><code class="c# language-c#">SortedDictionary&lt;String, String&gt; LoadStartMenuLinks()
{
    SortedDictionary&lt;String, String&gt; dictionary = new SortedDictionary&lt;String, String&gt;();

    String[] links = Utils.MergeArrays(
        ExtractLinks(Program.GetAllUsersStartMenuDirectory()),
        ExtractLinks(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu)));

    // the filename without extension becomes the key
    // the absolute path is the value
    // the SortedDictionary will sort by key in ascending order
    foreach (String p in links) {
        String filename = Path.GetFileNameWithoutExtension(p);
        if (dictionary.ContainsKey(filename)) {
            continue;
        }
        dictionary.Add(filename, p);
    }

    return dictionary;
}
</code></pre>
<p>I created a class member to store this list.</p>
<pre><code class="c# language-c#">SortedDictionary&lt;String, String&gt; linksList;

// constructor...
linksList = LoadStartMenuLinks();
</code></pre>
<h2 id="populatingthelistbox">Populating the List Box</h2>
<p>The <code>ListBox</code> can use the <code>SortedDictionary</code> data through a <code>BindingSource</code> object:</p>
<pre><code class="c# language-c#">appsList.DataSource = new BindingSource(linksList, null);
appsList.DisplayMember = "Key";
appsList.ValueMember = "Value";
</code></pre>
<figure style="display:block;text-align:center">
  <a href="/media/app-launcher1.png" target="_blank" style="display:inline-block">
    <img src="/media/app-launcher1.png" />
  </a>
</figure>
<p>To show only the applications matching the search input, I looped the full list and moved the items that contain the search string into a different <code>SortedDictionary</code>, then set that as the <code>ListBox</code>'s <code>DataSource</code>:</p>
<pre><code class="c# language-c#">void FilterLinks(String keyword)
{
    SortedDictionary&lt;String, String&gt; filteredData = new SortedDictionary&lt;String, String&gt;();

    foreach (KeyValuePair&lt;String, String&gt; val in linksList) {
        // exclude items containing "uninstall"
        Boolean containsUninstallWord = val.Key.ToLowerInvariant().Contains("uninstall");
        if (containsUninstallWord &amp;&amp; ExcludeUninstallersCheckbox.Checked) {
            continue;
        }
        // contains the search string
        if (val.Key.ToLowerInvariant().Contains(keyword.ToLowerInvariant())) {
            filteredData.Add(val.Key, val.Value);
        }
    }

    if (filteredData.Count == 0) {
        appsList.DataSource = null;
        return;
    }

    appsList.DataSource = new BindingSource(filteredData, null);
    appsList.DisplayMember = "Key";
    appsList.ValueMember = "Value";
}
</code></pre>
<p>The filtering executes on the form load event and the search box text change event:</p>
<pre><code class="c# language-c#">void OnMainFormLoad(object sender, EventArgs e)
{
    FilterLinks(searchbox.Text);
}

void OnSearchBoxTextChanged(object sender, EventArgs e)
{
    FilterLinks(((TextBox)sender).Text);
}
</code></pre>
<figure style="display:block;text-align:center">
  <a href="/media/app-launcher2.png" target="_blank" style="display:inline-block">
    <img src="/media/app-launcher2.png" />
  </a>
</figure>
<h2 id="runningthetargetapplication">Running the Target Application</h2>
<p>The <code>System.Threading.Process</code> can help start the chosen application:</p>
<pre><code class="c# language-c#">Process.Start(path);
</code></pre>
<p>It may throw an <code>Exception</code> on error, so I wrapped it in a <code>try-catch</code> statement. Putting that in a method to execute the selected value from the <code>ListBox</code>:</p>
<pre><code class="c# language-c#">void ExecuteSelectedLink()
{
    String path = appsList.SelectedValue.ToString();
    try {
        Process.Start(path);
        Application.Exit();
    } catch {
        MessageBox.Show("Failed to run application.", "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}
</code></pre>
<p>To execute the program when the user presses the <code>Enter</code> key after typing on the search box:</p>
<pre><code class="c# language-c#">void OnSearchBoxKeyDown(object sender, KeyEventArgs e)
{
    switch (e.KeyCode) {
        case Keys.Enter:
            if (appsList.SelectedItems.Count == 0) {
                return;
            }
            ExecuteSelectedLink();
            e.SuppressKeyPress = true;
            break;
    }
}
</code></pre>
<p>Or when the user presses the <code>Enter</code> key while the focus is on the <code>ListBox</code>:</p>
<pre><code class="c# language-c#">void OnAppListKeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Enter) {
        ExecuteSelectedLink();
    }
}
</code></pre>
<p>And of course, when the Launch <code>Button</code> is clicked:</p>
<pre><code class="c# language-c#">void OnLaunchActionClick(object sender, EventArgs e)
{
    ExecuteSelectedLink();
}
</code></pre>
<h2 id="handlingtheexpecteduserbehavior">Handling the Expected User Behavior</h2>
<p>I also made sure that the launcher handles the other common UX behaviors:</p>
<ul>
<li>Move the <code>ListBox</code> selection on <code>Up</code> and <code>Down</code> key down while focused on the search box</li>
<li>Close the launcher on <code>Esc</code> key</li>
<li>Launch the selected item when double-clicking on the <code>ListBox</code></li>
<li>Retain the last size and position of the window using <code>Properties.Settings</code></li>
<li>Search box select all on <code>CTRL + A</code></li>
</ul>
<h2 id="sourcecode">Source Code</h2>
<p>You can get the source code of this project from my Github <a href="https://github.com/johnillo/app-launcher">repositiory</a>.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Becoming Vegan]]></title>
            <description><![CDATA[An essay on how I decided to leave animals off my plate.]]></description>
            <link>https://jhnsprtu.com/blog/becoming-vegan</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/becoming-vegan</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Sun, 11 Jun 2023 23:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>I stopped eating meat in 2022 and went vegan. Like everybody else, I too was a meat eater.</p>
<p>The reason behind this is because I grew fond of pigs few years ago. Our cultures deemed these critters dirty, undesirable, and the symbol of gluttony. But I opened my eyes and learned to see them and other farm animals as individuals deserving love and respect.</p>
<p>How are they different from pet animals like dogs or cats? What did they do to deserve such horrible fate?</p>
<figure>
  <a href="/media/becoming-vegan-1.jpg" target="_blank">
    <img src="/media/becoming-vegan-1.jpg" />
  </a>
  <figcaption>We met the adorable rescue pigs in Animal Sanctuary in Campo, CA</figcaption>
</figure>
<p>Pointing out to other people that eating meat is wrong usually ends up in an argument. They'll say that animals like cows, pigs, and chickens exist for us to eat and that they taste good. Ironically, these same people would prosecute someone who hurt a dog and condemn poachers who hunt elephants for their ivory.</p>
<p>This is referred to as <a href="https://en.wikipedia.org/wiki/Speciesism">speciesism</a>. Animals that bring profit are treated as nothing more than commodities, while we feign concern for animal life by protecting those species that are endangered.</p>
<p>Some will argue that because animals don't possess human-like intelligence, they can be viewed as a resource for humans to use. While animals may not possess the same level of intelligence as humans, they are, like us, sentient beings — capable of feeling joy, love, pain, and suffering. Therefore, they should be treated with respect.</p>
<p>Asserting our superiority over animals is morally wrong. If we harbor this belief, it becomes all too easy to discriminate against people who appear or think differently from us, such as those of different races or genders. Our history is replete with atrocities caused by those who considered themselves special or important.</p>
<figure>
  <a href="/media/becoming-vegan-3.jpg" target="_blank">
    <img src="/media/becoming-vegan-3.jpg" />
  </a>
  <figcaption>San Diego Vegan Festival</figcaption>
</figure>
<p>It may have been necessary for our ancestors to consume animals for growth and survival, but that doesn't mean it's right to use animals. Moreover, we now live in an era where we can create things that have never existed before, such as computers, machines, and AI. Our knowledge and advancements in technology should enable us to reduce or even eliminate the use and abuse of animals.</p>
<p>Unfortunately, this isn't the case. Our population continues to grow, and with it, our consumption. Worse, the animal agriculture industry fuels this demand with assertions such as 'milk is good for the bones' and 'you need meat for protein'. Similarly, designers tout their leather products as fashionable and luxurious. Many businesses, reliant on the exploitation of animals, are driven by a desire for increased profit. They use technology to genetically modify animals, causing them to grow abnormally large, and then slaughter them en masse as efficiently as possible.</p>
<figure>
  <a href="/media/becoming-vegan-2.jpg" target="_blank">
    <img src="/media/becoming-vegan-2.jpg" />
  </a>
  <figcaption>Really good plant-based franks and brownies</figcaption>
</figure>
<p>Please watch <a href="https://www.youtube.com/watch?v=LQRAfJyEsko" target="_blank">this documentary</a> and see for yourself. This is disturbing and horrifying. If you like eating meat, at least get to know what the animals have to endure just to satisfy your palate.</p>
<p>It's interesting to observe here in the United States how terms like 'humanely slaughtered,' 'grass-fed,' and 'free-range' are used to describe meat from animals. However, there's nothing 'humane' about ending the life of a being that doesn't want to die. The animal agriculture industry uses these labels as a means to ease consumer guilt and promote their products as healthy, effectively sidestepping the ethical questions involved.</p>
<p>Veganism may seem 'extreme' to many because it challenges deeply ingrained pleasures and traditions. It's human nature to resist change. Often, people justify the consumption of animals by claiming it's the 'natural order', conveniently overlooking the unique attribute humans possess: the ability to choose. Unlike animals, we have the capacity to make ethical decisions about our diet.</p>
<figure>
  <a href="/media/becoming-vegan-4.jpg" target="_blank">
    <img src="/media/becoming-vegan-4.jpg" />
  </a>
  <figcaption>Vegan 'duck' Thai Food</figcaption>
</figure>
<p>So, what do vegans eat? They consume anything that doesn't contain meat or animal byproducts such as milk and eggs. But being vegan is more than just a diet. It's a lifestyle that also includes avoiding the purchase of items derived from animals, like leather and fur, and refraining from visiting places where animals are used for entertainment.</p>
<p>Let's all be kind to all kinds.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mobile Legends]]></title>
            <description><![CDATA[A MOBA mobile game I've been playing for about 6 years.]]></description>
            <link>https://jhnsprtu.com/blog/mlbb-gaming</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/mlbb-gaming</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Fri, 26 May 2023 15:30:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>I started playing <a href="https://mobilelegends.com">Mobile Legends: Bang Bang</a>, a <a href="https://en.wikipedia.org/wiki/Multiplayer_online_battle_arena">MOBA</a> game for mobile, roughly a few months after its initial release in 2016. It's just like <a href="https://en.wikipedia.org/wiki/Defense_of_the_Ancients">DotA</a> and <a href="https://en.wikipedia.org/wiki/League_of_Legends">LoL</a>. The game is available for Android and iOS.</p>
<figure>
  <a href="/media/mlbb-3.jpg" target="_blank">
    <img src="/media/mlbb-3.jpg" />
  </a>
  <figcaption>Home screen (May 2023)</figcaption>
</figure>
<p>MLBB is <a href="https://escharts.com/news/most-watched-esports-mobile-games-2022">popular</a> in South East Asia and is <a href="https://en.wikipedia.org/wiki/Esports_at_the_SEA_Games">an official sport in the SEA games</a> since 2019. It <a href="https://sensortower.com/blog/top-grossing-mobile-games-in-southeast-asia-for-september-2022">grossed $9bn</a> in 2022 (&ast;cough&ast; <a href="https://en.wikipedia.org/wiki/Gacha_game">gacha</a> &ast;cough&ast;). There's no concrete data on how it dominated the region, but the simplified mechanics and social nature are probably the main factors… or perhaps of the <a href="https://www.polygon.com/23064347/riot-games-league-of-legends-knockoffs-mobile-legends-bang-bang">very familiar look</a>.</p>
<p>The graphics were optimized for smartphones. The skill mechanics like last hit gold, denying, and creep blocking were not added. You can buy items anywhere from the map. Item and emblem building is easy to understand. Overall, it's a fast-paced game and you can enjoy a competitive scene without investing too much time learning it.</p>
<figure>
  <a href="/media/mlbb-5.jpg" target="_blank">
    <img src="/media/mlbb-5.jpg" />
  </a>
  <figcaption>MVP = highest KDA</figcaption>
</figure>
<p>Like any online games, it can be <a href="https://www.reddit.com/r/gamedesign/comments/9n2opy/will_online_competitive_games_always_be_toxic/">toxic</a>. Playing as a hero with unique abilities and roles, the primary objective of MOBA games is to destroy the enemy base and defend yours, which requires strategy and team work. You'll mostly play in matchmade sessions, so losing because of trolls and stupid teammates can happen. Losing means time or points (Ranked) wasted, and this usually induces toxic actions. I'm not immune to this problem.</p>
<figure>
  <a href="/media/mlbb-2.jpg" target="_blank">
    <img src="/media/mlbb-2.jpg" />
  </a>
  <figcaption>A match with friends</figcaption>
</figure>
<p>It's more fun with friends. My team at a previous work held friendly tournaments. We formed two teams of random members (most were beginners), in which me and the other skilled player can't be together. My team won the first cup and lost the second. Eventually, some members left the company that made a third tournament impossible.</p>
<figure>
  <a href="/media/mlbb-1.jpg" target="_blank">
    <img src="/media/mlbb-1.jpg" />
  </a>
  <figcaption>My Ruby 23rd in CA rank - 2023/05/20</figcaption>
</figure>
<p>I probably have stopped playing this game if not for my favorite hero, <a href="https://mobile-legends.fandom.com/wiki/Ruby">Ruby</a>. I was a <a href="https://mobile-legends.fandom.com/wiki/Kagura">Kagura</a> main before Ruby came out in 2017. Kagura is a mage and her skill set was very different at that time. Mages are typically squishy and important in damage dealing, thus requiring more timing and coordination skills.</p>
<figure>
  <a href="/media/mlbb-7.jpg" target="_blank">
    <img src="/media/mlbb-7.jpg" />
  </a>
  <figcaption>Kagura in the 2016 version of the game</figcaption>
</figure>
<p>When I realized mage isn't for me, I tried other heroes and found out that Ruby perfectly matches my playstyle.</p>
<figure>
  <a href="/media/mlbb-6.jpg" target="_blank">
    <img src="/media/mlbb-6.jpg" />
  </a>
  <figcaption>My highest all-time rank</figcaption>
</figure>
<p>I've chosen Ruby in more than 3,400 matches with a 61% win rate and made it on the leaderboards several times. Overall, I've played 3,611 matches (1.5 matches/day).</p>
<figure>
  <a href="/media/mlbb-4.jpg" target="_blank">
    <img src="/media/mlbb-4.jpg" />
  </a>
  <figcaption>3,454 Matches with Ruby with 61% Win Rate</figcaption>
</figure>
<p>Ruby closely resembles <a href="https://en.wikipedia.org/wiki/Little_Red_Riding_Hood">the Little Red Riding Hood</a> and <a href="https://rwby.fandom.com/wiki/Ruby_Rose">Ruby Rose</a> of RWBY. She is a melee fighter with all crowd control <a href="https://www.esports.net/wiki/guides/aoe-meaning/">AoE</a> skills, strong sustain and dash abilities with an overall balanced damage output. A viable choice if protecting or setting for the team is your priority.</p>
<figure>
  <a href="/media/mlbb-8.jpg" target="_blank">
    <img src="/media/mlbb-8.jpg" />
  </a>
  <figcaption>No deaths in a single match</figcaption>
</figure>
<p>The best items for Ruby are those with <a href="https://mobile-legends.fandom.com/wiki/Cooldown_reduction">cooldown reduction</a> and <a href="https://mobile-legends.fandom.com/wiki/Spell_vamp">spell vamp</a> effects. The technique is to make best use of her lifesteal abilities by casting skills that will hit the most units. Her passive also grants additional physical and magic defense (up to 3 stacks) upon dashing.</p>
<figure>
  <a href="/media/mlbb-9.gif" target="_blank">
    <img style="width:100%" src="/media/mlbb-9.gif" />
  </a>
  <figcaption>Clumping together against Ruby is a bad idea</figcaption>
</figure>
<p>Some game modes like Ranked are <a href="https://dotesports.com/league-of-legends/news/what-is-draft-pick-in-league-of-legends">draft pick</a>. This means your hero can be picked or banned by your opponents. It's important that you can play other heroes or roles for a good game and to protect your rank points.</p>
<figure>
  <a href="/media/mlbb-10.gif" target="_blank">
    <img style="width:100%" src="/media/mlbb-10.gif" />
  </a>
  <figcaption>Maniac (quadra) kill with Beatrix</figcaption>
</figure>
<p>Mobile Legends is a fun game to kill time. If you're into MOBA games, I recommend trying it out! However, don't expect many good players outside SEA. It may not be available in some countries either, like <a href="https://pib.gov.in/PressReleseDetailm.aspx?PRID=1635206">India that have banned</a> the game because it's <a href="https://en.wikipedia.org/wiki/Moonton">Chinese</a>.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Adding an RSS Feed to your Nuxt 3 Site]]></title>
            <description><![CDATA[How to add an RSS feed to a Nuxt 3 + Nuxt Content Site.]]></description>
            <link>https://jhnsprtu.com/blog/rss-feed-nuxt-markdown</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/rss-feed-nuxt-markdown</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Thu, 18 May 2023 23:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>I recently added an RSS feed to my site so visitors can subscribe to my latest posts using their preferred RSS readers. Prolific bloggers use it; people won't always have the time visit your site; and we usually read from multiple sources.</p>
<p>An RSS feed is normally included with publishing platforms like <a href="https://wordpress.com/support/feeds/">WordPress</a>. With Nuxt 3, adding one isn't straightforward, so I wrote this guide to help others set up theirs.</p>
<p>This only covers <a href="https://nuxt.com/docs/getting-started/deployment#static-hosting">prerendered static generated sites</a> and markdown posts managed by <a href="https://content.nuxtjs.org/">Nuxt Content</a>. However, I believe it's still a good starting point even with server-side rendering or other content backends.</p>
<h2 id="addaserverroute">Add a server route</h2>
<p>Create an endpoint for the feed - let's define it as <code>/rss.xml</code>. The endpoint must return an XML response.</p>
<p>Add the file <code>server/route/rss.xml.js</code> with the following codes:</p>
<pre><code class="js language-js">export default defineEventHandler(async (event) =&gt; {
  event.res.setHeader('content-type', 'text/xml')
})
</code></pre>
<p>The route must be prerendered. On the <code>nuxt.config.js</code> file, add:</p>
<pre><code class="js language-js">export default defineNuxtConfig({
  nitro: {
    prerender: {
      routes: [ '/rss.xml' ]
    }
  }
})
</code></pre>
<p>Read more about server routes <a href="https://masteringnuxt.com/blog/server-routes-in-nuxt-3">here</a>.</p>
<h2 id="outputthebaserssxmldata">Output the base RSS XML data</h2>
<p>Add the RSS library using <code>npm i rss</code>, then update the <code>server/route/rss.xml.js</code> file to:</p>
<pre><code class="js language-js">import RSS from 'rss'

const SITE_URL = 'your-site-url'

export default defineEventHandler(async (event) =&gt; {
  const feed = new RSS({
    title: 'My Site',
    site_url: SITE_URL,
    feed_url: SITE_URL + '/rss.xml',
  })

  event.res.setHeader('content-type', 'text/xml')
  event.res.end(feed.xml({ indent: true }))
})
</code></pre>
<p>The endpoint should respond with data similar to:</p>
<pre><code class="xml language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;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"&gt;
  &lt;channel&gt;
    &lt;title&gt;&lt;![CDATA[Title]]&gt;&lt;/title&gt;
    &lt;description&gt;&lt;![CDATA[Description]]&gt;&lt;/description&gt;
    &lt;link&gt;http://localhost:3000&lt;/link&gt;
    &lt;generator&gt;RSS for Node&lt;/generator&gt;
    &lt;lastBuildDate&gt;{{ current date }}&lt;/lastBuildDate&gt;
    &lt;atom:link href="http://localhost:3000/rss.xml" rel="self" type="application/rss+xml"/&gt;
  &lt;/channel&gt;
&lt;/rss&gt;
</code></pre>
<h2 id="retrieveandlistblogfiles">Retrieve and list blog files</h2>
<p>Let's say you have your blog posts on Markdown files under the <code>content/blog</code> directory.</p>
<p>Update the <code>server/route/rss.xml.js</code> file to:</p>
<pre><code class="js language-js">import RSS from 'rss'
import { serverQueryContent } from '#content/server'

const SITE_URL = 'your-site-url'

export default defineEventHandler(async (event) =&gt; {
  const feed = new RSS({
    title: 'My Site',
    site_url: SITE_URL,
    feed_url: SITE_URL + '/rss.xml',
  })

  const docs = await serverQueryContent(event)
    .sort({ createdAt: -1 })
    .find()
  const blogPosts = docs.filter((doc) =&gt; doc?._path?.includes('/blog'))
    // .slice(0, 10) // limit the output to 10 posts only

  for (const doc of blogPosts) {
    feed.item({
      title: doc.title ?? '-',
      url: `${SITE_URL}${doc._path}`,
      date: doc.createdAt, // front matter date &lt;- adjust
      description: doc.description, // front matter data &lt;- adjust
    })
  }

  event.res.setHeader('content-type', 'text/xml')
  event.res.end(feed.xml({ indent: true }))
})
</code></pre>
<p>Change the <code>sort</code> condition to the front matter field that you want to sort by. In this case, the posts all have a <code>createdAt</code> date fields. This sorts the posts in reverse chronological order.</p>
<p>Each post also has a <code>description</code> front matter field, which contains the description/summary of the article. This should also be changed depending on your setup.</p>
<p>The XML response should be like:</p>
<pre><code class="xml language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;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"&gt;
  &lt;channel&gt;
    &lt;title&gt;&lt;![CDATA[Title]]&gt;&lt;/title&gt;
    &lt;description&gt;&lt;![CDATA[Description]]&gt;&lt;/description&gt;
    &lt;link&gt;http://localhost:3000&lt;/link&gt;
    &lt;generator&gt;RSS for Node&lt;/generator&gt;
    &lt;lastBuildDate&gt;{{ current date }}&lt;/lastBuildDate&gt;
    &lt;atom:link href="http://localhost:3000/rss.xml" rel="self" type="application/rss+xml"/&gt;
    &lt;item&gt;
      &lt;title&gt;&lt;![CDATA[Title]]&gt;&lt;/title&gt;
      &lt;description&gt;&lt;![CDATA[Description]]&gt;&lt;/description&gt;
      &lt;link&gt;http://localhost:3000/blog/article&lt;/link&gt;
      &lt;guid isPermaLink="true"&gt;http://localhost:3000/blog/article&lt;/guid&gt;
      &lt;pubDate&gt;{{ created date }}&lt;/pubDate&gt;
    &lt;/item&gt;
    ...
  &lt;/channel&gt;
&lt;/rss&gt;
</code></pre>
<p>At this point, you now have a working RSS feed. You can commit and deploy the changes.</p>
<figure>
  <a href="/media/rss-feed-nuxt3-1.png" target="_blank">
    <img src="/media/rss-feed-nuxt3-1.png" />
  </a>
</figure>
<h2 id="optionalincludethemarkdowncontent">Optional: Include the markdown content</h2>
<p>Showing only the summary of posts on your feed is probably best for sites that need inbound traffic. Otherwise, including the whole article would be convenient for your readers.</p>
<p>RSS supports <a href="https://www.rssboard.org/rss-profile#namespace-elements-content-encoded">HTML elements</a> inside the <code>content:encoded</code> tag. While Nuxt Content can transform markdown into HTML, you can only do that with the <code>ContentRenderer</code> component on a view template.</p>
<p>To convert markdown files into HTML from the server route codes, we'll use <a href="https://github.com/showdownjs/showdown">Showdown</a>.</p>
<p>Install it with <code>npm i showdown</code>, then import the following:</p>
<pre><code class="js language-js">import showdown from 'showdown'
import { join } from 'path'
import { readFile } from 'fs/promises'
</code></pre>
<p>Create a <code>Showdown Converter</code> instance inside the handler:</p>
<pre><code class="js language-js">const converter = new showdown.Converter()
</code></pre>
<p>Inside the blog post loop, add:</p>
<pre><code class="js language-js">for (const doc of blogPosts) {
  const filename = join(process.cwd(), 'content', doc._file)
  const html = converter.makeHtml(await readFile(filename, 'utf8'))
</code></pre>
<p>Each post object contains the file name (<code>_file</code>) relative to the <code>content/</code> directory. The snippet above builds the absolute file name, reads the file, then generates the HTML string using the converter instance.</p>
<p>Static site markdowns normally have a <a href="https://jekyllrb.com/docs/front-matter/">front matter</a> that should be removed:</p>
<pre><code class="js language-js">const filename = join(process.cwd(), 'content', doc._file)
const markdownText = await readFile(filename, 'utf8')

let contentWithoutFrontmatter = markdownText

const frontmatterEndIndex = markdownText.indexOf('---', 3)
if (frontmatterEndIndex !== -1) {
  contentWithoutFrontmatter = markdownText.slice(frontmatterEndIndex + 3).trim()
}

const html = converter.makeHtml(contentWithoutFrontmatter)
</code></pre>
<p>Then in the feed <code>item</code> method, add the HTML content:</p>
<pre><code class="js language-js">feed.item({
  title: doc.title ?? '-',
  url: `${SITE_URL}${doc._path}`,
  date: doc.createdAt,
  description: doc.description,
  custom_elements: [
    { 'content:encoded': { _cdata: html } }
  ]
})
</code></pre>
<p>That's it! Build your site and load the RSS feed on a reader app.</p>
<figure>
  <a href="/media/rss-feed-nuxt3-2.png" target="_blank">
    <img src="/media/rss-feed-nuxt3-2.png" />
  </a>
</figure>
<h2 id="rssautodiscovery">RSS Autodiscovery</h2>
<p>Your visitors will need to know the exact URL of your feed to subscribe, but adding this tag will enable readers to automatically detect the feed:</p>
<pre><code class="html language-html">&lt;link rel="alternate" type="application/rss+xml" title="My Site" href="/rss.xml"&gt;
</code></pre>
<p>In <a href="https://nuxt.com/docs/getting-started/seo-meta#types">Nuxt 3</a>, define this under the <code>app.head.link</code> of your <code>nuxt.config.js</code>:</p>
<pre><code class="js language-js">app: {
  head: {
    link: [
      {
        rel: 'alternate',
        type: 'application/rss+xml',
        title: 'My Site',
        href: '/rss.xml'
      }
    ]
  }
}
</code></pre>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[RSS Feed]]></title>
            <description><![CDATA[Added an RSS Feed to my site.]]></description>
            <link>https://jhnsprtu.com/blog/rss-feed</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/rss-feed</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Mon, 15 May 2023 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>I never used RSS readers as I don't follow many blogs. I'm more active on social media, where you can always <em>subscribe</em> or <em>follow</em> other users from your account.</p>
<p>For those who aren't familiar, <a href="https://en.wikipedia.org/wiki/RSS">RSS</a> is a web feed in a standardized (XML) format. You'll find tons of pages on the web explaining what it is and how it works, so I'm not going to explain it here. Basically, it's a file that contains a list of articles/posts on a website that you can add to <a href="https://www.wired.com/story/best-rss-feed-readers/">any RSS reader application</a>.</p>
<p>My site now has an RSS feed! I had to code the function since it doesn't come out of the box with Nuxt, unlike with CMS such as WordPress. Feel free to subscribe using your favorite reader.</p>
<p>Now that I think of it, I probably should start using RSS Readers. <a href="https://netnewswire.com/">NetNewsWire</a> seems to be a good app.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Film Photography]]></title>
            <description><![CDATA[How I started doing film photography in 2022.]]></description>
            <link>https://jhnsprtu.com/blog/film-photography</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/film-photography</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Sat, 13 May 2023 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>I started dabbling in film photography around November 2022.</p>
<p>My parents used to have a point-and-shoot film camera for family pictures, so film is not new to me. I can remember inspecting our camera and what it is (Kodak Star), but never learned how to use it.</p>
<p>They stopped taking family pictures when my dad got really upset because the lab ruined our last film and lost all the pictures. They never used a camera since then.</p>
<p>I took my first pictures with the camera on my <a href="https://en.wikipedia.org/wiki/Nokia_3200">Nokia 3200</a> (or perhaps with a webcam). By that time, analog photography has declined, stores stopped selling analog cameras, and labs closed down.</p>
<h2 id="gettingafilmcamera">Getting a film camera</h2>
<p>In the digital camera and smartphone era, there are only a handful of companies that make film cameras, like <a href="https://leica-camera.com/en-US/photography/cameras/m/m6">Leica</a>, <a href="https://shop.lomography.com">Lomography</a>, and <a href="https://www.bhphotovideo.com/c/buy/Disposable-Single-Use-Cameras/ci/2171/N/4288586275">disposables</a> that you can find on some grocery and online stores.</p>
<p>Getting a used or disposable film camera is the easiest and cheapest way to get into film photography. I found a store in North Park, San Diego called <a href="http://www.cameraexposure.com/">Camera Exposure</a>, which has a great collection of used cameras. They also have a <a href="https://www.safelightlabs.com/">development lab</a>, so it's a one-stop shop. If you're a local, check them out!</p>
<figure>
  <a href="/media/film-photog1.jpg" target="_blank">
    <img src="/media/film-photog1.jpg" />
  </a>
  <figcaption>Medium format cameras on display</figcaption>
</figure>
<p>A recent resurgence of film photography pushed up the prices of used film cameras and films. I bought a <a href="https://global.canon/en/c-museum/product/film100.html">Canon A-1</a> ($350) for me and a Minolta X-370 ($180) for my sister, both with 50mm (a.k.a. nifty fifty) lens.</p>
<p>I could've find cheaper ones if I looked harder, but it's good to support small local businesses.</p>
<figure>
  <a href="/media/film-photog2.jpg" target="_blank">
    <img src="/media/film-photog2.jpg" />
  </a>
</figure>
<h2 id="canona1">Canon A-1</h2>
<p>My Canon A-1 is a 40-year-old 35mm black camera that's still in excellent condition and I really love it. It's a bit heavy but feels sturdy. The grip makes it ergonomic to use.</p>
<p>While focusing the lens and advancing/rewinding the film are manual operations, it's an electronic camera with all-digital control. The shutter priority (Tv) and aperture priority (Av) modes makes it really easy to create well-exposed images.</p>
<p>It only needs one 4LR44 battery to operate, which can last for quite some time depending on how frequent you take pictures.</p>
<figure>
  <a href="/media/film-photog8.jpg" target="_blank">
    <img src="/media/film-photog8.jpg" />
  </a>
  <figcaption>My Canon A-1 and my sister's AE-1</figcaption>
</figure>
<p>It is equipped with a Canon FD 50mm 1.8 lens. The <a href="https://en.wikipedia.org/wiki/Canon_FD_lens_mount">FD lens</a> works with the auto-exposure (AE) function of the camera.</p>
<h2 id="costsanddevelopment">Costs and development</h2>
<p>Films nowadays cost $10 or more (see <a href="/media/film-photog12.jpg" target="_blank">prices back in 2005</a>). Color films are more expensive. A roll of Kodak Portra 400 is around $18. I usually buy a pack of 5 from <a href="https://www.bhphotovideo.com/c/product/742308-USA/Kodak_6031678_35mm_Professional_Portra_400.html">B&H</a> that costs $75.</p>
<p>I go to Camera Exposure to have my films developed. The regular 35mm color films are developed through a process called <a href="https://en.wikipedia.org/wiki/C-41_process">C-41</a>. Most film labs can process them.</p>
<p>For developing a single roll, I spend around $8 for the development and about $10 for the scanning (6MP). I live about 11 miles away from the lab, so that's roughly $3/trip on gas. I get the photos after 3-5 busines days.</p>
<p>I also tried Atlanta Film Co. 250D films, which are rebranded motion picture films with the remjet. It requires the <a href="https://en.wikipedia.org/wiki/Eastman_Color_Negative">ECN-2 process</a> that's not available on my local lab. The development costed me $19/roll excluding shipping fees. I got the photos after 10 business days.</p>
<h2 id="thephotos">The photos</h2>
<p>Here are some of the photos I took with my Canon A-1.</p>
<figure>
  <a href="/media/film-photog3.jpg" target="_blank">
    <img src="/media/film-photog3.jpg" />
  </a>
</figure>
<figure>
  <a href="/media/film-photog4.jpg" target="_blank">
    <img src="/media/film-photog4.jpg" />
  </a>
</figure>
<figure>
  <a href="/media/film-photog5.jpg" target="_blank">
    <img src="/media/film-photog5.jpg" />
  </a>
</figure>
<figure>
  <a href="/media/film-photog6.jpg" target="_blank">
    <img src="/media/film-photog6.jpg" />
  </a>
</figure>
<figure>
  <a href="/media/film-photog7.jpg" target="_blank">
    <img src="/media/film-photog7.jpg" />
  </a>
</figure>
<figure>
  <a href="/media/film-photog9.jpg" target="_blank">
    <img src="/media/film-photog9.jpg" />
  </a>
</figure>
<figure>
  <a href="/media/film-photog10.jpg" target="_blank">
    <img src="/media/film-photog10.jpg" />
  </a>
</figure>
<figure>
  <a href="/media/film-photog11.jpg" target="_blank">
    <img src="/media/film-photog11.jpg" />
  </a>
</figure>
<p>These are unedited shots. The color effects (a e s t h e t i c s) varies from film to film. So far, I've used Kodak Portra 400, Atlanta Film Co. 250D, and CineStill 800T.</p>
<figure>
  <a href="/media/film-photog13.jpg" target="_blank">
    <img src="/media/film-photog13.jpg" />
  </a>
</figure>
<p>With a film camera, light leakage or mistakes like accidentally opening the camera with the film not fully rewound can ruin your photos.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Other than the experience, there are no benefits in using film over digital. I just find my Canon A-1 really fun and simple to use and it matters to me.</p>
<p>When I was buying my camera from the store, there was a guy there who bought an Olympus XA for his girlfriend and said "I never regretted buying film cameras." The same goes for me: I never regretted buying my Canon A-1.</p>
<figure>
  <a href="/media/film-photog16.jpg" target="_blank">
    <img src="/media/film-photog16.jpg" />
  </a>
  <figcaption>Shot with Canon AE-1 on expired 35mm film</figcaption>
</figure>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Website Redesign 2023]]></title>
            <description><![CDATA[Website 2023 redesign!]]></description>
            <link>https://jhnsprtu.com/blog/website-redesign-2023</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/website-redesign-2023</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Wed, 22 Mar 2023 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>I rebuilt my website with a fresh new look (finally, a dark mode). Few months ago, I migrated it to plain HTML pages. I'm good with it, but I feel it's not giving off a good impression.</p>
<p>Anyways, site is all fancy again, inspired by the various websites that I found interesting. It is static generated just like the <a href="/blog/updated-my-website">previous iteration</a>, built with <a href="https://nuxt.com/">Nuxt</a>, <a href="https://tailwindcss.com">Tailwind</a>, and <a href="https://vuejs.org/">Vue</a> version <em>tres</em>, then deployed to <a href="https://www.netlify.com/">Netlify</a>.</p>
<figure>
  <a href="/media/newsite2023-1.png" target="_blank">
    <img src="/media/newsite2023-1.png" />
  </a>
  <figcaption>Dark mode</figcaption>
</figure>
<figure>
  <a href="/media/newsite2023-2.png" target="_blank">
    <img src="/media/newsite2023-2.png" />
  </a>
  <figcaption>Light mode</figcaption>
</figure>
<h2 id="domain">Domain</h2>
<p>Got a couple of domains for myself lately. I had <code>johnespiritu.com</code> few years ago, but someone got it after I didn't renew. Then I bought <code>johnespiritu.dev</code> for this website, but not everything I post is tech related. So, I got <code>johnespiritu.info</code> and <code>jhnsprtu.com</code> because I still can't reclaim the first domain. I'll be using <code>jhnsprtu.com</code> for now and have the other ones redirect.</p>
<p>I recommend <a href="https://www.hover.com/">Hover</a> if you want to get a domain &mdash; it is really simple to use and WHOIS privacy is included.</p>
<h2 id="development">Development</h2>
<p>Remaking my site was fun. I learned new things in Vue 3 and the <a href="https://vuejs.org/guide/extras/composition-api-faq.html">Composition API</a>, which I think is nicer than the original Options API. Vue also made <a href="https://vuejs.org/guide/built-ins/transition.html#the-transition-component">animating</a> easy, so I added a few page and element transitions to spice things up.</p>
<p>It's easy to build Vue websites with Nuxt. The third major version was released a <a href="https://nuxt.com/blog/v3">few months ago</a> and it runs on top of Vue 3. I find the <a href="https://nuxt.com/docs">documentation</a> lacking and a bit confusing, so I had to do lots of web searches to resolve the issues I had.</p>
<p>For the design, I used <a href="https://tailwindcss.com/">Tailwind CSS</a>. It has become my go to CSS framework as it has sensible constraints that make it easy to create well-designed and responsive components. Plus, it is <a href="https://tailwindcss.com/docs/optimizing-for-production">tiny</a> and works flawlessly with <a href="https://tailwindcss.nuxtjs.org/">Nuxt</a>.</p>
<p>I've decided to try out Netlify for this project and it's amazing how simple the deployment was. The <a href="https://www.netlify.com/pricing/">Starter tier</a> seems good enough, so I'll switch over to it and stop my current VPS subscriptions.</p>
<h2 id="wrapup">Wrap Up</h2>
<p>I plan to write more this year and put up contents that could help me out on my career. I've neglected my website since <a href="/blog/moved-to-the-us">moving to the States</a> and have been quite busy sorting out my life and career.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mac OS X User Interface]]></title>
            <description><![CDATA[Revisiting the Mac OS X Aqua Interface.]]></description>
            <link>https://jhnsprtu.com/blog/osx-ui</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/osx-ui</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Mon, 03 Oct 2022 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>Apple arguably creates the finest and innovative GUI in the industry. My favorite is the Aqua Interface from OS X 10.5 (Leopard) to OS X 10.9 (Mavericks). OS X Leopard's pixel-perfect design enthralled me the first time I saw it on a <a href="https://en.wikipedia.org/wiki/MacFormat">Mac Format</a> magazine 2007 issue.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Aqua_%28user_interface%29">Aqua interface</a> first appeared on OS X, and has changed frequently over the years. The design from the first version of OS X to 10.9 (Mavericks) is mainly skeuomorphic.</p>
<figure>
  <a href="/media/osx-ui1.png" target="_blank">
    <img src="/media/osx-ui1.png" alt="OS X Finder" />
  </a>
  <figcaption>Finder in CoverFlow View</figcaption>
</figure>
<p><a href="https://en.wikipedia.org/wiki/Skeuomorph">Skeuomorphism</a> imitates aesthetics of physical objects. Researchers state that newer technologies that resemble their predecessors give people comfort and ease of learning during the transition.</p>
<figure>
  <a href="/media/osx-ui3.png" target="_blank">
    <img src="/media/osx-ui3.png" alt="OS X Calendar App" />
  </a>
  <figcaption>Calendar app sporting a leather texture and torn pages</figcaption>
</figure>
<p>Opponents state that skeuomorphic UIs take up more space, cause inconsistent look and feel between applications, and increase cognitive load with unnecessary visual noise. It can also limit creativity by grounding the user experience to physical counterparts and are often wrongly imitated (e.g. analog gauges on digital interfaces.)</p>
<figure>
  <a href="/media/osx-ui2.png" target="_blank">
    <img src="/media/osx-ui2.png" alt="OS X Aperture 2" />
  </a>
  <figcaption>Aperture 2, Photos' predecessor</figcaption>
</figure>
<p>Interestingly, internal politics in Apple influenced its software design. <a href="https://en.wikipedia.org/wiki/Scott_Forstall">Scott Forstall</a> was the proponent of the skeuomorphic design, which was also favored by Steve Jobs. When Jobs died, Forstall lost foothold in Apple and <a href="https://www.nytimes.com/2012/11/01/technology/apple-shake-up-could-mean-end-to-real-world-images-in-software.html">resigned</a>. <a href="https://en.wikipedia.org/wiki/Jony_Ive">Jony Ive</a> took over the Human Interface team, shifting iOS and OS X from skeuomorphic to flat design.</p>
<figure>
  <a href="/media/osx-ui4.png" target="_blank">
    <img src="/media/osx-ui4.png" alt="Photo Booth App" />
  </a>
  <figcaption>Photo Booth app on full screen mode</figcaption>
</figure>
<p>Apple causes conniptions among designers when they use outdated visual metaphors, like the Photo Booth App in OS X 10.8 and Podcasts App in iOS 6.</p>
<figure>
  <a href="/media/osx-ui5.png" target="_blank">
    <img src="/media/osx-ui5.png" alt="Reminders App" />
  </a>
  <figcaption>Reminders App with notebook aesthetics</figcaption>
</figure>
<p>I believe that skeuomorphic design is better when done appropriately. Imitating physical objects should be avoided, but applying a subtle skeuomorphism to certain UI and visual elements, such as buttons and textbox, would help them stand apart from the contents.</p>
<figure>
  <a href="/media/osx-ui6.png" target="_blank">
    <img src="/media/osx-ui6.png" alt="Game Center" />
  </a>
  <figcaption>Game Center UI with casino metaphors</figcaption>
</figure>
<p>To me, the OS X 10.5 to 10.9 Aqua UI still has the most comfortable and pleasing aesthetics among Mac OS.</p>
<figure>
  <a href="/media/osx-ui7.png" target="_blank">
    <img src="/media/osx-ui7.png" alt="Audio Pref Dialog" />
  </a>
  <figcaption>Audio Devices dialog box</figcaption>
</figure>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fujifilm X100T RAF Conversion on OS X 10.8]]></title>
            <description><![CDATA[How to open Fujifilm X100T RAF (RAW) files on OS X 10.8 Mountain Lion.]]></description>
            <link>https://jhnsprtu.com/blog/fuji-raw-conversion-osx-10-8</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/fuji-raw-conversion-osx-10-8</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Sun, 02 Oct 2022 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>This article may help someone trying to work with newer camera using legacy computers. I was looking for a way to edit my Fujifilm X100T raw images on my Mac Mini 2012 running OS X 10.8 (Mountain Lion).</p>
<h2 id="whatisrawimage">What is RAW image?</h2>
<p><a href="https://en.wikipedia.org/wiki/Raw_image_format">RAW image</a> contains unprocessed data from the image sensor of a digital camera or scanner. This format is 2-6x larger than JPEG files, having 12-14 bits per channel. This allows a wider range of adjustments without losing much information (e.g. noise).</p>
<p>The problem with this format is <em>there are no standards</em>. Manufacturers would often change the format from one camera model to the next, and some encrypt portions of it to prevent third-party access.</p>
<p>There's an ISO standard for raw image format called <a href="https://en.wikipedia.org/wiki/TIFF/EP">TIFF/EP</a>. However, most camera don't use this. Adobe created a raw file format called <a href="https://en.wikipedia.org/wiki/Digital_Negative">DNG</a>, which is based on TIFF/EP. Apple <a href="https://support.apple.com/en-ca/HT211965">ProRAW</a> uses DNG. Some smartphones use DNG like Nokia Lumia, Samsung Galaxy, and Huawei. Niche and low market share cameras use DNG to leverage software support.</p>
<p>Apps in OS X 10.8 like Aperture 2, Lightroom 3, and Preview support DNG and TIFF formats. Thus, we should convert Fuji RAW (RAF) files to either of these.</p>
<h2 id="librawdcraw">LibRaw/dcraw</h2>
<p><a href="https://www.libraw.org/docs">LibRaw</a> is a util for reading RAW files that includes parts of <a href="https://www.dechifro.org/dcraw/">dcraw</a>, used by open-source applications like <a href="https://www.irfanview.com/">InfranView</a> and <a href="https://www.darktable.org/">DarkTable</a>. Since most camera RAW formats are proprietary, the authors developed the decoding functions through reverse engineering.</p>
<h3 id="supportedcameras">Supported Cameras</h3>
<ul>
<li><a href="https://www.libraw.org/supported-cameras">List of supported cameras</a></li>
</ul>
<h3 id="installing">Installing</h3>
<ul>
<li><a href="https://www.libraw.org/download">Download</a> the binaries found on the official site.</li>
<li>Through a package manager like <a href="https://brew.sh/">Homebrew</a> or <a href="https://www.macports.org/install.php">Mac Ports</a>.</li>
</ul>
<h3 id="macports">Mac Ports</h3>
<p>Run on terminal: <code>sudo port install libraw</code></p>
<h2 id="convertingtotiff">Converting to TIFF</h2>
<p>Once LibRaw is installed, use the dcraw emulation utility included. Read the instructions on <a href="https://www.libraw.org/docs/Samples-LibRaw.html">this page</a>.</p>
<p>If you use Mac Ports (or homebrew), the commands listed on the page should be on your <code>PATH</code> and ready to be used.</p>
<p>Run the dcraw emulation command:</p>
<pre><code class="bash language-bash"># dcraw_emu [OPTION]... [FILE]...
dcraw_emu -T DSCXXXX1.RAF DSCXXXX2.RAF ...
</code></pre>
<p>Notes:</p>
<ul>
<li>The <code>-T</code> option uses TIFF format instead of PPM.</li>
<li>You can convert multiple files, separated by a space.</li>
<li>The conversion may take a few seconds, depending on the specs of your system.</li>
</ul>
<p>The converted image should appear on your working directory.</p>
<p><a href="/media/raw-conv2.png" target="_blank">
  <img src="/media/raw-conv2.png" />
</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mac Mini 2012 + OS X 10.8]]></title>
            <description><![CDATA[Retro computing with Mac Mini 2012 and OS X 10.8 Mountain Lion.]]></description>
            <link>https://jhnsprtu.com/blog/mac-mini-2012</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/mac-mini-2012</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Sat, 01 Oct 2022 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>Got a used <a href="https://support.apple.com/kb/sp659">Mac Mini 2012</a> from <a href="https://eshop.macsales.com/">OWC</a> on 09/19/22 for my retro computing. I was thinking of getting a Black MacBook 2009, but realized that <a href="https://discussions.apple.com/thread/253088904">chipping</a>, battery, and keyboard issues will be a headache. Old MacBooks are still pricey. </p>
<p><a href="/media/mmini1.jpg" target="_blank">
  <img src="/media/mmini1.jpg" />
</a></p>
<p>OWC is a good store. They sell parts like battery, RAM, and storage for Apple devices (up to 2006 models). I bought a battery from them back in 2017 for a MacBook Pro 2011 slowed down to a crawl by its swollen battery. Highly recommended!</p>
<p>Customization was available for this model. Got it with these specs for $313.74: </p>
<ul>
<li><strong>CPU</strong>: Intel i7-3615QM (2.3 GHz Quad Core)</li>
<li><strong>RAM</strong>: 16 GB DDR3 (1600 MHz)</li>
<li><strong>HDD</strong>: 500GB SSD</li>
<li><strong>OS</strong>: macOS 10.15 (Catalina)</li>
</ul>
<p><a href="/media/mmini6.png" target="_blank">
  <img class="no-rounded" src="/media/mmini6.png" />
</a></p>
<p><a href="/media/mmini4.jpg" target="_blank">
  <img src="/media/mmini4.jpg" />
</a></p>
<p>I wanted to use an older OS X somewhere between 10.6 (Snow Leopard) and 10.8 (Mountain Lion). The 2012 model can run OS X 10.8 up to 10.15 (Catalina). My unit came with 10.15, so I downgraded it to 10.8.5. Macs can only run the versions that originally came with it and the later ones that still support it.</p>
<p>I loved the Aqua and skeuomorph interfaces on OS X 10.5 and 10.8. I even went as far as skinning my WinXP box to look like OS X Leopard.</p>
<p><a href="/media/mmini3.jpg" target="_blank">
  <img src="/media/mmini3.jpg" />
</a></p>
<h2 id="setup">Setup</h2>
<p>I prepared a bootable copy of OS X 10.8 using my MacBook Pro. For older OS X, you make the bootable by <a href="https://www.lifewire.com/create-bootable-copies-os-x-mountain-lion-installer-2260352">restoring the InstallESD.dmg image</a> found inside Install OS X Mountain Lion.app (apps are actually directories).</p>
<p>The installer will error if downgrading from a later OS, so I wiped out the drive first. After the installation, I created my account and set up the network connection.</p>
<p>The setup was pretty much the same as the current versions.</p>
<h2 id="software">Software</h2>
<p>I searched online for Mac apps compatible with 10.8. Some vendors keep an archive of their older software, many don't. I discovered <a href="https://www.macintoshrepository.org/">Macintosh Repository</a> and got several good old software (donate to this community, a rare gem nowadays!)</p>
<p>Got the following apps installed:</p>
<ul>
<li><a href="https://ftp.mozilla.org/pub/firefox/releases">Firefox 45.9 ESR</a> - main browser<ul>
<li><a href="https://github.com/gorhill/uBlock-for-firefox-legacy/releases">uBlock Origin for Legacy Firefox 1.16.4.30</a> - death to ads!</li></ul></li>
<li><a href="https://developer.apple.com/download/more">Xcode 5.1.1 + Command Line Tools</a> - Apple dev utils</li>
<li><a href="https://www.macports.org/install.php">Mac Ports 2.7.2</a> - package manager</li>
<li><a href="https://www.videolan.org/vlc">VLC media player 10.0.17.3</a> - media player</li>
<li><a href="https://sourceforge.net/projects/veracrypt/files/">VeraCrypt 1.24</a> - encryption tool</li>
<li><a href="https://download.blender.org/release/Blender2.79/">Blender 2.79b</a> - 3D editor</li>
<li><a href="https://download.filezilla-project.org/client/">FileZilla 3.24.1</a> - FTP browser/util</li>
<li><a href="https://www.macintoshrepository.org/35062-pixelmator-2-0">Pixelmator 2.0</a> - raster editor</li>
<li><a href="https://www.macintoshrepository.org/18430-aperture-2">Aperture 2.1.2</a> - photo editor</li>
<li><a href="https://www.macintoshrepository.org/40764-adobe-lightroom-3">Adobe Lighroom 3.0</a> - photo Editor</li>
<li><a href="https://www.sublimetext.com/2">Sublime Text 2.0.2</a> - text Editor</li>
<li><a href="https://adoptium.net/temurin/archive/">Java 11.0.16.1 (OpenJDK Temurin LTS)</a> - Java Runtime and SDK<ul>
<li><a href="https://support.apple.com/kb/dl1572?locale=en_US">Java SE 6 for Legacy Software</a> (Adobe CS3 needs this)</li></ul></li>
<li><a href="https://iterm2.com/downloads.html">iTerm 2 Build 3.0.15</a> - better than the built-in terminal</li>
</ul>
<p>Utils and runtimes via Mac Ports:</p>
<ul>
<li>Vim 9.0 - main text editor</li>
<li>Python 3.10.7 - Python 3 runtime</li>
<li>OpenSSL 3.0.5 - updated Open SSL/TLS</li>
<li>Git 2.37.3 - source control</li>
<li>Node.js 12.22.12 - server-side js</li>
<li>Rsync 3.2.6 - remote deployment and file transfer</li>
<li>OpenSSH 9.0p1 - SSH/remote access</li>
<li>Ranger 1.9.3 - TUI file explorer</li>
<li>Neofetch 7.1.0 - system preview</li>
<li>Ack 3.6.0 - search util ala grep</li>
<li>yt-dlp 2022.09.01 - YouTube downloader</li>
<li>jEnv 0.5.5 - Java version manager</li>
<li>nvm 0.39.1 - Node version manager</li>
<li>wpm 1.51.5 - typing game/util</li>
</ul>
<h2 id="tlsissues">TLS Issues</h2>
<p>Many servers in 2022 reject TLS v1.0, which is used by the old OpenSSL libs included in OS X 10.8. Upgrading OpenSSL, Git, and OpenSSH using Mac Ports resolved TLS issues. </p>
<h2 id="letsencryptrootcaissues">Let's Encrypt Root CA Issues</h2>
<p>Many TLS websites weren't accessible due to the <a href="https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021">expired Root CA</a> on OS X 10.8.</p>
<p>I tried importing the root certificates from my MacBook Pro 2020. However, that didn't fix Safari 6.2. Firefox 45 also had the same problem, but was fixed after setting the ISRG Root X1 on its Preferences page.</p>
<h2 id="www">WWW</h2>
<p>Many websites are broken, usually due to reliance on modern JavaScript. Apps with web view contents, like iTunes Store, aren't working because the servers don't exist anymore or were moved.</p>
<p>Many sites load ads (cancer of the modern web) that can crash Firefox. Using an ad blocker will help stop those abomination from loading. I <a href="https://github.com/gorhill/uBlock/blob/master/dist/README.md#firefox-legacy">manually installed uBlock Origin</a> for legacy Firefox 1.16.</p>
<p><a href="/media/mmini7.png" target="_blank">
  <img src="/media/mmini7.png" />
</a></p>
<p><a href="/media/mmini8.png" target="_blank">
  <img src="/media/mmini8.png" />
</a></p>
<h2 id="pipbinaries">PIP Binaries</h2>
<p>Added Python binaries directory to PATH on <code>.zshrc</code>:</p>
<pre><code class="bash language-bash"># Python 3
export PATH="/Users/{username}/Library/Python/3.10/bin:$PATH"
</code></pre>
<h2 id="workingwithfujifilmx100traw">Working with Fujifilm X100T RAW</h2>
<p>The Fujifilm X100T was relased on 2014, about 2 years after OS X 10.8. This means the OS doesn't know the device.</p>
<p>The camera connected via USB isn't accessible on Finder, but can be seen by Lightroom, Aperture, and Preview. The apps throw an unsupported format error when opening the RAW images. However, they can import the files from the camera.</p>
<p><a href="/media/x100t-raw-1.png" target="_blank">
  <img src="/media/x100t-raw-1.png" />
</a></p>
<p>According to Apperture's <a href="https://support.apple.com/kb/SP772">support page</a>, OS X 10.10 and Photos can open X100T RAF images.</p>
<p>One trick is to convert these RAF files into some intermediate format, but without needing another computer to do it. I discovered <a href="https://www.libraw.org/supported-cameras">LibRaw</a> and <a href="https://www.dechifro.org/dcraw/">dcraw</a>. dcraw development has stalled, but parts of it are in LibRaw. LibRaw has <code>dcraw_emu</code> command that emulates dcraw.</p>
<p>The best output format using LibRaw is <a href="https://en.wikipedia.org/wiki/TIFF">TIFF</a>, which can be read by Aperture and Lightroom. The format is larger than the RAF file (around 10 MB). Not sure if there are other formats available, but this works for now.</p>
<p>I installed LibRaw via Mac Ports then ran the command on the terminal:</p>
<pre><code class="sh language-sh"># dcraw_emu [OPTION]... [FILE]...
dcraw_emu -T DSCXXXX1.RAF DSCXXXX2.RAF ...
</code></pre>
<p>The TIFF file should appear with the same filename (except extension) in the working directory.</p>
<p>The image below was converted from RAF to TIFF, post-processed in Lightroom 3, then exported as JPEG.</p>
<p><a href="/media/mmini2.jpg" target="_blank">
  <img src="/media/mmini2.jpg" />
</a></p>
<p>More on this topic: <a href="fuji-raw-conversion-osx-10-8">Fujifilm X100T RAF Conversion on OS X 10.8</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[United States]]></title>
            <description><![CDATA[An update on my life in the US.]]></description>
            <link>https://jhnsprtu.com/blog/united-states</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/united-states</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Mon, 04 Jul 2022 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>It's been seven month since I moved to the United States. It's one of the best decision I've ever made.</p>
<p>I grew up in the Philippines and have never been here. I acquired my citizenship through my dad, who was naturalized during his service at the Navy. I was a permanent resident on my home country as we never applied for dual citizenship.</p>
<p>Moving to a different country isn't easy. Thankfully, our cousins were willing to give us a helping hand. They leased us their condo unit in San Diego county for six months and assisted us in many important matters.</p>
<p>Within a week, I found a web developer job that pays well. Since you need a car to move around here, my cousins also taught me how to drive. Eventually, I got my driver's license (on the second try) and bought a used car.</p>
<p>Below is a tale of my experience so far:</p>
<h2 id="climate">Climate</h2>
<p>The climate in San Diego is more comfortable than in the Philippines. Most people I talked to find it perfect compared to other states, even Los Angeles and San Francisco.</p>
<p><a href="https://en.wikipedia.org/wiki/Climate_of_San_Diego">This</a> wiki page explains climate here in detail.</p>
<h2 id="expenses">Expenses</h2>
<p>The cost of living in California is high, making life more challenging if you earn only the minimum wage ($15/hr and varies by state).</p>
<p>As an IT professional, I make enough money to afford a comfortable life. 26% of my salary goes to taxes, Medicare, and Social Security; 3% to health insurance; 35% to rent and utilities; 6% to car loan; 3% to car insurance; and the remaining to food, savings, gas, and other personal expenses.</p>
<p>Medical care seems to be crazy expensive. I can't tell, however, as I haven't had the need to use them.</p>
<h2 id="creditscore">Credit Score</h2>
<p>Credit history is an essential part of living here and one of the things we first worked on. Lenders and landlords make use of your credit score to determine your eligibility for a loan or rental.</p>
<p>Having a credit card is the simplest way to get started. You need to have an income and a good credit record to be approved for a regular (unsecured) credit card. Since I didn't qualify, I applied for a secured credit card with a $500 deposit. It can be upgraded to a regular one after 6 months of good credit.</p>
<p>After three months of moving, I was able to get financing for my car. Due to my lack of credit history, most lenders rejected my loan application, and the one that accepted arranged with a relatively high APR.</p>
<p>We tried applying for a mortgage. Although I have a job and enough money for the minimum down payment, we were ultimately rejected. Apparently, at least two years of good credit and rental history are required.</p>
<p>Applying for a loan incurs a <em>hard inquiry</em> on your record. I tried many applications in a short time, so my credit score decreased by quite a significant amount.</p>
<h2 id="insurances">Insurances</h2>
<p>Insurance companies make a killing in this country. You can't drive without auto and driver insurance. My apartment unit requires renter's insurance. You'll get a tax penalty if you don't have health insurance in California.</p>
<h2 id="postalservices">Postal Services</h2>
<p>I'm amazed how the postal services are very much utilized here. Even in the age of emails and paperless transactions, I still receive plenty of mails and ads weekly.</p>
<p>The government offices use the postal service to send documents. I got my driver's license, vehicle registration papers, state IDs, and USCIS documents by mail, so I didn't need to go to their office unless required.</p>
<p>USPS provides standard mailboxes to residential and commercial buildings, which you can use to send and receive mails.</p>
<p>Unlike in the Philippines, most couriers here would leave packages on your doorstep if a signature isn't required, which is prone to package theft. I haven't lost a delivered package so far.</p>
<h2 id="technology">Technology</h2>
<p>You'll need a phone number and a smartphone for many things here. My iPhone 7 battery had gone bad, so I decided to get a new iPhone 13 with an unlimited data and phone line plan. The 5G network coverage in San Diego is good overall.</p>
<p>I use Apple Maps to find my way around. When driving, it shows you the traffic conditions and estimated arrival time to the destination. The geolocation here is accurate and up-to-date.</p>
<p>You can do many transactions electronically. I carry only a little cash as most shops, vending machines, and gas stations accept card and mobile payments. I can do most transactions on my bank's app. I pay my rent and utilities via their official apps and portal. You can also buy stuff or food online and pick them up at the curbside.</p>
<h2 id="people">People</h2>
<p>Americans are generally friendly and cheerful. But like anywhere else, you'll still find rude people. I haven't been discriminated against so far.</p>
<p>Most people here are also active and busy. Teens as young as 16 can work at specific jobs. My sister, who works in a fast-food chain, has plenty of coworkers who are 20 years old or younger. Being independent is central to the American culture, and many people work at a young age to afford their own life. The Filipino culture is the opposite of that.</p>
<p>Asians generally treat customers with esteem. That kind of customer service doesn't exist in the US. However, "the customer is always right" here, so it's easy to demand a return or exchange for things you are dissatisfied with, even if you're being dishonest.</p>
<p>In my workplace, I treat my coworkers equally regardless of their position. Most of them are approachable and outgoing. However, I haven't made friends with any of them yet.</p>
<h2 id="transportation">Transportation</h2>
<p>You need a car to get around in San Diego, so we prioritized getting one. Due to the way how cities are designed here, public transport is not very effective.</p>
<p>If I commute using public transport, it will take me about two hours (18 miles from Lakeside to Scripps Ranch). I wouldn't want to waste time commuting to work every day.</p>
<p>In my first weeks at work, I used Uber. It cost me around $30 to $40 per ride. After a month, my managers learned what I had to endure, and they were considerate enough to let me work from home until I got my driver's license and car.</p>
<p>I haven't got the time to visit most places in San Diego yet, but I'll write it in a separate post if I do.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[First tip]]></title>
            <description><![CDATA[An appreciation post to the nice person that gave me a tip.]]></description>
            <link>https://jhnsprtu.com/blog/first-tip</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/first-tip</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Sat, 11 Jun 2022 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>This site just got its first tip last month. To my supporter, thank you very much. You're awesome!</p>
<p>To my readers, you can send a tip by clicking the link below each blog post. Your support will help keep this site alive and motivate me to create more content.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Wristwatch]]></title>
            <description><![CDATA[A look at my digital wristwatch that's more than a decade old.]]></description>
            <link>https://jhnsprtu.com/blog/wristwatch</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/wristwatch</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Thu, 28 Apr 2022 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>I'm still using the wristwatch my uncle gave me more than a decade ago (circa 2008; can't remember exactly). It may not be fashionable, but it is doing its purpose - telling time.</p>
<figure>
  <a href="/media/consumerism-01.jpg" target="_blank">
    <img class="full" src="/media/consumerism-01.jpg" alt="watch" />
  </a>
</figure>
<p>I've replaced the wristband three times and the battery probably four. These parts are susceptible to wear. The backlight malfunctioned after a few years, but it's not a big deal because the display is readable in most conditions.</p>
<p>This wristwatch is surprisingly durable despite its looks. I dropped it countless times, submerged it in saltwater, and wear it every time I go out of my house. No one will believe it survived the test of time. I've owned other watches, but they didn't last as long.</p>
<figure>
  <a href="/media/consumerism-02.jpg" target="_blank">
    <img class="full" src="/media/consumerism-02.jpg" alt="watch" />
  </a>
</figure>
<p>It's rare for people to own and use the same stuff for years. Things either break down, become inefficient or impractical in the current times, or simply go out of fashion.</p>
<p>I try to acquire as few things as possible and consume what I only need.</p>
<p>In a <a href="https://en.wikipedia.org/wiki/Consumerism">consumerist economy</a>, companies would purposely design frail products, so it becomes obsolete in a pre-determined time upon which they will cease to function, be useful, or might be perceived as unfashionable. By shortening the "replacement cycle" for long-term sales volume, consumers are forced to purchase replacements.</p>
<p>It's even more prevalent in consumer electronics like computers and smartphones. Technology and software play a huge role in the lifecycle and usability of these products. The advancement of software and the internet granted companies greater control over how their products are used. Companies would even use software updates to <a href="https://en.wikipedia.org/wiki/Batterygate">degrade</a> their products or <a href="https://www.theverge.com/2020/2/6/21127243/tesla-model-s-autopilot-disabled-remotely-used-car-update">disable</a> functions.</p>
<p>While consumerism stimulates economic growth, it also certainly <a href="https://news.climate.columbia.edu/2020/12/16/buying-stuff-drives-climate-change/">affects our climate negatively</a>. It's not the best economic order. But like everything else, anything excessive is harmful.</p>
<p>How about you, do you still use something more than a decade old?</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Moved to the US]]></title>
            <description><![CDATA[A story of my migration to the US in 2021.]]></description>
            <link>https://jhnsprtu.com/blog/moved-to-the-us</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/moved-to-the-us</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Mon, 03 Jan 2022 08:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>Happy new year! It was a rough 2021, but glad I managed to survive.</p>
<p>It's my first month living in the US. Although I'm a US Citizen by birth through petition (dad is a naturalized citizen), I haven't set foot on the continent for the 28 years of my existence. Only in 2021 my sister and I decided to move to the US for good.</p>
<p>Moving to the US was my dad's plan since we were young. However, it never happened because of our family and financial circumstances.</p>
<p>After graduating college, my dad's dementia progressed until he needed special care. In 2018, my sister brought him to the US. But because of his condition and agitation, my sister was forced to put him in Rosecrans Care Center in Los Angeles. The costs were too high for us to shoulder, so we put him in an aged care facility in the Philippines.</p>
<p>I didn't see anything interesting in the US. Instead, I wanted to go to Japan because of its interesting culture and technological scene. While working at Bizwind, I even expressed my interest in working for its Japan branch. I even studied the Japanese language and got JPLT N4 certified.</p>
<p>Unfortunately, the COVID-19 pandemic happened. Most countries, including Japan, closed their borders to slow the spread of the virus. They implemented stringent border measures, including limiting visas and travel from "green" countries only.</p>
<p>There were still no signs of when Japan will open its borders. The Philippine government is insufficient at handling the pandemic. These situations forced me to reconsider all other opportunities. I realized that working in the US will give me more opportunities than in the Philippines. Also, given my dad's worsening health, my sister and I decided that we should make his plans for us a reality once and for all.</p>
<h2 id="preparation">Preparation</h2>
<p>We gave ourselves about three months to prepare and booked our flight with Philippine Airlines for November 12. I resigned from my work on August 30.</p>
<p>The flight was rescheduled multiple times due to our COVID-19 vaccination. After booking, we got our first shot on August 23 and the second one on November 15. We had to allow at least 14 days after the second shot to be considered "fully" vaccinated as per the CDC travel bulletin at the time. The final date of our flight was rescheduled to November 30.</p>
<p>Our flight baggage allowance is limited to two 23 kg check-in and 7 kg hand-carry, so I had to let go of most stuff such as memorabilia, electronics, and school medals to make room for the important ones. I left a few things to my girlfriend that I wished to ship some other time. However, I probably won't because shipping those is expensive and impractical.</p>
<p>Flights to the US were restricted. The CDC requires a negative test result at least three days before departure for vaccinated individuals and at least a day for non-vaccinated. We were not fully vaccinated three days before our departure, so we took the test on the day of our flight. We tested negative (faak you, COVID).</p>
<p>At the time, the Omicron variant was discovered and has <a href="https://www.cbs8.com/article/news/local/california/first-us-omicron-infection-found-in-san-francisco/509-ceef2480-c57d-41b0-bd5b-a1a98202a999">eventually found its way to the US</a>, prompting the US government to update its travel advisory. On December 3, all passengers to the US must provide a negative test result taken at least a day before departure, regardless of their vaccination status.</p>
<h2 id="flight">Flight</h2>
<p>Our flight was PR102, an Economy Class flight from Manila (MNL) to Los Angeles International Airport (LAX) on November 30 at 21:10. We arrived at NAIA Terminal 2 at around 16:00. Passengers are required to show the negative test result upon entering the airport. We went through a luggage inspection at the airport entrance.</p>
<figure>
  <a href="/media/moved-to-the-us-3.jpg" target="_blank">
    <img class="full" src="/media/moved-to-the-us-3.jpg" />
  </a>
</figure>
<p>The airport wasn't crowded, and there were also no lines at the immigration counters. The check-in took us about 30 minutes because of multiple inspections. We were permanent residents, so we paid for ECC at the immigration to depart the country. After the immigration check, we went through another luggage inspection then waited at Gate 10.</p>
<figure>
  <a href="/media/moved-to-the-us-4.jpg" target="_blank">
    <img class="full" src="/media/moved-to-the-us-4.jpg" />
  </a>
</figure>
<p>They also conducted another check at the gates. Overall, we went through three inspections, which in my opinion, are inconvenient and unnecessary.</p>
<figure>
  <a href="/media/moved-to-the-us-5.jpg" target="_blank">
    <img class="full" src="/media/moved-to-the-us-5.jpg" />
  </a>
</figure>
<p>The flight was delayed to 23:00, almost two hours from the original schedule. The trip was 12 hours long. We slept throughout the trip, except during the meals. With the complimentary 25 MB in-flight Wi-Fi, I was able to send a few messages to my friends and relatives.</p>
<figure>
  <a href="/media/moved-to-the-us-6.jpg" target="_blank">
    <img class="full" src="/media/moved-to-the-us-6.jpg" />
  </a>
</figure>
<figure>
  <a href="/media/moved-to-the-us-1.jpg" target="_blank">
    <img class="full" src="/media/moved-to-the-us-1.jpg" />
  </a>
</figure>
<h2 id="arrival">Arrival</h2>
<p>We arrived at Los Angeles International Airport on November 30 at 20:20. It was a bit hazy outside the airport.</p>
<figure>
  <a href="/media/moved-to-the-us-7.jpg" target="_blank">
    <img class="full" src="/media/moved-to-the-us-7.jpg" />
  </a>
</figure>
<p>After disembarking, we went through an immigration check, then picked up our luggage from the conveyor. Our cousin picked us up from the arrival area and drove us for about two hours to her condominium that we rented in Lakeside, California.</p>
<figure>
  <a href="/media/moved-to-the-us-2.jpg" target="_blank">
    <img class="full" src="/media/moved-to-the-us-2.jpg" />
  </a>
  <figcaption>San Diego nightscape</figcaption>
</figure>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Survived COVID-19]]></title>
            <description><![CDATA[A journal on my experience as a COVID patient and survivor.]]></description>
            <link>https://jhnsprtu.com/blog/survived-covid</link>
            <guid isPermaLink="true">https://jhnsprtu.com/blog/survived-covid</guid>
            <dc:creator><![CDATA[John Espiritu]]></dc:creator>
            <pubDate>Tue, 02 Nov 2021 00:00:00 GMT</pubDate>
            <author>John Espiritu</author>
            <content:encoded><![CDATA[<p>The coronavirus disease 2019 (COVID-19) is a contagious disease caused by severe acute respiratory coronavirus 2 (SARS-CoV-2). It ravaged the planet in December 2019 and is still ongoing at the time of writing.</p>
<p>The WHO released guidelines to slow down the spread of the virus such as:</p>
<ul>
<li>Staying at home</li>
<li>Wearing a mask</li>
<li>Keeping distance from others</li>
<li>Washing hands with soap and water</li>
<li>Frequently disinfecting hands and objects with alcohol</li>
<li>Avoid touching the eyes, nose, and mouth with unwashed hands</li>
<li>Getting vaccinated</li>
</ul>
<p>We follow these protocols vigorously and stay at home as much as possible. However, the virus got past our defenses and infected us in October 2021.</p>
<h2 id="howwegotit">How we got it</h2>
<p>My girlfriend went home to her hometown on October 2 to attend her sister's wedding ceremony. During that period, I stayed in our apartment in Makati.</p>
<p>The government restrictions that time allow public gatherings such as weddings to be held with guests no more than 30% of the venue's seating capacity while strictly observing the preventive measures.</p>
<p>I advised that she stay home for at least 7 days before going back to the apartment, but her home is not good for telework. She went back to our apartment on October 4.</p>
<p>To avoid the risks of public transportation, she rented a cab using the ride-hailing service Grab on her travels.</p>
<p>A few days after she went back, we isolated in our apartment unit and never went out. We requested my sister, who's living in a different unit, to pick up our food deliveries and run errands on our behalf.</p>
<h2 id="whathappened">What happened</h2>
<p>Around October 8, we started to sneeze and have runny nose. We assumed it was just the cold because we catch it now and then, although we never leave our apartment.</p>
<p>On October 10, my girlfriend lost her sense of smell and taste, a <a href="https://www.mayoclinichealthsystem.org/hometown-health/featured-topic/q-and-a-covid-19-and-loss-of-smell-taste">common symptom</a> of COVID-19. At the same time, we are experiencing dry coughs.</p>
<p>On October 12, I had a fever, which lasted for a day. The IR thermometer we've bought in the early periods of the pandemic broke just after a few months, so we didn't have an instrument to measure our temperatures. My pulse was also fast, even at rest. My girlfriend didn't have a fever.</p>
<p>Our symptoms show that we have COVID, so we reported our situation to the property management the next day. They advised that we get tested using <a href="https://www.zennya.com/">Zennya</a>, a telemedical service. We booked rapid antigen tests on the same day, around 16:00.</p>
<figure>
  <a href="/media/survived-covid-2.jpg" target="_blank"><img class="sm" src="/media/survived-covid-2.jpg"/></a>
  <a href="/media/survived-covid-1.jpg" target="_blank"><img class="sm" src="/media/survived-covid-1.jpg"/></a>
  <figcaption>Home service testing</figcaption>
</figure>
<p>A registered nurse went to our unit in full PPE and performed the nasal swab. The tests used <a href="https://diagnostics.roche.com/global/en/products/params/sars-cov-2-rapid-antigen-test.html">Roche antigen test</a> kits. We were able to see the results within a few minutes. As expected, we were positive of the virus.</p>
<p>We submitted a copy of the results to the management. They allowed us to stay in the building. However, we were forbidden to go out of our unit at any time for the next 14 days.</p>
<p>On October 14, I also lost my sense of smell and taste.</p>
<p>We confirmed the condition of my girlfriend's relatives, who also attended the event. Because they didn't show any symptoms, we can't exactly tell where she got the virus.</p>
<h2 id="careandrecovery">Care and recovery</h2>
<p>The building staff would deliver our drinking water outside our unit and put away our garbage bags. My sister would bring our food deliveries to our doorstep.</p>
<p>Zennya offered a complimentary consultation, which we gladly took. The consultation was conducted via video call using their app. The doctor prescribed that I take Paracetamol, Vitamin C + Zinc, Azithromycin, Dynatussin, Ketesse, and Vitamin D. <em>(warning: don't use these drugs without prescription!)</em></p>
<p>Although not proven helpful against the virus, we took Scott's Vitamin C pastilles and drank fruit juice daily to give our immune system an extra boost.</p>
<p>We also got a new thermometer and pulse oximeter to monitor our oxygen saturation level and temperature.</p>
<figure>
  <a href="/media/survived-covid-4.jpg" target="_blank"><img class="sm" src="/media/survived-covid-4.jpg"/></a>
  <figcaption>Pulse oximeter</figcaption>
</figure>
<p>I lost my appetite for fast foods so we ate lots of meals with soup such as <em>sinigang</em> and <em>nilaga</em>. Cooking with a stove is not allowed in our apartment, so we usually order meals from Grab.</p>
<p>Luckily, our symptoms remained mild during the our infection. Our oxygen levels never went below 95, and our breathing was fine, so we didn't need oxygen support.</p>
<p>Our condition has gradually improved a week after the onset of symptoms. We regained our sense of smell and taste around the second week.</p>
<figure>
  <a href="/media/survived-covid-3.jpg" target="_blank"><img class="sm" src="/media/survived-covid-3.jpg"/></a>
  <figcaption>Fully recovered after 14 days</figcaption>
</figure>
<p>We booked another antigen test on the 14th day (October 27) as advised by the property management. Finally, we tested negative and were officially fully recovered from the virus.</p>
<h2 id="getvaccinated">Get vaccinated</h2>
<p>Getting the virus is scary and depressing because you can't tell how hard it will hit you. I've personally known some people who got moderate to severe symptoms; others didn't survive.</p>
<p>The best prevention is to get vaccinated once you're eligible. Vaccination <a href="https://www.cdc.gov/coronavirus/2019-ncov/vaccines/effectiveness/why-measure-effectiveness/breakthrough-cases.html">doesn't guarantee</a> you won't get the virus, but it will lower your chance of developing severe illness. No, <a href="https://www.hopkinsmedicine.org/health/conditions-and-diseases/coronavirus/covid-19-vaccines-myth-versus-fact">vaccines don't alter</a> your DNA; stop believing bullshit.</p>
<p>Vaccines prepare your adaptive immune system against the virus so it can react faster before the virus can cause significant damage to your body. The CDC has an <a href="https://www.cdc.gov/coronavirus/2019-ncov/vaccines/different-vaccines/how-they-work.html">article</a> explaining this phenomenon in detail.</p>
<p>I got my first dose of <a href="https://en.wikipedia.org/wiki/Oxford%E2%80%93AstraZeneca_COVID-19_vaccine">AstraZeneca</a> vaccine on August 23. The effects of the vaccine on each people differ. About 12 hours after the vaccination, my sister and I got a fever that lasted for a day. My girlfriend didn't develop any fever at all.</p>
<p>Depending on where you live, your government may prioritize certain groups of people due to limited vaccine supplies. Register and get vaccinated as soon it's your turn. While you're not yet <a href="https://www.cdc.gov/coronavirus/2019-ncov/vaccines/fully-vaccinated.html">fully vaccinated</a>, strictly follow all protocols, be vigilant, stay healthy, and avoid unnecessary travel.</p>
<p>My schedule for the second dose is on November 15. The long wait between doses is said to provide <a href="https://www.abc.net.au/news/health/2021-07-05/astrazeneca-vaccine-timing-doses/100259926">the optimal protection</a> against the virus.</p>]]></content:encoded>
        </item>
    </channel>
</rss>