<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Yousef Akbar's posts</title>
    <link>https://yousef.sh/posts/</link>
    <description>Writing and technical notes by Yousef Akbar</description>
    <language>en</language>
    <lastBuildDate>Thu, 27 Aug 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://yousef.sh/posts/feed.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Google Fitbit Air Review</title>
      <link>https://yousef.sh/posts/google-fitbit-air-review.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/google-fitbit-air-review.html</guid>
      <pubDate>Thu, 27 Aug 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>A few months ago, my <a href="https://www.apple.com/watch/">Apple
Watch</a> strap broke and I stopped using it for a while. I went on a
quest to find a suitable wearable fitness tracker and settled on
Google’s Fitbit Air.</p>
<p>My requirements while searching were the following:</p>
<ul>
<li>Reasonably priced with <em>no recurring subscriptions</em></li>
<li>Did not care much for a watch face or telling the time</li>
<li>Lightweight and out of my way
<ul>
<li>No notifications or bright screen</li>
</ul></li>
<li><strong>IMPORTANT</strong>: data ownership and exportability (more
on that below)</li>
<li>Long battery life</li>
<li>Good sleep tracking</li>
<li>Accurate <em>enough</em></li>
</ul>
<h2 id="price">Price</h2>
<p>The Fitbit Air sits at a very attractive price point ($99), and it is
a one-time fee. In contrast, the WHOOP is priced higher and includes a
yearly subscription fee with multiple membership tiers.</p>
<p>The Fitbit <em>does</em> have a paid tier as well, which adds on
personalized coaching with Gemini, adaptive plans, sleep guidance,
etc.</p>
<p>You can essentially replicate some of the data analysis and
personalized monitoring by self-hosting your own health data using <a
href="https://github.com/yousefakbar/vitald"><code>vitald</code></a>,
since your data is not vendor-locked and can be extracted from the
Google API.</p>
<h2 id="look-and-feel">Look and feel</h2>
<p>No complaints whatsoever here. The design of the Fitbit is sleek,
subtle, and super light. Oftentimes I forget I am even wearing it, and
that makes sleeping with the Fitbit on very comfortable.</p>
<p>It comes in three color options: black, red/pink, and blue. I picked
the first, and it works well for most occasions whether you’re going for
a sporty look or business-casual.</p>
<p>Not much more to say on that. It’s a very simple-looking device, and
I like that.</p>
<h2 id="battery-life">Battery life</h2>
<p>Compared to the Apple Watch I previously used, the Fitbit Air’s
battery life is excellent.</p>
<p>Charging to 100% takes around an hour, and fully charged it lasts me
about a full week. For reference, I was used to charging my Apple Watch
nightly, which meant I pretty much always lost out on sleep tracking. I
usually top it up while showering rather than waiting for the battery to
run out, so charging rarely feels disruptive.</p>
<p>The device vibrates and briefly pulses a red light when the battery
falls below 20%, and you get a notification on your phone as well to
remind you.</p>
<p>To check the battery you can see the percentage on the Google Health
app, or you can tap twice on the strap tracker. However, I find the
double-tap gesture unreliable; it often takes several attempts before it
works.</p>
<h2 id="health-metrics">Health metrics</h2>
<p>This device captures most of what I need in terms of health
metrics:</p>
<ul>
<li>Steps</li>
<li>Distance moved</li>
<li>Sleep
<ul>
<li>Duration</li>
<li>Score</li>
<li>Breakdown of sleep stages (light, deep, REM)</li>
</ul></li>
<li>Heart rate
<ul>
<li>Resting heart rate</li>
<li>Heart rate variability</li>
</ul></li>
<li>Calories burned (roughly)</li>
<li>Exercise
<ul>
<li>Track sessions with the <a
href="https://healthapp.google/"><em>Google Health app</em></a></li>
<li>Set targets for exercise streaks</li>
<li>Weekly cardio percentage</li>
</ul></li>
<li>Blood oxygen (SpO2)</li>
<li>Skin temperature</li>
<li>Readiness (recovery) score</li>
</ul>
<p>It covers pretty much everything I need from a casual fitness
tracker.</p>
<h2 id="accuracy-in-everyday-use">Accuracy in everyday use</h2>
<p>I would give the accuracy a rating of 7.5/10.</p>
<p>Sleep detection has been particularly reliable in my experience. It
generally figures out when I have fallen asleep and when I fully wake
up. It’s easier to know if sleep metrics are right based on your
awareness of how long you slept and how you <em>feel</em> after you wake
up.</p>
<p>Similarly the heart rate metrics seem consistent with my experience
on the Apple Watch and they are sufficiently accurate. I haven’t
compared either device against clinical equipment, so this is a
subjective affirmation.</p>
<p>With other metrics - such as calories burned, exercise intensity,
readiness, etc. - it’s harder to judge because these devices make
estimates based on height, weight, and other factors. Therefore, this is
an assessment of everyday consistency rather than medical accuracy.</p>
<p>That said, my own observation of calories in/out vs. daily weight
trend seems pretty reasonable (I’m maintaining weight at the moment).
It’s not a validation on the accuracy, but more so an affirmation that
it <em>works for me</em>.</p>
<h2 id="integration">Integration</h2>
<p>Since Fitbit is now Google-owned, the ecosystem pairs very well with
the Google Health app for a general view of your metrics.</p>
<p>As I hinted earlier, you also get to export your own data through the
Google API and that kind of data ownership I was missing with the Apple
Watch and it was a critical factor in this purchase.</p>
<blockquote>
<p><strong>Note:</strong> Technically Apple Health supports complete XML
export as well through HealthKit. The advantage of the Fitbit is the
convenient server-side API access.</p>
</blockquote>
<p>In fact, I recently rolled out my own self-hosted data aggregation
and health monitoring dashboard solution <a
href="https://github.com/yousefakbar/vitald"><code>vitald</code></a>.
It’s a <code>systemd</code>-compatible service that periodically pulls
my health data, backs it up, stores raw archives, normalizes the data
into a Postgres database, and connects it to Grafana for visualization
and monitoring. You can read my <a
href="https://yousef.sh/posts/devlog-1-vitald.html">devlog</a> on how I
built it and how you can do the same.</p>
<p>Fitbit also gives you the ability to connect it to gym equipment
(although I have not used this feature) to integrate data with it both
ways.</p>
<p>That makes it a 9/10 on integrations.</p>
<h2 id="alarms">Alarms</h2>
<p>One thing I really liked about the Apple Watch is that I could use
watch-like features (duh) with it like alarms, timers, and
stopwatches.</p>
<p>It’s a bit of a regression with the Fitbit: it only has an alarm
feature (you can set up to 9 alarms), and they activate with haptic
feedback. The lack of timers and stopwatches makes sense, though, since
there is no watch face to it; it’s just a strap, so I knew what to
expect.</p>
<p>The haptic feedback is configurable with intensity. At the highest
intensity, the vibration is strong enough to wake me up from sleep.
Although the gesture to turn it off is really cumbersome and unreliable
(tap twice <em>really hard</em> on the strap crown).</p>
<p>This gets a 6.5/10. Could be better in my opinion if silencing it was
more convenient with a small button or a more reliable gesture.</p>
<h2 id="verdict">Verdict</h2>
<p>Overall, I’m very happy with this purchase and I really think it was
worth the price for what it’s capable of and the data ownership it
provides. The battery life is excellent and it gets out of your way. The
auto-detection of activities is a really nice touch too if you can’t be
bothered to log them beforehand. With a myriad of metrics, extensive
integration potential, and reasonable accuracy, it’s more than enough
for the average person to get into fitness tracking and improving their
health.</p>
<p>Let me know if you have any thoughts on this device or any other
suggestions for similar products worth checking out. Feel free to
contact me <a href="https://yousef.sh/#contact">here</a>.</p>]]></description>
    </item>
    <item>
      <title>IMAP IDLE: Making mbsync Feel Instant</title>
      <link>https://yousef.sh/posts/imap-idle-making-mbsync-feel-instant.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/imap-idle-making-mbsync-feel-instant.html</guid>
      <pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>For the two people out there who still manage their mail offline in
the terminal with tools like <code>mbsync</code> and
<code>notmuch</code>, this is a useful tip to make your synchronization
with IMAP servers more seamless and efficient, without needing to poll
and pull so frequently. Enter: <code>IDLE</code> on <a
href="https://datatracker.ietf.org/doc/html/rfc2177.html">IMAP</a> and
<a
href="https://gitlab.com/shackra/goimapnotify"><code>goimapnotify</code></a>.</p>
<p>For context, this is my current setup to get my email into a Maildir
directory and access it offline:</p>
<pre><code>    ┌──────────────┐        
    │ IMAP Server  │        
    │ (e.g. Gmail) │        
    └──────┬───────┘        
           │                
         mbsync             
        Push/Pull           
           │                
           ▼                
    ┌──────────────┐        
    │ Local Machine│        
    │   Maildir    │        
    └──────┬───────┘        
           │                
       notmuch new          
           │                
           ▼                
    ┌──────────────┐        
    │   Indexed    │        
    └──────────────┘        
                            
Accessible with any frontend
                            
  e.g. - Emacs              
       - *notmuch.nvim*
       - neomutt            </code></pre>
<p>The <code>mbsync</code> and <code>notmuch</code> stack is pretty
canonical at this point and most setups use the same. It works fine on
its own but requires frequent polling and it’s still not as fresh as I
would like.</p>
<p><strong>Note</strong>: Check out my <a
href="https://github.com/yousefakbar/notmuch.nvim">Neovim plugin
notmuch.nvim</a>, which acts as a frontend for reading and writing email
inside your favorite text editor :-).</p>
<h2 id="imap-idle-command">IMAP IDLE command</h2>
<p>As per <a
href="https://datatracker.ietf.org/doc/html/rfc2177.html">RFC 2177</a>,
IMAP servers have a useful <em>capability</em> called <code>IDLE</code>.
The <code>IDLE</code> command allows clients to receive “push
notifications” from the server upon an update (new/updated/removed mail)
from a watched mailbox.</p>
<p>With a specialized tool (see below for <code>goimapnotify</code>),
you can setup hooks that pull/synchronize your Maildir with the server
whenever a new message arrives in that mailbox.</p>
<p>To check whether your mail server supports this capability, run the
following:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Replace &quot;imap.example.com:993&quot; with your provider&#39;s IMAP details</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">openssl</span> s_client <span class="at">-connect</span> imap.example.com:993 <span class="at">-crlf</span> <span class="at">-quiet</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ex">*</span> OK IMAP server ready</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="co"># Type this once you are connected</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="ex">a1</span> CAPABILITY</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="ex">*</span> CAPABILITY IMAP4rev1 IDLE NAMESPACE UIDPLUS MOVE AUTH=PLAIN</span></code></pre></div>
<p>For more information on IDLE and how it works, check out the <a
href="https://datatracker.ietf.org/doc/html/rfc2177.html">RFC
reference</a>.</p>
<h2 id="goimapnotify">goimapnotify</h2>
<p><code>goimapnotify</code> is a Go utility (improved version of the
older <code>imapnotify</code>) that executes scripts on IMAP mailbox
changes (new/deleted/updated messages) using the <code>IDLE</code>
command on capable servers.</p>
<p>It’s configured with a YAML file that allows for control over
multiple accounts, and configurable per-mailbox behavior.</p>
<h3 id="installation">Installation</h3>
<p>It’s a Go program so you can use <code>go install</code> to install
it:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">go</span> install gitlab.com/shackra/goimapnotify/cmd/goimapnotify@latest</span></code></pre></div>
<h3 id="configuration">Configuration</h3>
<p>Here’s my sample configuration that allows me to get notifications on
new/updated/removed mail (no sensitive information):</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ~/.config/imapnotify/gmail.yaml</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="fu">configurations</span><span class="kw">:</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="kw">-</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">host</span><span class="kw">:</span><span class="at"> imap.gmail.com</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">port</span><span class="kw">:</span><span class="at"> </span><span class="dv">993</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">tls</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">tlsOptions</span><span class="kw">:</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">rejectUnauthorized</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="fu">starttls</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">idleLogoutTimeout</span><span class="kw">:</span><span class="at"> </span><span class="dv">15</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">username</span><span class="kw">:</span><span class="at"> </span><span class="st">&#39;&lt;YOUR-EMAIL&gt;&#39;</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="co">    # password: &#39;&lt;YOUR-PASSWORD&gt;&#39;</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">passwordCMD</span><span class="kw">:</span><span class="at"> </span><span class="st">&#39;&lt;COMMAND-TO-PASSWORD-MANAGER&gt;&#39;</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">xoAuth2</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">boxes</span><span class="kw">:</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="at">      </span><span class="kw">-</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a><span class="at">        </span><span class="fu">mailbox</span><span class="kw">:</span><span class="at"> INBOX</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a><span class="at">        </span><span class="fu">onNewMail</span><span class="kw">:</span><span class="at"> </span><span class="st">&#39;mbsync gmail:INBOX&#39;</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a><span class="at">        </span><span class="fu">onChangedMail</span><span class="kw">:</span><span class="at"> </span><span class="st">&#39;mbsync gmail:INBOX&#39;</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a><span class="at">        </span><span class="fu">onNewMailPost</span><span class="kw">:</span><span class="at"> </span><span class="st">&#39;notmuch new&#39;</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a><span class="at">        </span><span class="fu">onChangedMailPost</span><span class="kw">:</span><span class="at"> </span><span class="st">&#39;notmuch new&#39;</span></span></code></pre></div>
<p>The <code>boxes</code> section defines the behavior.
<code>onNewMail</code> and <code>onChangedMail</code> trigger
<code>mbsync &lt;account&gt;:INBOX</code> to start synchronizing to my
Maildir. <code>onNewMailPost</code> and <code>onChangedMailPost</code>
run <code>notmuch new</code> to index any updates in
<code>notmuch</code> where the tagging and searching capabilities
work.</p>
<h2 id="persistent-systemd-service">Persistent systemd service</h2>
<p>You could run the <code>goimapnotify</code> program with this
configuration manually:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">goimapnotify</span> <span class="at">-conf</span> ~/.config/imapnotify/gmail.yaml</span></code></pre></div>
<p>But you would be better served by defining a small systemd service
for this so that it runs in the background automatically:</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode ini"><code class="sourceCode ini"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">; ~/.config/systemd/user/goimapnotify.service</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">[Unit]</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Description</span><span class="ot">=</span><span class="st">IMAP IDLE Notifier</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Documentation</span><span class="ot">=</span><span class="st">https://gitlab.com/shackra/goimapnotify</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="kw">[Service]</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Type</span><span class="ot">=</span><span class="st">simple</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="co">; Replace this path with `command -v goimapnotify`</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="dt">ExecStart</span><span class="ot">=</span><span class="st">/home/yha/go/bin/goimapnotify -conf %h/.config/imapnotify/gmail.yaml</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Restart</span><span class="ot">=</span><span class="st">on-failure</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="dt">RestartSec</span><span class="ot">=</span><span class="dv">5</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="kw">[Install]</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a><span class="dt">WantedBy</span><span class="ot">=</span><span class="st">default.target</span></span></code></pre></div>
<p>Don’t forget to reload your systemd config and enable and start the
service:</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ex">systemctl</span> <span class="at">--user</span> daemon-reload</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ex">systemctl</span> <span class="at">--user</span> enable <span class="at">--now</span> goimapnotify.service</span></code></pre></div>
<h2 id="conclusion">Conclusion</h2>
<p>Now, whenever I receive new emails, I am not beholden to whenever my
whim compels me to refresh and update my sync flow. I can safely rely on
<code>goimapnotify</code> to receive those update notifications from
Gmail and accordingly run <code>mbsync</code> and <code>notmuch</code>
to sync my Maildir, which is particularly useful when I need to reach
for an email OTP or a confirmation email quickly.</p>
<p>For any thoughts or suggestions, <a
href="https://yousef.sh/#contact">feel free to contact me</a>.</p>]]></description>
    </item>
    <item>
      <title>Devlog #1: vitald v0.1.0 — Building a Self-Hosted Health Data Pipeline</title>
      <link>https://yousef.sh/posts/devlog-1-vitald.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/devlog-1-vitald.html</guid>
      <pubDate>Wed, 19 Aug 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>This is a write-up of a weekend project, <a
href="https://github.com/yousefakbar/vitald"><code>vitald</code></a>, I
made after buying a <em>Google Fitbit Air</em> (I’m slowly transitioning
out of the Apple ecosystem).</p>
<p>One of the main reasons I gravitated towards the Fitbit Air was that,
with the Google Health App, my health metrics are synchronized to my
Google account, which in turn can be pulled offline over API (data
ownership!).</p>
<p>This means that I can fetch and synchronize all my health data
offline and visualize it to do my own collection and wrangling with the
data.</p>
<p>This is what I built <code>vitald</code> to do: it is a
systemd-compatible service that periodically pulls my health data,
stores it into a database, and connects it to Grafana for visualization
and playing around with the data to make better health choices.</p>
<h2 id="showcase">Showcase</h2>
<blockquote>
<p>It’s critical to note that wearable fitness trackers provide
<strong>estimates</strong> of health metrics and should not be seen as
100% accurate data. Do not use commercial wearables as replacements for
medical professionals.</p>
</blockquote>
<p>The end result from this project is that I created 6 analytics views
for Grafana. Below is the primary “overview” dashboard that I use to see
my metrics at a glance.</p>
<p><img src="/static/img/vitald-grafana-dashboard.png"
title="Health Overview Dashboard" alt="vitald Grafana dashboard" /></p>
<p>This overview dashboard contains:</p>
<ul>
<li>Daily steps count</li>
<li>A plot of my recorded weight over time</li>
<li>My resting heart rate (RHR) over time</li>
<li>Heart rate variability over time</li>
<li>Sleep duration every day</li>
<li>Exercise data including total and active zone minutes</li>
<li>Daily calories in and out</li>
</ul>
<p>This contains the high-level data I would like to know in a quick
skim. Then there are other dashboards and queries for data points I may
find interesting to track to answer questions such as:</p>
<ul>
<li>How does my calorie surplus/deficit affect my weight over time?
What’s my BMR?</li>
<li>How does strenuous exercise affect my sleep duration?</li>
<li>Is there any correlation between my sleep duration and weight?</li>
<li>How did last year’s work stress affect my HRV and well-being?</li>
</ul>
<p>This kind of information is not so trivially analyzed with the basic
Google Health app, and definitely not available under Apple’s ecosystem
since you don’t own your data there.</p>
<h2 id="architecture-and-data-flow">Architecture and data flow</h2>
<p>Below is the architecture diagram for the project’s data flow. The
first two are straight forward and already provided by the hardware and
Google’s infrastructure.</p>
<p>The <code>vitald</code> CLI and the components hosted locally on my
homelab are managed by this project.</p>
<p>The subsequent sections describe these 2 components in more
detail.</p>
<p><img src="/static/img/vitald-architecture-diagram.png" alt="Project architecture
diagram" style="height:750px;"/></p>
<h2 id="go-utility">Go utility</h2>
<p>At its core, <code>vitald</code> is a Go command-line tool. It
handles the OAuth management with Google Cloud, and is responsible for
fetching, storing, and normalizing the data sets from the Health API
into JSON archives, as well as structured data in Postgres.</p>
<p>In a nutshell (<em>note it is recommended to use
docker/podman</em>):</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># First time authentication (sign-in and accept)</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> compose run <span class="at">--rm</span> <span class="at">--no-deps</span> <span class="at">--service-ports</span> vitald auth</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Verify identity with Cloud project</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> compose run <span class="at">--rm</span> <span class="at">--no-deps</span> vitald identity</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co"># Check on the status and last run(s) if any</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> compose run <span class="at">--rm</span> <span class="at">--no-deps</span> vitald status</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="co"># Initiate the first sync command</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> compose run <span class="at">--rm</span> <span class="at">--no-deps</span> vitald sync</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="co"># Health check</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> compose run <span class="at">--rm</span> <span class="at">--no-deps</span> vitald doctor</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> compose run <span class="at">--rm</span> <span class="at">--no-deps</span> vitald doctor <span class="at">--online</span> <span class="co"># Check your auth</span></span></code></pre></div>
<h2 id="compose-and-systemd">Compose and systemd</h2>
<p>The project stack (Postgres, Grafana, <code>vitald</code> binary) are
bundled in <code>compose.yaml</code>, including backup and restore
services as well.</p>
<p>If you just want to run it once to try it out:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Set up the project containers</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> compose up <span class="at">-d</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Then, for vitald, run the commands listed earlier</span></span></code></pre></div>
<p>The <code>scripts/install-systemd.sh</code> script installs 4 service
unit/timer pairs for automated management, ideal for long-term usage and
homelab setups. Under the hood it uses the same compose commands.</p>
<p>After running this script you can verify the installed timers, as
well as their previous and next scheduled runs:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">systemctl</span> <span class="at">--user</span> list-timers <span class="st">&quot;vitald-*&quot;</span></span></code></pre></div>
<p>Sample output:</p>
<pre class="text"><code>NEXT                            LEFT LAST                              PASSED UNIT                       ACTIVATES
Wed 2026-08-19 18:16:51 +03 1h 29min Wed 2026-08-19 12:16:52 +03 4h 30min ago vitald-sync.timer          vitald-sync.service
Thu 2026-08-20 02:01:53 +03       9h Wed 2026-08-19 02:01:56 +03      14h ago vitald-doctor.timer        vitald-doctor.service
Thu 2026-08-20 03:06:57 +03      10h Wed 2026-08-19 03:06:58 +03      13h ago vitald-backup.timer        vitald-backup.service
Sun 2026-08-23 04:01:53 +03   3 days Tue 2026-08-18 12:55:04 +03            - vitald-verify-backup.timer vitald-verify-backup.service</code></pre>
<h2 id="steps-to-run-it-yourself">Steps to run it yourself</h2>
<ol type="1">
<li>Clone repo</li>
</ol>
<div class="sourceCode" id="cb5"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> clone git@github.com:yousefakbar/vitald.git</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> vitald</span></code></pre></div>
<ol start="2" type="1">
<li><p>Copy <code>.env.example</code> to <code>.env</code></p></li>
<li><p>Populate required variables in <code>.env</code></p>
<ul>
<li>From Google Cloud Dashboard
<ul>
<li><code>GOOGLE_CLIENT_ID</code></li>
<li><code>GOOGLE_CLIENT_SECRET</code></li>
</ul></li>
<li>Generate using <code>openssl rand -hex 32</code>
<ul>
<li><code>POSTGRES_PASSWORD</code> (and update DATABASE_URL)</li>
<li><code>GRAFANA_ADMIN_PASSWORD</code></li>
<li><code>GRAFANA_SECRET_KEY</code></li>
<li><code>VITALD_GRAFANA_DB_PASSWORD</code></li>
</ul></li>
<li>Generate using <code>openssl rand -base64 32</code>
<ul>
<li><code>.restic-password</code> file</li>
</ul></li>
<li>Specify the container engine in
<code>$VITALD_CONTAINER_ENGINE</code>
<ul>
<li>Defaults to <code>podman</code></li>
<li>You can switch it to <code>docker</code></li>
</ul></li>
<li>Specify tailscale IP in <code>$GRAFANA_ROOT_URL</code> to access
externally</li>
</ul></li>
<li><p>Source the <code>.env</code> variable to export their variables
to your environment</p></li>
</ol>
<pre><code>set -a
source .env
set +a</code></pre>
<ol start="5" type="1">
<li><p>Run <code>docker compose up -d</code> for image pulling and first
time setup</p></li>
<li><p>Initial <code>vitald</code> run for auth and identity
management</p></li>
</ol>
<pre><code>docker compose run --rm --no-deps --service-ports vitald auth
docker compose run --rm --no-deps vitald identity</code></pre>
<ol start="7" type="1">
<li>Bring down compose project and then install the systemd units</li>
</ol>
<div class="sourceCode" id="cb8"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> compose down <span class="co"># (optional)</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="co"># &quot;--engine docker&quot; depends on if you use docker or podman (default)</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">./scripts/install-systemd.sh</span> <span class="at">--engine</span> docker</span></code></pre></div>
<h3 id="google-cloud-pre-requisites">Google Cloud pre-requisites</h3>
<p>Make sure you create a Google Cloud project from their dashboard and
get a <code>Client_ID</code> and <code>Client_Secret</code> to use in
the <code>.env</code> file.</p>
<p><strong>Even more important</strong> is to make sure that it has the
needed API permissions:</p>
<ul>
<li><code>googlehealth.activity_and_fitness.readonly</code></li>
<li><code>googlehealth.health_metrics_and_measurements.readonly</code></li>
<li><code>googlehealth.sleep.readonly</code></li>
<li><code>googlehealth.nutrition.readonly</code></li>
</ul>
<p>The auth and fetching will not work if you don’t have these
permissions on the client generated.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this day and age, data is your most valuable asset, so strive to
own your data as much as possible.</p>
<p>By having access to your raw data, you can now take more intentional
and informed decisions related to your health.</p>
<p>Just make sure not to obsess over it and remember to enjoy the
moment!</p>
<p>With that said, although this is a personal project I made, I’d love
to hear your thoughts and feedback. Anything related to either the
technical implementation or, on a more creative side, the potential use
cases for these dashboards are more than welcome.</p>
<p><a href="https://yousef.sh/#contact">Feel free to reach out</a></p>]]></description>
    </item>
    <item>
      <title>Terminal Image Display with WezTerm</title>
      <link>https://yousef.sh/posts/terminal-image-display-with-wezterm.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/terminal-image-display-with-wezterm.html</guid>
      <pubDate>Tue, 10 Feb 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>For the longest time I’ve been struggling with image display in
terminals. I either never bothered to put in the effort to configure it,
or I was in config hell trying to figure out which program or layer was
blocking the image display.</p>
<p>Now that I’ve ditched <code>Ghostty</code> and went back to
<code>WezTerm</code> (I am so glad I did this, but that deserves its own
blog), I finally got a working terminal setup with image display both
with and without <code>tmux</code>.</p>
<p>Here’s how I did it, and some notes for reproducibility.</p>
<h2 id="wezterm-built-in-command">WezTerm built-in command</h2>
<p><code>WezTerm</code> has the <code>wezterm</code> CLI command for
interacting with the terminal. This command includes a built-in
<code>imgcat</code> subcommand that outputs an image to the terminal.
This subcommand also respects <code>tmux</code> passthrough with an
option flag.</p>
<h3 id="custom-script">Custom script</h3>
<p>I created the following script for printing image output to the
terminal, both within tmux and outside of it:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env sh</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Script name: `img`</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="bu">[</span> <span class="ot">-n</span> <span class="st">&quot;</span><span class="va">$TMUX</span><span class="st">&quot;</span> <span class="bu">]</span><span class="kw">;</span> <span class="cf">then</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="ex">wezterm</span> imgcat <span class="at">--tmux-passthru</span> detect <span class="at">--max-pixels</span> 2000000 <span class="st">&quot;</span><span class="va">$@</span><span class="st">&quot;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="ex">wezterm</span> imgcat <span class="st">&quot;</span><span class="va">$@</span><span class="st">&quot;</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="cf">fi</span></span></code></pre></div>
<p><strong>Note</strong>: The <code>max-pixels</code> makes it so that
tmux doesn’t have issues displaying large or high resolution image files
(this happened a lot.)</p>
<h3 id="config">Config</h3>
<p>This config line is needed for WezTerm to enable the
<code>kitty</code> image display protocol and allow for images to be
displayed using escape sequences.</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode lua"><code class="sourceCode lua"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Required for reliable image rendering</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="va">config</span><span class="op">.</span><span class="va">enable_kitty_keyboard</span> <span class="op">=</span> <span class="kw">true</span></span></code></pre></div>
<h2 id="file-manager-previews">File manager previews</h2>
<p>I wrestled for hours with <code>ranger</code> and <code>lf</code>
with no luck because they were all really hacky and error-prone.</p>
<p>Come to find out, <code>yazi</code> works like a charm out of the box
because it already speaks the <code>kitty</code> image display protocol.
No extra configuration needed, and it works in tmux without even needing
to use the <code>img</code> script I showed above.</p>
<h3 id="cherry-on-top">Cherry on top</h3>
<p>Just to make things even smoother with <code>yazi</code>, I added PDF
image previews in the terminal which requires <code>poppler</code> to be
installed. Very straight forward install with <code>brew</code>.</p>]]></description>
    </item>
    <item>
      <title>2026 Roadmap and Goals</title>
      <link>https://yousef.sh/posts/2026-roadmap-and-goals.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/2026-roadmap-and-goals.html</guid>
      <pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<blockquote>
<p>“The important thing is not your process, the important thing is your
process for improving your process.” — Henrik Kniberg, on the continuous
nature of self-improvement.</p>
</blockquote>
<p>Happy new year to everyone around the world! I hope you too have had
a lovely break from the whiny PM’s this past week or two, and enjoyed
your holidays. A new year marks renewed excitement, hopes, and
challenges. It is also a chance to reflect on the past 12 months and set
concrete goals for self-improvement.</p>
<p>In that spirit, I want to take this opportunity to spell out some
objectives I had in mind that I am aiming to achieve in this Year of the
Horse. By doing so, I want to keep myself accountable so that I can
revisit these objectives quarterly and do a final retrospective at the
end of the year.</p>
<p><strong>TL;DR</strong> (in no particular order):</p>
<ul>
<li>Revamp website (already WIP)</li>
<li>Career boosts
<ul>
<li>Get promotion or paybump at my job</li>
<li>Finally do Kubernetes CKA certificate</li>
<li>Learn Rust?</li>
</ul></li>
<li>Side hustles
<ul>
<li>Get <code>notmuch.nvim</code> to 100+ stars</li>
<li>Roll out my own <code>pkm</code> system for notetaking and task
management</li>
<li>Launch app startup</li>
</ul></li>
<li>Blog more</li>
<li><code>Nix</code>ify homeserver (and Macbook?)</li>
</ul>
<h2 id="revamp-website">🚧 Revamp website</h2>
<p>(This is already in progress).</p>
<p>I first created and deployed this microblog site in late 2024 as an
exercise for me to get into blogging, journalling, and sharing cool
things I’ve learned as a lens for my future self.</p>
<p>I’m no web dev, so naturally I prioritized a simple, static, stupid
design with monospace fonts and hilariously basic HTML/CSS tricks here
and there. I even built tiny bash scripts: a <code>pandoc</code> wrapper
for turning blog posts from markdown to HTML; an <code>rssgen</code>
script to generate, update, and publish my RSS feed. All of the site
code, of course, tracked with <code>git</code> on my remote VPS with a
<code>post-receive</code> git hook to deploy it to
<code>/srv</code>.</p>
<p>It’s about time that I revisit this site and make it more presentable
to people online. I think of it as my digital version of <em>cleaning up
my room, bucko</em> (🐸).</p>
<p>Some wishlist items on my agenda for tangible differences:</p>
<ul>
<li>Settle on a more elegant and readable font-face across the site
<ul>
<li><code>Poppins</code> for sans-serif, and <code>Jetbrains Mono</code>
for code</li>
</ul></li>
<li>Clean up typesetting with consistent sizing, emphasis, weights,
etc.</li>
<li>Upload my <code>gpg</code> key so that people can download it and
verify my emails and <code>git</code> commits
<ul>
<li><em>Check it out <a href="https://yousef.sh/pgp">here</a></em></li>
</ul></li>
<li>Fix code blocks everywhere, especially my previous blog posts
<ul>
<li>Syntax highlighting</li>
<li>Fix code display issues from <code>pandoc</code> generation</li>
<li>Add copy button</li>
</ul></li>
<li>Blog system revamp
<ul>
<li>Generate an index of blog posts and tags</li>
<li>Searchable</li>
<li>Reading time estimates</li>
</ul></li>
<li>More to come…</li>
</ul>
<h2 id="career-kaizen">💼 Career kaizen</h2>
<p>Self-improvement is a foundational pillar in my life. I’m allergic to
feeling stale and behind, and am constantly looking for ways to improve
my career trajectory. I enjoy it because I’m genuinely passionate in
this field. Learning things like DevOps and system design feels like
gymming for my brain.</p>
<p>One of my favorite feelings is being able to apply skills and
certification knowledge directly in my job as I have done for the past
4-5 years: DevSecOps, Cloud computing, AI (basic stuff), PowerBI, and
more. Apart from the job clout it gives, this feedback loop is really
fulfilling and gives meaning and purpose to my role as Solution
Architect.</p>
<h3 id="chase-the-corporate-bag">💰 Chase the corporate bag</h3>
<p>I’ve been employed at my current job for about 4.5 years now (<a
href="https://yousef.sh/files/resume.pdf">CV</a>). I started out as a
junior/trainee engineer (solutions architect role), and got promoted to
“Senior Engineer” in Feb 2023.</p>
<p>Since then, my role, impact, and scope as an engineer has grown
vastly. This year alone, I’ve achieved these milestones apart from
growing organically as an engineer:</p>
<ul>
<li>Became a lead SPOC DevSecOps engineer, integrating all
systems/applications in our tech stack into our GitLab for automated
CI/CD.</li>
<li>Delivered 93+ change requests (1-3 month SLA) – the highest in my
team.</li>
<li>Delivered hundreds of business-as-usual (BAU) requests (1-3 day
SLA).</li>
<li>Improved our department role’s business impact and value with
PowerBI dashboards for operational monitoring post-go-live.</li>
<li>Spearheaded group-led AI initiative in our DevSecOps ecosystem with
GitLab Duo (first in the region).</li>
<li>And more…</li>
</ul>
<p>With this expanding role and ever-growing list of responsibilities (I
consider myself as doing multiple job descriptions), as well as recent
layoffs in our team (we are down to two engineers – yikes), I think it’s
high time to negotiate a better compensation package.</p>
<p>Starting this year with a bang, I’m demanding getting a better pay
grade, otherwise I’m looking elsewhere because this volume of work is
not sustainable for what I’m currently being paid in the long run –
especially if you consider the additional workload we’re anticipating
this year, my excellent performance last year, and my marital situation
now.</p>
<h3 id="finally-complete-cka-certification">🐳 Finally complete CKA
certification</h3>
<p>Last year I started my journey into learning <a
href="https://k8s.io">Kubernetes</a>. Like any other well-guided
certification path, I aimed to get <strong>CKA</strong> certified to
enrich my role as a <em>GitLab</em> DevSecOps lead engineer, and staying
ahead of the curve as our infrastructure is moving more and more towards
containerization (specifically with <strong>RedHat
OpenShift</strong>).</p>
<p>Alas, life hit me in the face and I fell in love 😅. Marriage and its
obligations made me re-structure my life and priorities. My better half,
of course, took precedence. Fortunately, since things are settling down
and I am getting back into my groove and routine, I have the opportunity
to kickstart my learning journey back up and pursue this
certification.</p>
<p>My goal is to get CKA certified by end of Q1 this year. To keep
myself accountable, I will be blogging about the journey <a
href="https://yousef.sh/posts">here</a>.</p>
<h3 id="learn-rust">🦀 Learn Rust</h3>
<p>Last year I made a concentrated effort at learning
<strong>Go</strong>. I built multiple tools specifically in Go such as
<a href="https://github.com/yousefakbar/o"><code>o</code>, the Obsidian
CLI wrapper</a> and <a
href="https://github.com/yousefakbar/pkm"><code>pkm</code>, my personal
knowledge management tool</a>. Even the backend for the app startup I’m
working on, <strong>KuwaitCare</strong>, is written in Go.</p>
<p>I’ve gained a lot of skills and knowledge by focusing so much of my
effort on learning the programming language through a mix of theory and
project-driven practice with real-world applications that put that
knowledge to the test:</p>
<ul>
<li>Test-Driven Development (TDD)</li>
<li>Error as a first class citizen of a lanugage (error handling in
general)</li>
<li>Building TUIs with Charmbracelet’s <a
href="https://github.com/charmbracelet/bubbletea">BubbleTea
framework</a></li>
<li>Building full-scale backend systems with routing, middleware, JWT
authentication, RBAC authorization, rate-limiting, DB interfacing, and
packaging it with Docker (for k8s in the near future)</li>
</ul>
<p>Building on that momentum, I want to use that same project-driven
learning methodology to the next programming language/framework that has
been on my radar for a long time: <strong>Rust</strong>.</p>
<p>I won’t jump into it blindly. I want to wait for project ideas to
come to me first that I can use as an opportunity to learn and apply
knowledge into Rust.</p>
<p>Ideas are welcome! I’m mostly anticipating another CLI/TUI tool to
implement. Perhaps something to do with homeserver management or
similar.</p>
<h2 id="side-hustles">👨‍🚀 Side hustles</h2>
<p>This year I want to focus more of my free time on open-source
projects I have and side projects I have going on. Some of my open
source projects have gone stale over time and collected dust in the form
of Issues and PR’s on GitHub. However, I’ve made sure to clean those up
recently over the past month or two and I have seen a significant uptick
in their traffic, so it would be a shame not to capitalize on the moment
to build something real and useful to the community.</p>
<h3 id="get-notmuch.nvim-to-100-stars-on-github">⭐ Get
<code>notmuch.nvim</code> to 100+ stars on GitHub</h3>
<p>I wrote my Neovim plugin, <a
href="https://github.com/yousefakbar/notmuch.nvim"><code>notmuch.nvim</code></a>,
back in 2021 during COVID to turn my favorite text editor into a Mail
User Agent (MUA) with basic features.</p>
<p>I left it stale this time last year with a very early release of
<code>v0.1.0</code> with humble and basic features for reading and
sending email from within <code>nvim</code>. Over the past few months it
accrued some issues and feature requests which I have recently tended
to.</p>
<p>Now it is in a really promising position in its early stage where it
can be built into a fully featured mail client with tons of
<code>nvim</code> related features like inspecting, searching, tagging,
sending with attachments, etc. and I am really excited to see it to its
full potential.</p>
<p>I am already working on a <code>v0.2.0</code> release with the
following wishlist:</p>
<ul>
<li>Tons of new features added
<ul>
<li>Examples…</li>
</ul></li>
<li>Add a <code>CHANGELOG</code> and semantic versioning for community
friendly collaboration and updates</li>
<li>Publish more documentation</li>
<li>Publish FAQs for <code>notmuch</code>/Maildir related topics</li>
<li>Record and publish a demo video showcasing the plugin and its
features</li>
<li>Announce to Reddit and other boards for more traction</li>
</ul>
<p>The main goal here for this year is to <strong>get this plugin up to
100+ ⭐ stars</strong> on GitHub (it’s currently at 44 as of writing
this blog post).</p>
<h3 id="roll-out-pkm-first-release">📝 Roll out <code>pkm</code> first
release</h3>
<p>What better way to learn a programming language (in this case Go)
than to implement <em>yet another to-do list manager and notetaking
system</em>? I wrote <a
href="https://github.com/yousefakbar/pkm"><code>pkm</code></a> to make a
“chronological journalling” system where I can externalize my thoughts
and view <em>projects</em> and their evolution over time through the
axis of notes <strong>over time</strong>.</p>
<p>The time component is not to be understated at all. For knowledge
workers like myself, our work environment <strong>demands</strong> that
we adapt dynamically to rapidly changing requirements and decisions from
every channel: meetings, one-on-ones, emails, informal conversations,
overheard insights, etc.</p>
<p>For that reason, I sought to make this CLI (and TUI) app to better
streamline the influx of information in the superhighway that is
knowledge work. Its main idea is to allow you to “view” a
project/topic/tag by displaying a list of notes (gathered information)
over time to better track its evolution.</p>
<p>I won’t go into too many details, or get too dramatically
philosophical, so let me cut to the chase here: if you are familiar with
<a
href="https://fortelabs.com/blog/the-4-notetaking-styles-how-to-choose-a-digital-notes-app-as-your-second-brain/">Tiago
Forte’s 4 Notetaking Styles</a>, this app follows the “Architect”
notetaking style.</p>
<p>I’m planning on releasing a public version of this app soon that
hopefully resonates with people with this idea of time-based knowledge
organization.</p>
<h3 id="launch-kuwaitcare-app-startup">📱 Launch <code>KuwaitCare</code>
app startup</h3>
<p>This one’s a slow burner. For a couple of years now I’ve wanted to
launch an app startup here in Kuwait to provide an app solution for
healthcare/selfcare businesses and their customers.
<code>KuwaitCare</code> is essentially a booking reservation system
offered for self-care establishments (clinics, spas, barbershops,
etc.).</p>
<p>Today these businesses rely on Instagram DM’s to handle reservations,
bookings, questions, etc. This opens up the opportunity of bad faith
business in many ways:</p>
<ul>
<li>Shady impersonator “business” accounts stealing customer info or
funds</li>
<li>Businesses can’t verify authenticity of customer from social
handles</li>
<li>Customers have no gauge of the business due to lack of review
system</li>
<li>No booking timesheet available, it’s all guesswork</li>
<li>Double booking galore</li>
<li>And so much more…</li>
</ul>
<p>This app I’m building is aimed at bridging this gap in the market to
provide a comfortable and seamless experience for both customers and
establishments in the self-care space, which is a booming market
here.</p>
<p>I really want to get this thing to the finish line and complete a
first MVP for it. So far I’ve implemented many huge milestones (mainly
on the backend) and I feel I need to focus much more on the look and
feel this year to get this pushed out to store.</p>
<h2 id="nixify-my-homeserver">❄️ <code>Nix</code>ify my homeserver</h2>
<p>A year or two ago, I took one of my old gaming PC’s hostage, shoved
it in my basement right next to the main home router, installed Ubuntu
Linux, and turned this old PC into a glorified homelab/homeserver.</p>
<p>Currently I run a few really awesome self-hosted services on it:</p>
<ul>
<li>☁️ <a href="https://owncloud.com/"><code>ownCloud</code></a> for
self-hosted cloud storage (De-Google!)</li>
<li>🏴‍☠️ <a
href="https://transmissionbt.com/"><code>Transmission</code></a>
BitTorrent client</li>
<li>📡 <a
href="https://www.commafeed.com/#/welcome"><code>CommaFeed</code></a>
self-hosted feed reader</li>
<li>📺 <a href="https://jellyfin.org/"><code>Jellyfin</code></a>
Plex-like self-hosted content streaming</li>
</ul>
<p>I also use it as a convenient testbed for many projects that I work
on. With Docker and Kubernetes installed on it, it doubles as a useful
tinkering tool and cluster.</p>
<p>One of the things I want to learn this year is <a
href="https://nixos.org/"><code>Nix</code></a>, the declarative
language, operating system, package manager, and system
configurator.</p>
<p>As mentioned before, I learn the most through practical projects
where I can get my hands dirty and apply my skills. This is no
different.</p>
<p>So, I am planning to install <code>NixOS</code> on my homeserver to
turn my messy homeserver into a reproducible, version controlled,
declarative machine.</p>
<h2 id="blog-more">👨‍💻 Blog more</h2>
<p>This blog post takes the first step in doing so. I
<strong>really</strong> enjoy the process of blogging and sharing my
thoughts online, even though I don’t know (or care) who reads this.</p>
<p>I already have a backlog of things I would love to write about. But
on top of that, I’d like to use this microblog to document my journey –
not just in progress updates for the above points, but also in sharing
guides, issues and fixes, frustrations, general journalling/logbooking,
capturing travel moments, and so much more.</p>
<p><strong>A solid metric</strong>: I should keep a tangible goal of
writing <em>at least</em> 1 blog post per month, as a goal to stick to
this year.</p>
<h2 id="final-thoughts">💭 Final thoughts</h2>
<p>If you reached this far, I really appreciate the time you took and
hope I gave some cool insight into my life. Who knows, maybe this
motivates you to start your own blog or personal roadmap to keep
yourself accountable.</p>
<p>Here’s to a beautiful new year filled with exciting moments!</p>]]></description>
    </item>
    <item>
      <title>Bash Reference Guide</title>
      <link>https://yousef.sh/posts/bash-reference-guide.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/bash-reference-guide.html</guid>
      <pubDate>Sat, 30 Aug 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<blockquote>
<p>Changelog:</p>
<p>(2025-08-30): Published initial version</p>
<p>(2025-12-14): Fixed <code>for loop</code> missing <code>in</code>
keyword</p>
</blockquote>
<p>Here is a compendium of reference information regarding
<code>bash</code> (also applies to <code>zsh</code>) for syntatic sugar
that I keep finding myself googling. I’d much rather keep these handy
with me offline to make sure I’m always prepared for quick shell
scripting or issuing complex commands on the go.</p>
<h1 id="if-else-statements"><code>if-else</code> Statements</h1>
<p>The typical <code>if-else</code> statement in <code>bash</code> looks
like this:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="bu">[</span> condition1 <span class="bu">]</span><span class="kw">;</span> <span class="cf">then</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="co"># commands to execute if condition1 is met</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="cf">elif</span> <span class="bu">[</span> condition2 <span class="bu">]</span><span class="kw">;</span> <span class="cf">then</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="co"># commands to execute if condition2 is met</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="co"># commands to execute if none of above conditions are met</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="cf">fi</span></span></code></pre></div>
<h2 id="conditional-operators">Conditional Operators</h2>
<p>Here are common conditional operators that are used in condition
checks</p>
<h3 id="file-operators">File Operators</h3>
<p>These are operators used to check on files</p>
<ul>
<li><code>-e</code>: checks if file exists</li>
<li><code>-f</code>: checks if regular file</li>
<li><code>-d</code>: checks if argument is a directory</li>
<li><code>-s</code>: checks if file is non-empty</li>
<li><code>-r</code>: checks if file is readable</li>
<li><code>-w</code>: checks if file is writable</li>
<li><code>-x</code>: checks if file is executable</li>
</ul>
<p>Keep in mind that these operators are <strong>not</strong> stackable.
If you want to check if a given file is both readable and writable, you
would do something like this:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="bu">[</span> <span class="ot">-r</span> <span class="st">&quot;filename.txt&quot;</span> <span class="bu">]</span> <span class="kw">&amp;&amp;</span> <span class="bu">[</span> <span class="ot">-w</span> <span class="st">&quot;filename.txt ]; then</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="st">    # file is both readable and writable</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="st">fi</span></span></code></pre></div>
<h3 id="string-operators">String Operators</h3>
<p>These are operators used to perform checks on strings</p>
<ul>
<li><code>string</code>: true if the length of <code>string</code> if
non-zero</li>
<li><code>==</code> / <code>=</code> : true if both string operands are
equal</li>
<li><code>!=</code>: true if the string operands are not equal</li>
<li><code>&lt;</code>: true if <code>string1</code> sorts before
<code>string2</code> lexographically</li>
<li><code>&gt;</code>: true if <code>string1</code> sorts after
<code>string2</code> lexographically</li>
<li><code>-eq</code>, <code>-ne</code>, <code>-lt</code>,
<code>-le</code>, <code>-gt</code>, <code>-ge</code>: string arithmetic
checks</li>
</ul>
<h1 id="case-statement-syntax">Case Statement Syntax</h1>
<div class="sourceCode" id="cb3"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="cf">case</span> EXPRESSION <span class="kw">in</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="ss">PATTERN1</span><span class="kw">)</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>        <span class="ex">COMMANDS1</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>        <span class="cf">;;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="ss">PATTERN2</span><span class="kw">)</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>        <span class="ex">COMMANDS2</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>        <span class="cf">;;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="co"># ...and so on...</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>    <span class="pp">*</span><span class="kw">)</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>        <span class="ex">DEFAULT_COMMAMDS</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>        <span class="cf">;;</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="cf">esac</span></span></code></pre></div>
<h1 id="loops">Loops</h1>
<p>There are multiple types of loops in bash scripting depending on the
use case</p>
<h2 id="for-loop"><code>for</code> Loop</h2>
<p>You can do <strong>list-based</strong> iteration like so:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> variable <span class="kw">in</span> item1 item2 item3<span class="kw">;</span> <span class="cf">do</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="co"># commands to execute for each item</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="bu">echo</span> <span class="st">&quot;Reference item with: </span><span class="va">$variable</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="st">done</span></span></code></pre></div>
<p>Or you can do <strong>range-based</strong> iteration:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> {start_idx..end_idx<span class="pp">[</span><span class="ss">..increment</span><span class="pp">]</span>}<span class="kw">;</span> <span class="cf">do</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="co"># commands to execute</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="bu">echo</span> <span class="st">&quot;Current number: </span><span class="va">$i</span><span class="st">&quot;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span></span></code></pre></div>
<p><strong>Note</strong>: C-style syntax also works</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="kw">((</span> <span class="va">i</span><span class="op">=</span><span class="va">start</span><span class="kw">;</span> <span class="va">i</span><span class="op">&lt;=</span><span class="va">end</span><span class="kw">;</span> <span class="va">i</span><span class="op">++</span> <span class="kw">));</span> <span class="cf">do</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="bu">echo</span> <span class="st">&quot;Current number: </span><span class="va">$i</span><span class="st">&quot;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span></span></code></pre></div>
<h2 id="while-loop"><code>while</code> Loop</h2>
<p>This loop runs commands until the condition is no longer met (no
longer true)</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="cf">while</span> <span class="bu">[</span> condition <span class="bu">]</span><span class="kw">;</span> <span class="cf">do</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Commmands to execute</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span></span></code></pre></div>
<p><strong>Note</strong>: You can use the same conditional operators as
seen in the <code>if-else</code> section</p>
<h2 id="until-loop"><code>until</code> Loop</h2>
<p>This loop runs in the inverse logic of the <code>while</code> loop.
It runs <strong>until</strong> the condition is met (becomes true).</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="cf">until</span> <span class="bu">[</span> condition <span class="bu">]</span><span class="kw">;</span> <span class="cf">do</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Commands to execute</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span></span></code></pre></div>
<p><strong>Note</strong>: You can use the same conditional operators as
seen in the <code>if-else</code> section</p>
<h1 id="parameter-expansion">Parameter Expansion</h1>
<p>When invoking parameters and variables in shell scripting, you may
need to transform or manipulate the content in some ways:</p>
<h2 id="basic-expansion">Basic Expansion</h2>
<p>Simple substitution ivolves using <code>$paramter</code> or better
yet <code>${parameter}</code> to substitute the content of the variable
in place.</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="va">myvar</span><span class="op">=</span><span class="st">&quot;hello world&quot;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="bu">echo</span> <span class="st">&quot;</span><span class="va">${myvar}</span><span class="st">&quot;</span> <span class="co"># output: hello world</span></span></code></pre></div>
<h2 id="default-value">Default Value</h2>
<p>You can give a default value for safety if a parameter/variable may
be empty</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="va">${paramater</span><span class="op">:-</span>default<span class="va">}</span> <span class="co"># uses &quot;default&quot; if `parameter` is unset or null</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="va">$(</span><span class="ex">parameter:=default}</span> <span class="co"># same as above but assigns &quot;default&quot; to `parameter`</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">:?</span>default<span class="va">}</span> <span class="co"># displays &quot;default&quot; as an error message and exits if unset</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="va">$(</span><span class="ex">parameter:+default}</span> <span class="co"># uses &quot;default&quot; if `parameter` is set and not null</span></span></code></pre></div>
<h2 id="string-manipulation">String Manipulation</h2>
<p>You can use the following categories of manipulation on strings to
manipulate and transform the output if you want a subset of the string
only</p>
<h3 id="substring-manipulation">Substring Manipulation</h3>
<div class="sourceCode" id="cb11"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">:</span>offset<span class="va">}</span> <span class="co"># extracts substring from `offset` (int)</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">:</span>offset<span class="op">:</span>length<span class="va">}</span> <span class="co"># extracts substring of length `length` from `offset` (int)</span></span></code></pre></div>
<h3 id="remove-prefix">Remove Prefix</h3>
<div class="sourceCode" id="cb12"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">#</span>pattern<span class="va">}</span> <span class="co"># removes the shortest match of `pattern` from the beginning</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">##</span>pattern<span class="va">}</span> <span class="co"># removes the longest match of `pattern` from the beginning</span></span></code></pre></div>
<h3 id="remove-prefix-1">Remove Prefix</h3>
<div class="sourceCode" id="cb13"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">%</span>pattern<span class="va">}</span> <span class="co"># removes the shortest match of `pattern` from the end</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">%%</span>pattern<span class="va">}</span> <span class="co"># removes the longest match of `pattern` from the end</span></span></code></pre></div>
<h3 id="replace-substring">Replace Substring</h3>
<div class="sourceCode" id="cb14"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">/</span><span class="ss">pattern</span><span class="op">/</span>string<span class="va">}</span> <span class="co"># replaces the first match of `pattern` with `string`</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">//</span><span class="ss">pattern</span><span class="op">/</span>string<span class="va">}</span> <span class="co"># replaces all matches of `pattern` with `string`</span></span></code></pre></div>
<h3 id="case-modification">Case Modification</h3>
<div class="sourceCode" id="cb15"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">^</span><span class="ss">pattern</span><span class="va">}</span> <span class="co"># converts the first character of the matched pattern to uppercase</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">^^</span><span class="ss">pattern</span><span class="va">}</span> <span class="co"># converts all characters of the matched pattern to uppercase</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">,</span><span class="ss">pattern</span><span class="va">}</span> <span class="co"># converts the first character of the matched pattern to lowercase</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="va">${parameter</span><span class="op">,,</span><span class="ss">pattern</span><span class="va">}</span> <span class="co"># converts all characters of the matched pattern to lowercase</span></span></code></pre></div>
<h3 id="indirect-expansion">Indirect Expansion</h3>
<div class="sourceCode" id="cb16"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="va">${</span><span class="op">!</span><span class="va">parameter}</span> <span class="co"># uses the value of `parameter` as the name of another variable</span></span></code></pre></div>]]></description>
    </item>
    <item>
      <title>Moving from X to Bluesky</title>
      <link>https://yousef.sh/posts/moving-from-x-to-bluesky.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/moving-from-x-to-bluesky.html</guid>
      <pubDate>Fri, 22 Nov 2024 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>As of today, I’m officially moving away from X (formerly Twitter) and
joining <a href="https://bsky.app/profile/yousef.sh">Bluesky</a>
instead.</p>
<h1 id="reasons-for-moving">Reasons for moving</h1>
<p>The main reasons I did this are the following:</p>
<ol type="1">
<li>X is just way too toxic.</li>
</ol>
<p>Everyone (okay, not every single person) there is looking for a fight
<strong>CONSTANTLY</strong>. After a while it just gets too tiring and
draining.</p>
<ol start="2" type="1">
<li>Too much NSFW content.</li>
</ol>
<p>The platform is littered with “sex tapes” and “leaked scandals”.
Hell, I can’t even open a post without being bombarded with promoted ads
that are NSFW.</p>
<blockquote>
<p>inb4 iT’s yOuR aLgOriTHm BrO, iT aDjUsTs tO yOuR pReFeReNcEs
hurr.</p>
</blockquote>
<ol start="3" type="1">
<li>Bot situation is out of control.</li>
</ol>
<p>There is no sort of regular discussion anymore. Replies to posts are
filled with nonsensical content promoting irrelevant memecoins, scammy
courses, and attention-seeking social-engineering bots. It all feels
fake and plastic.</p>
<ol start="4" type="1">
<li>Misinformation</li>
</ol>
<p>The last U.S. election was a damning red flag fest, with the amount
of casual misinformation and fake news posted unfettered. Sure,
community notes are there, but it’s not helpful when the <a
href="https://en.wikipedia.org/wiki/Benevolent_dictator_for_life">BDFL</a>
of X <a
href="https://x.com/elonmusk/status/1859483544612913376">casually posts
fake news</a> on the regular and the damage is already done.</p>
<p>Elon’s toy project does not spell well for the future of Internet
users. It is now a disservice to humanity, in my opinion.</p>
<h1 id="follow-me">Follow me!</h1>
<p>Anyway, come join and you can follow me on Bluesky if you like my
content and want to connect. I’d love to see more people join. Make sure
you come say hi! :-).</p>
<p><a href="https://bsky.app/profile/yousef.sh">Yousef on
Bluesky</a></p>]]></description>
    </item>
    <item>
      <title>SQL Self Training Notes</title>
      <link>https://yousef.sh/posts/sql-basic-notes.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/sql-basic-notes.html</guid>
      <pubDate>Fri, 15 Nov 2024 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>This is the self learning phase notes of the SQL database management
system language.</p>
<p>You can consider this is a compilation of basic, intro-level notes to
SQL. It is not comprehensive nor is it “in-depth”.</p>
<p>If you feel there is anything missing, wrong, or worthy of addition,
please feel free to <a href="mailto:yousef@yhakbar.com">reach out</a>
and open a discussion.</p>
<p>The link to the training is found below:</p>
<p><a
href="https://www.freecodecamp.org/news/sql-and-databases-full-course">SQL
and Databases - A Full Course for Beginners</a></p>
<h1 id="material-covered">Material Covered</h1>
<p>Broadly speaking, it will cover: Schema design,
Create-Read-Update-Delete operations (CRUD), and database
fundamentals.</p>
<ul>
<li>What a database is</li>
<li>Tables and Keys</li>
<li>SQL Basics</li>
<li>MySQL Windows/Mac Installation</li>
<li>Creating Tables</li>
<li>Inserting Data</li>
<li>Constraints</li>
<li>Update &amp; Delete</li>
<li>Basic Queries</li>
<li>Company Database Intro</li>
<li>Creating Company Database</li>
<li>More Basic Queries</li>
<li>Functions</li>
<li>Wildcards</li>
<li>Unions</li>
<li>Joins</li>
<li>Nested Queries</li>
<li>On Delete</li>
<li>Triggers</li>
<li>ER Diagrams</li>
</ul>
<h1 id="what-is-a-database">What is a database</h1>
<p>A database is any collection of related information like a phone
book, shopping list, todo list, user base, list of transactions.</p>
<p>We typically store these in computers using a relational database. We
use a structured query language (SQL) to interact with that
database.</p>
<h2 id="database-management-systems-dbms">Database Management Systems
(DBMS)</h2>
<p>Special software program that helps users maintain a database.</p>
<p>Handles managing large amounts of information, security, backups,
importing/exporting, concurrency, etc.</p>
<h3 id="c.r.u.d.-operations">C.R.U.D. Operations</h3>
<p>Performs the CRUD operations:</p>
<ul>
<li>Create</li>
<li>Read</li>
<li>Update</li>
<li>Delete</li>
</ul>
<h2 id="types-of-databases">Types of databases</h2>
<h3 id="relational-dabatabases-sql">Relational Dabatabases (SQL)</h3>
<p>Organizes data into <strong>tables</strong> with rows and columns</p>
<p>Rows are identified using <strong>unique keys</strong>.</p>
<p>Examples:</p>
<ul>
<li>mySQL</li>
<li>Oracle</li>
<li>PostgreSQL</li>
<li>MariaDB</li>
</ul>
<h3 id="non-relational-dabatabases-non-sql">Non-Relational Dabatabases
(Non-SQL)</h3>
<p>“Anything but a traditional table”</p>
<p>Organizes data in less structured form.</p>
<p>Typically uses things like key-value stores (JSON), Documents,
Graphs, etc.</p>
<p>Examples:</p>
<ul>
<li>MongoDB</li>
<li>DynamoDB</li>
<li>Apache Cassandra</li>
<li>Firebase</li>
</ul>
<p>Implementation specific: Each implementation uses its own DBMS to
handle its own storage structure</p>
<h1 id="database-queries">Database Queries</h1>
<p>Queries are simply requests made from a user of application to the
database management system asking for speicific information matching a
criteria.</p>
<h1 id="tables-and-keys">Tables and Keys</h1>
<dl>
<dt>Surrogate Key</dt>
<dd>
A <strong>unique key</strong> which has no real world meaning or value
(e.g. randomly generated, unique, number to identify employees).
</dd>
<dt>Natural Key</dt>
<dd>
A <strong>unique key</strong> which has real world mapping
(e.g. employee SSN, or citizen national ID number).
</dd>
<dt>Foreign Key</dt>
<dd>
A attribute key which is used to link one table to another table. A
foreign key is considered a primary key for the table that it links to.
</dd>
<dt>Composite Key</dt>
<dd>
A unique key that is made up of 2 or more attributes (ie. ID + name).
</dd>
</dl>
<h1 id="sql-basics">SQL Basics</h1>
<p>SQL is a language used for intercting with Relational Database
Management Systems (RDBMS).</p>
<p>SQL is a hybrid of 4 types of languages:</p>
<ul>
<li>Data Query Language (DQL)
<ul>
<li>Query database for information</li>
</ul></li>
<li>Data Definition Language (DDL)
<ul>
<li>Defining database schemas</li>
</ul></li>
<li>Data Control Language (DCL)
<ul>
<li>Controlling access to the data in the database</li>
</ul></li>
<li>Data Manipulation Language (DML)
<ul>
<li>CRUD manipulation for updating database entries</li>
</ul></li>
</ul>
<h2 id="queries">Queries</h2>
<p>A query is one or more criteria given to the RDBMS as an instruction
to retrieve specific information from the database</p>
<h2 id="data-types">Data Types</h2>
<ul>
<li>INT</li>
<li>DECIMAL</li>
<li>VARCHAR(l) : String of length <code>l</code></li>
<li>BLOB : Binary large object, stores large data</li>
<li>DATE : YYYY-MM-DD</li>
<li>TIMESTAMP : YYYY-MM-DD HH:MM:SS</li>
</ul>
<h2 id="keywords">Keywords</h2>
<ul>
<li>DEFAULT for default values</li>
<li>AUTO_INCREMENT for setting PK without explicitly typing</li>
<li>NOT NULL does not allow empty values</li>
<li>UNIQUE prevents duplicates</li>
</ul>
<blockquote>
<p>Primary key is essentially just an INT with both UNIQUE and NOT NULL
properties</p>
</blockquote>
<h2 id="update">UPDATE</h2>
<p>To update values of rows in the table:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">UPDATE</span> student</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">SET</span> major <span class="op">=</span> <span class="st">&#39;Biochemistry&#39;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">WHERE</span> major <span class="op">=</span> <span class="st">&#39;Bio&#39;</span> <span class="kw">OR</span> major <span class="op">=</span> <span class="st">&#39;Chemistry&#39;</span></span></code></pre></div>
<h2 id="delete">DELETE</h2>
<p>To delete a certain row/entry from a table:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Deletes all entries where name is &#39;Tom&#39; with undecided major</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">DELETE</span> <span class="kw">FROM</span> student</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">WHERE</span> name <span class="op">=</span> <span class="st">&#39;Tom&#39;</span> <span class="kw">AND</span> major <span class="op">=</span> <span class="st">&#39;undecided&#39;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- To delete all entries from the table</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="kw">DELETE</span> <span class="kw">FROM</span> student</span></code></pre></div>
<h2 id="select">SELECT</h2>
<p>Retrieve all rows in the table:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Retrieves all columns from the `students` table (all entries)</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> student;</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- Select only the id and name in alphabetical order</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> student_id, name</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> student</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="kw">ORDER</span> <span class="kw">BY</span> name <span class="kw">DESC</span>;</span></code></pre></div>
<h1 id="company-database-example">Company Database Example</h1>
<h2 id="questions">Questions</h2>
<p>Difference between:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">SET</span> <span class="kw">NULL</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">CASCADE</span></span></code></pre></div>
<p>In this tutorial chapter we set up the company database for the
office with the tables for employee, branch, client, works_with, and
branch_supplier.</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Employee table</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">CREATE</span> <span class="kw">TABLE</span> employee (</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    emp_id <span class="dt">INT</span> <span class="kw">PRIMARY</span> <span class="kw">KEY</span>,</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    first_name <span class="dt">VARCHAR</span>(<span class="dv">40</span>),</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    last_name <span class="dt">VARCHAR</span>(<span class="dv">40</span>),</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    birth_day <span class="dt">DATE</span>,</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    sex <span class="dt">VARCHAR</span>(<span class="dv">1</span>),</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    salary <span class="dt">INT</span>,</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    super_id <span class="dt">INT</span>,</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>    branch_id <span class="dt">INT</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>DESCRIBE employee;</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> employee;</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Branch table</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="kw">CREATE</span> <span class="kw">TABLE</span> branch (</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>    branch_id <span class="dt">INT</span> <span class="kw">PRIMARY</span> <span class="kw">KEY</span>,</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>    branch_name <span class="dt">VARCHAR</span>(<span class="dv">40</span>),</span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>    mgr_id <span class="dt">INT</span>,</span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>    mgr_start_date <span class="dt">DATE</span>,</span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FOREIGN</span> <span class="kw">KEY</span>(mgr_id) <span class="kw">REFERENCES</span> employee(emp_id) <span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">SET</span> <span class="kw">NULL</span> </span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a>DESCRIBE branch;</span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> branch</span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a><span class="co">-- Add branch_id foreign key to employee</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a><span class="kw">ALTER</span> <span class="kw">TABLE</span> employee</span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true" tabindex="-1"></a><span class="kw">ADD</span> <span class="kw">FOREIGN</span> <span class="kw">KEY</span>(branch_id)</span>
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true" tabindex="-1"></a><span class="kw">REFERENCES</span> branch(branch_id)</span>
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true" tabindex="-1"></a><span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">SET</span> <span class="kw">NULL</span>;</span>
<span id="cb5-31"><a href="#cb5-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-32"><a href="#cb5-32" aria-hidden="true" tabindex="-1"></a><span class="kw">ALTER</span> <span class="kw">TABLE</span> employee</span>
<span id="cb5-33"><a href="#cb5-33" aria-hidden="true" tabindex="-1"></a><span class="kw">ADD</span> <span class="kw">FOREIGN</span> <span class="kw">KEY</span>(super_id)</span>
<span id="cb5-34"><a href="#cb5-34" aria-hidden="true" tabindex="-1"></a><span class="kw">REFERENCES</span> employee(emp_id)</span>
<span id="cb5-35"><a href="#cb5-35" aria-hidden="true" tabindex="-1"></a><span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">SET</span> <span class="kw">NULL</span>;</span>
<span id="cb5-36"><a href="#cb5-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-37"><a href="#cb5-37" aria-hidden="true" tabindex="-1"></a><span class="co">-- Client table</span></span>
<span id="cb5-38"><a href="#cb5-38" aria-hidden="true" tabindex="-1"></a><span class="kw">CREATE</span> <span class="kw">TABLE</span> client (</span>
<span id="cb5-39"><a href="#cb5-39" aria-hidden="true" tabindex="-1"></a>    client_id <span class="dt">INT</span> <span class="kw">PRIMARY</span> <span class="kw">KEY</span>,</span>
<span id="cb5-40"><a href="#cb5-40" aria-hidden="true" tabindex="-1"></a>    client_name <span class="dt">VARCHAR</span>(<span class="dv">40</span>),</span>
<span id="cb5-41"><a href="#cb5-41" aria-hidden="true" tabindex="-1"></a>    branch_id <span class="dt">INT</span>,</span>
<span id="cb5-42"><a href="#cb5-42" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FOREIGN</span> <span class="kw">KEY</span>(branch_id) <span class="kw">REFERENCES</span> branch(branch_id) <span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">SET</span> <span class="kw">NULL</span> </span>
<span id="cb5-43"><a href="#cb5-43" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb5-44"><a href="#cb5-44" aria-hidden="true" tabindex="-1"></a>DESCRIBE client;</span>
<span id="cb5-45"><a href="#cb5-45" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> client;</span>
<span id="cb5-46"><a href="#cb5-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-47"><a href="#cb5-47" aria-hidden="true" tabindex="-1"></a><span class="co">-- Works_with table</span></span>
<span id="cb5-48"><a href="#cb5-48" aria-hidden="true" tabindex="-1"></a><span class="kw">CREATE</span> <span class="kw">TABLE</span> works_with (</span>
<span id="cb5-49"><a href="#cb5-49" aria-hidden="true" tabindex="-1"></a>    emp_id <span class="dt">INT</span>,</span>
<span id="cb5-50"><a href="#cb5-50" aria-hidden="true" tabindex="-1"></a>    client_id <span class="dt">INT</span>,</span>
<span id="cb5-51"><a href="#cb5-51" aria-hidden="true" tabindex="-1"></a>    total_sales <span class="dt">INT</span>,</span>
<span id="cb5-52"><a href="#cb5-52" aria-hidden="true" tabindex="-1"></a>    <span class="kw">PRIMARY</span> <span class="kw">KEY</span>(emp_id, client_id),</span>
<span id="cb5-53"><a href="#cb5-53" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FOREIGN</span> <span class="kw">KEY</span>(emp_id) <span class="kw">REFERENCES</span> employee(emp_id) <span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">CASCADE</span>,</span>
<span id="cb5-54"><a href="#cb5-54" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FOREIGN</span> <span class="kw">KEY</span>(client_id) <span class="kw">REFERENCES</span> client(client_id) <span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">CASCADE</span></span>
<span id="cb5-55"><a href="#cb5-55" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb5-56"><a href="#cb5-56" aria-hidden="true" tabindex="-1"></a>DESCRIBE works_with;</span>
<span id="cb5-57"><a href="#cb5-57" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> works_with;</span>
<span id="cb5-58"><a href="#cb5-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-59"><a href="#cb5-59" aria-hidden="true" tabindex="-1"></a><span class="co">-- Branch supplier table</span></span>
<span id="cb5-60"><a href="#cb5-60" aria-hidden="true" tabindex="-1"></a><span class="kw">CREATE</span> <span class="kw">TABLE</span> branch_supplier (</span>
<span id="cb5-61"><a href="#cb5-61" aria-hidden="true" tabindex="-1"></a>    branch_id <span class="dt">INT</span>,</span>
<span id="cb5-62"><a href="#cb5-62" aria-hidden="true" tabindex="-1"></a>    supplier_name <span class="dt">VARCHAR</span>(<span class="dv">40</span>),</span>
<span id="cb5-63"><a href="#cb5-63" aria-hidden="true" tabindex="-1"></a>    supply_type <span class="dt">VARCHAR</span>(<span class="dv">40</span>),</span>
<span id="cb5-64"><a href="#cb5-64" aria-hidden="true" tabindex="-1"></a>    <span class="kw">PRIMARY</span> <span class="kw">KEY</span>(branch_id, supplier_name),</span>
<span id="cb5-65"><a href="#cb5-65" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FOREIGN</span> <span class="kw">KEY</span>(branch_id) <span class="kw">REFERENCES</span> branch(branch_id) <span class="kw">ON</span> <span class="kw">DELETE</span> <span class="kw">CASCADE</span></span>
<span id="cb5-66"><a href="#cb5-66" aria-hidden="true" tabindex="-1"></a>);</span>
<span id="cb5-67"><a href="#cb5-67" aria-hidden="true" tabindex="-1"></a>DESCRIBE branch_supplier;</span>
<span id="cb5-68"><a href="#cb5-68" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> branch_supplier;</span>
<span id="cb5-69"><a href="#cb5-69" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-70"><a href="#cb5-70" aria-hidden="true" tabindex="-1"></a><span class="co">-- Insert Corporate office employees</span></span>
<span id="cb5-71"><a href="#cb5-71" aria-hidden="true" tabindex="-1"></a><span class="kw">INSERT</span> <span class="kw">INTO</span> employee <span class="kw">VALUES</span>(<span class="dv">100</span>, <span class="st">&#39;David&#39;</span>, <span class="st">&#39;Wallace&#39;</span>, <span class="st">&#39;1967-11-17&#39;</span>, <span class="st">&#39;M&#39;</span>, <span class="dv">25000</span>, <span class="kw">NULL</span>, <span class="kw">NULL</span>);</span>
<span id="cb5-72"><a href="#cb5-72" aria-hidden="true" tabindex="-1"></a><span class="kw">INSERT</span> <span class="kw">INTO</span> branch <span class="kw">VALUES</span>(<span class="dv">1</span>, <span class="st">&#39;Corporate&#39;</span>, <span class="dv">100</span>, <span class="st">&#39;2006-02-09&#39;</span>);</span>
<span id="cb5-73"><a href="#cb5-73" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-74"><a href="#cb5-74" aria-hidden="true" tabindex="-1"></a><span class="kw">UPDATE</span> employee</span>
<span id="cb5-75"><a href="#cb5-75" aria-hidden="true" tabindex="-1"></a><span class="kw">SET</span> branch_id <span class="op">=</span> <span class="dv">1</span></span>
<span id="cb5-76"><a href="#cb5-76" aria-hidden="true" tabindex="-1"></a><span class="kw">WHERE</span> emp_id <span class="op">=</span> <span class="dv">100</span>;</span>
<span id="cb5-77"><a href="#cb5-77" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-78"><a href="#cb5-78" aria-hidden="true" tabindex="-1"></a><span class="kw">INSERT</span> <span class="kw">INTO</span> employee <span class="kw">VALUES</span>(<span class="dv">101</span>, <span class="st">&#39;Jan&#39;</span>, <span class="st">&#39;Levinson&#39;</span>, <span class="st">&#39;1961-05-11&#39;</span>, <span class="st">&#39;F&#39;</span>, <span class="dv">110000</span>, <span class="dv">100</span>, <span class="dv">1</span>);</span></code></pre></div>
<h1 id="more-basic-queries">More Basic Queries</h1>
<ul>
<li>SELECT &lt;attributes&gt; vs. *</li>
<li>SELECT &lt;attribute&gt; AS &lt;alias&gt;</li>
<li>SELECT DISTINCT &lt;attribute&gt;</li>
<li>ORDER BY</li>
<li>LIMIT</li>
</ul>
<h1 id="functions">Functions</h1>
<ul>
<li>SELECT COUNT(&lt;attribute&gt;) to find number of entries there
are</li>
<li>SELECT AVG(&lt;attribute&gt;) to find the average of entries</li>
<li>SELECT SUM(&lt;attribute&gt;) to find the sum of entries</li>
<li>GROUP BY &lt;attribute&gt; to aggregate function results by
attribute</li>
</ul>
<h1 id="wildcards">Wildcards</h1>
<ul>
<li>% = any</li>
<li>_ = one character</li>
<li>LIKE</li>
</ul>
<div class="sourceCode" id="cb6"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Find any clients who are an LLC</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> client</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">WHERE</span> client_name <span class="kw">LIKE</span> <span class="st">&#39;%LLC&#39;</span>;</span></code></pre></div>
<div class="sourceCode" id="cb7"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Find any employee born in October</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> employee</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">WHERE</span> birth_date <span class="kw">LIKE</span> <span class="st">&#39;____-10%&#39;</span>;</span></code></pre></div>
<h1 id="union">Union</h1>
<dl>
<dt>Union</dt>
<dd>
A special operator used to combine the result of two or more search
criteria.
</dd>
</dl>
<div class="sourceCode" id="cb8"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Find a list of employee first names and branch names</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> first_name</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> employee</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">UNION</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> branch_name</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> branch;</span></code></pre></div>
<p>&gt; Note: Unions assert that each combined criteria is using the
same number of &gt; columns in the SELECT part</p>
<h1 id="joins">Joins</h1>
<dl>
<dt>Join</dt>
<dd>
Operator used to combine rows from two or more tables based on a related
attribute between them
</dd>
</dl>
<div class="sourceCode" id="cb9"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Find all branches and the names of their managers</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> employee.emp_id, employee.first_name, branch.branch_name</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> employee</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="kw">JOIN</span> branch</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="kw">ON</span> employee.emp_id <span class="op">=</span> branch.mgr_id;</span></code></pre></div>
<dl>
<dt>LEFT JOIN</dt>
<dd>
Includes all entries in the LEFT table (FROM &lt;table&gt;) in the
output of the JOIN
</dd>
<dt>RIGHT JOIN</dt>
<dd>
Includes all entries in the RIGHT table (JOIN &lt;table&gt;) in the
output of the JOIN
</dd>
</dl>
<h1 id="nested-queries">Nested Queries</h1>
<p>Using multiple <code>SELECT</code> statements to get specific
information.</p>
<p>Nest another <code>SELECT</code> statement after <code>WHERE</code>
statement</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Find names of all employees who have sold over 30,000 to a single client</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> employee.first_name, employee.last_name</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> employee</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">WHERE</span> employee.emp_id <span class="kw">IN</span> (</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">SELECT</span> works_with.emp_id</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FROM</span> works_with</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">WHERE</span> works_with.total_sales <span class="op">&gt;</span> <span class="dv">30000</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>);</span></code></pre></div>
<h1 id="on-delete">On Delete</h1>
<p>Determines how deleted entries update onto other tables with foreign
keys.</p>
<h2 id="set-null">SET NULL</h2>
<p>When one entry is deleted, it sets the foreign key in other tables
pointing to that entry to NULL.</p>
<h2 id="cascade">CASCADE</h2>
<p>When one entry is deleted, it also deletes the entries in other
tables where the deleted entry is the foreign key.</p>
<p>Typically, we use CASCADE when the foreign key is part of the primary
key for the relevant table (because a primary key cannot have a NULL
value).</p>
<h1 id="triggers">Triggers</h1>
<p>A piece of code that defines a certain action that should occur when
another event/operation takes place.</p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>DELIMITER $$</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">CREATE</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">TRIGGER</span> my_trigger <span class="kw">BEFORE</span> <span class="kw">INSERT</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">ON</span> employee</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">FOR</span> <span class="kw">EACH</span> <span class="kw">ROW</span> <span class="cf">BEGIN</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">INSERT</span> <span class="kw">INTO</span> trigger_test <span class="kw">VALUES</span>(<span class="st">&#39;added new employee&#39;</span>);</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    END$$</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>DELIMITER ;</span></code></pre></div>
<h1 id="entity-relationship-er">Entity Relationship (ER)</h1>
<p>ER diagrams are a way to visually map out the schema, the relations
between its tables and attributes.</p>
<dl>
<dt>Entity</dt>
<dd>
Object we want to model and store information about
</dd>
<dt>Attributes</dt>
<dd>
Specific pieces of information about an entity. These are going to be
the attributes or columns in tables
</dd>
<dt>Primary Key</dt>
<dd>
Attribute taht uniquely identify an entry in the database table
</dd>
<dt>Composite attribute</dt>
<dd>
Attribute that can be broken up into two or more sub-attributes
</dd>
<dt>Multi-valued attribute</dt>
<dd>
An attribute that can have more than one value
</dd>
<dt>Derived attribute</dt>
<dd>
Attribute that can be derived from other attributes. Does not go into
the actual table but is used for visual convenience
</dd>
<dt>Relationships</dt>
<dd>
Defines a relationship between two entities to describe how they relate.
Denoted by “Takes” or “Taken by”
</dd>
<dt>Cardinality</dt>
<dd>
1:1, 1:N, N:M referring to how the relationships act (ie. one side is
connected to many of another side, etc.)
</dd>
<dt>Weak Entity</dt>
<dd>
Entity that cannot be uniquely identified by its attributes alone. It
needs to be expressed using attributes of another entity as well
</dd>
</dl>
<h1 id="mapping-er-to-schema">Mapping ER to Schema</h1>
<ol type="1">
<li><p>Mapping regular entities entity types -&gt; Create
tables</p></li>
<li><p>Mapping of weak entity types -&gt; Create a relation
table</p></li>
<li><p>Mapping of binary 1:1 relationship types -&gt; Foreign
keys</p></li>
<li><p>Mapping of binary 1:N relationship types -&gt; 1 sides PK as FK
of N side</p></li>
<li><p>Mapping of binary N:M relationship types -&gt; Create a new table
whose PK is combination of each side’s PK</p></li>
</ol>]]></description>
    </item>
    <item>
      <title>SAP MDEP Introduction</title>
      <link>https://yousef.sh/posts/sap-mdep-introduction.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/sap-mdep-introduction.html</guid>
      <pubDate>Thu, 17 Oct 2024 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>Today marks the kick off of the SAP Multi-Dimensional Engineer
Program (MDEP) where engineers who passed the selection process are
onboarded to the program.</p>
<p>We received introductions to the mentors, the program, and the
curriculum we will be expected to learn in the next two months.</p>
<p>Below is the notes I took during the meeting for future
reference.</p>
<p>Overall I am super proud and excited to be in this program. It looks
super insightful, and aligns exactly with my ambitions of empowering not
only my technical skills, but also my soft skills to better myself as an
engineer.</p>
<h1 id="multi-dimensional-experience">Multi-Dimensional Experience</h1>
<ul>
<li><p>Program is specially designed for mixing top-notch technology
skills with social and soft skills.</p></li>
<li><p>Pushes you out of your comfort zone to instill a real lasting
education.</p></li>
<li><p>Explore Silicon Valley culture.</p></li>
<li><p>Exclusive opportunities to visit institutions and universities
and bright minds.</p></li>
<li><p>Opportunity to network and build ties in the community.</p></li>
</ul>
<h1 id="program-structure">Program Structure</h1>
<p>The program has 5 phases:</p>
<pre><code>Selection -&gt; [Kickoff] -&gt; Self learning phase -&gt; In person phase -&gt; Graduation</code></pre>
<ul>
<li>2 months of Hybrid Learning Experience
<ul>
<li>Phase 1: 1 month of self learning phase</li>
<li>Onboarding workshop in Riyadh (Bring laptop with you)</li>
<li>Phase 2: 1 month of in person learning full time in the USA</li>
</ul></li>
</ul>
<blockquote>
<p>TODO: Apply for visa as soon as possible</p>
</blockquote>
<h1 id="mdep-curriculum">MDEP Curriculum</h1>
<p>As mentioned, the MDEP is split into two halves of the curriculum:
technical and soft skills.</p>
<h2 id="technology-stack">Technology Stack</h2>
<ul>
<li>SAP products overview: S4 HANA, SuccessFactors, Business Networks,
and more</li>
<li>SAP Business Technology Platform</li>
<li>SAP analytics Cloud</li>
<li>Application Development using SAP Build, SAP CAP</li>
<li>Machine Learning and GenAI</li>
<li>Agile Methodology</li>
<li>Cybersecurity</li>
<li>UX Design</li>
<li>First principles thinking &amp; systems thinking</li>
</ul>
<h2 id="multi-disciplinary-stack">Multi-Disciplinary Stack</h2>
<ul>
<li>Cross cultural intelligence</li>
<li>Purpose Driven Leadership</li>
<li>Effective Storytelling and Communication</li>
<li>Personality assessment workship</li>
<li>Thought leadership sessions</li>
<li>Community building and hackathon</li>
<li>Art of Journaling and Reflections</li>
</ul>
<h1 id="self-learning-topics">Self Learning Topics</h1>
<p>The technology stack self-learning takes about 24 hours to complete
in total.</p>
<ul>
<li>NodeJS (8 hours)</li>
<li>SQL (4 hours)</li>
<li>ERP Business Process (12 hours)</li>
<li>Hackathon for testing our skills and teamwork.</li>
</ul>
<h2 id="digital-badges-and-completion-certificates">Digital Badges and
Completion Certificates</h2>
<ul>
<li>Digital Badge (LinkedIn and other social media)</li>
<li>Graduation Certificate (Hard copy certificate of completion)</li>
</ul>
<h1 id="important-updates">Important Updates</h1>
<ul>
<li>Apply for VISA ASAP.
<ul>
<li>B1/B2 visa.</li>
</ul></li>
<li>COVID Protocols.</li>
</ul>]]></description>
    </item>
    <item>
      <title>Hash Fast, Bash Smart</title>
      <link>https://yousef.sh/posts/hash-in-bash.html</link>
      <guid isPermaLink="true">https://yousef.sh/posts/hash-in-bash.html</guid>
      <pubDate>Mon, 14 Oct 2024 00:00:00 +0000</pubDate>
      <description><![CDATA[<p><a
href="https://www.gnu.org/software/bash/manual/bash.html#index-hash"><code>hash</code></a>
is a useful built-in shell command used for caching commands/executables
from your <code>$PATH</code> variable. This helps bash/zsh avoid having
to rescan your <code>PATH</code> each time you enter a command during
the <a
href="https://www.gnu.org/software/bash/manual/bash.html#:~:text=Bash%20uses%20a%20hash%20table%20to%20remember%20the%20full%20pathnames%20of%20executable%20files%20to%20avoid%20multiple%20PATH%20searches%20(see%20the%20description%20of%20hash%20in%20Bourne%20Shell%20Builtins).">find
and execution process</a>.</p>
<p>This command is great for resetting/regenerating the
<code>PATH</code> commands cache with the <code>-r</code> flag. For
example, python3’s <code>virtualenv</code> uses this to manage your
command cache after activating and deactivating your virtual
environment.</p>
<pre><code>hash -r 2&gt; /dev/null</code></pre>
<p>This snippet runs <code>hash</code> with <code>-r</code> flag to
“reset” the commands cache. Error/logging is discarded to /dev/null for
quiet execution.</p>
<blockquote>
<p><strong>Note</strong>: Running <code>hash</code> alone just prints
out the current command cache list</p>
</blockquote>
<h2 id="use-cases">Use Cases</h2>
<ul>
<li>(Shown above) Quickly recaching your commands after (de)activating
virtualenv</li>
<li>Moving, renaming, or deleting a command: Reflect its non-existence
with <code>-r</code></li>
<li>Installing a package/binary: Quickly recache to shell with
<code>hash -r</code></li>
<li>After adding a new directory into <code>PATH</code> and wanting to
index its commands</li>
</ul>
<p>To learn a bit more about <code>hash</code>, check out the <a
href="https://www.gnu.org/software/bash/manual/bash.html#index-hash">bash
manual entry</a>.</p>]]></description>
    </item>
  </channel>
</rss>
