<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>j-riv</title>
  <subtitle>Personal site of José Rivera — Full-Stack Developer working across Shopify, NetSuite, Node.js, and AWS.</subtitle>
  <link href="https://j-riv.com/feed.xml" rel="self"/>
  <link href="https://j-riv.com/"/>
  <updated>2026-08-28T00:00:00Z</updated>
  <id>https://j-riv.com/</id>
  <author><name>José Alfredo Rivera Turcios</name></author>
  
  <entry>
    <title>Pi Cluster Rebuild Guide</title>
    <link href="https://j-riv.com/blog/posts/2026-08-28-pi-cluster-rebuild-guide/"/>
    <updated>2026-08-28T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2026-08-28-pi-cluster-rebuild-guide/</id>
    <content type="html">&lt;p&gt;This is my reference for rebuilding my five-node Raspberry Pi 4 k3s cluster from scratch.&lt;/p&gt;
&lt;p&gt;The cluster consists of five Raspberry Pi 4s with 8 GB of RAM each: one control-plane node and four workers. It runs Ubuntu Server 26.04 LTS, k3s, Rancher, Helm, and cert-manager.&lt;/p&gt;
&lt;p&gt;I&#39;m documenting the entire process here mostly so the next time I inevitably break or rebuild the cluster, I don&#39;t have to figure everything out again.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/raspberry-pi-4-five-node-rack-mounted-cluster-400w-tTqyX_JtDd.webp 400w, https://j-riv.com/img/raspberry-pi-4-five-node-rack-mounted-cluster-800w-tTqyX_JtDd.webp 800w, https://j-riv.com/img/raspberry-pi-4-five-node-rack-mounted-cluster-1200w-tTqyX_JtDd.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/raspberry-pi-4-five-node-rack-mounted-cluster-400w-tTqyX_JtDd.jpeg&quot; alt=&quot;Raspberry Pi 4 Five-Node Rack Mounted Cluster&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1499&quot; srcset=&quot;https://j-riv.com/img/raspberry-pi-4-five-node-rack-mounted-cluster-400w-tTqyX_JtDd.jpeg 400w, https://j-riv.com/img/raspberry-pi-4-five-node-rack-mounted-cluster-800w-tTqyX_JtDd.jpeg 800w, https://j-riv.com/img/raspberry-pi-4-five-node-rack-mounted-cluster-1200w-tTqyX_JtDd.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Raspberry Pi 4 Five-Node Rack Mounted Cluster&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Nodes:&lt;/strong&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; max-width: 600px;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ccc; padding: 8px 16px; text-align: left; background: #666; color: #fff;&quot;&gt;Hostname&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ccc; padding: 8px 16px; text-align: left; background: #666; color: #fff;&quot;&gt;IP&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ccc; padding: 8px 16px; text-align: left; background: #666; color: #fff;&quot;&gt;Role&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;k3s-master&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;xxx.xx.x.80&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;control-plane&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;k3s-worker-01&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;xxx.xx.x.81&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;worker&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;k3s-worker-02&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;xxx.xx.x.82&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;worker&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;k3s-worker-03&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;xxx.xx.x.83&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;worker&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;k3s-worker-04&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;xxx.xx.x.84&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ccc; padding: 8px 16px;&quot;&gt;worker&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use the same username on all nodes: &lt;code&gt;ubuntu&lt;/code&gt; or whatever you set during imaging (e.g., &lt;code&gt;jriv&lt;/code&gt;)&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;1. Image the OS (per node)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Download &lt;strong&gt;Raspberry Pi Imager&lt;/strong&gt; from raspberrypi.com/software&lt;/li&gt;
&lt;li&gt;Insert SD card / storage for the node&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choose OS&lt;/strong&gt; → &lt;strong&gt;Other general-purpose OS&lt;/strong&gt; → &lt;strong&gt;Ubuntu&lt;/strong&gt; → &lt;strong&gt;Ubuntu Server 26.04 LTS (64-bit)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choose Storage&lt;/strong&gt; → select the correct device.&lt;/li&gt;
&lt;li&gt;Click the gear/advanced settings icon before writing:
&lt;ul&gt;
&lt;li&gt;Set unique &lt;strong&gt;hostname&lt;/strong&gt; (&lt;code&gt;k3s-master&lt;/code&gt;, &lt;code&gt;k3s-worker-01&lt;/code&gt;, &lt;code&gt;k3s-worker-02&lt;/code&gt;, &lt;code&gt;k3s-worker-03&lt;/code&gt;, &lt;code&gt;k3s-worker-04&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;username&lt;/strong&gt;: &lt;code&gt;ubuntu&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enable SSH, add your public key or set a password for the &lt;code&gt;ubuntu&lt;/code&gt; user&lt;/li&gt;
&lt;li&gt;Set WiFi/locale if not using Ethernet&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Write the image&lt;/li&gt;
&lt;li&gt;Repeat for each node, changing only the hostname&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;2. Prepare Each Node&lt;/h2&gt;
&lt;p&gt;SSH in (by IP if .local hostname resolution isn&#39;t working, find the node&#39;s IP address in your router&#39;s client list and connect directly.):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; ubuntu@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;node-ip&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Update the system:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; upgrade &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a fresh Ubuntu install, unattended-upgrades may already be running and temporarily lock apt. If that happens, let it finish before continuing.
You can check progress with:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; /var/log/unattended-upgrades/unattended-upgrades.log&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Disable unattended-upgrades&lt;/strong&gt; (avoid future collisions with manual work):&lt;/p&gt;
&lt;p&gt;I disable unattended upgrades on these nodes because I prefer to control when package updates happen and avoid nodes updating independently while the cluster is running.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl stop unattended-upgrades
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl disable unattended-upgrades&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;USB boot readiness (do this now, even if you will be booting from SD today)&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; rpi-eeprom &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; rpi-eeprom-update
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; rpi-eeprom-config &lt;span class=&quot;token parameter variable&quot;&gt;--edit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the editor, find or add under &lt;code&gt;[all]&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOT_ORDER=0xf41
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tries SD first, falls back to USB, retries, flag list may vary slightly by Pi 4 revision, that&#39;s normal.&lt;/p&gt;
&lt;p&gt;Save and exit (&lt;code&gt;Ctrl+O&lt;/code&gt;, Enter, &lt;code&gt;Ctrl+X&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reboot to apply both the kernel update and EEPROM change:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reboot&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confirm after reboot:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;# updated kernel&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;hostname&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;# correct hostname&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; if a node&#39;s hostname reverts after reboot, the real source is &lt;code&gt;/boot/firmware/user-data&lt;/code&gt; (cloud-init), not just &lt;code&gt;hostnamectl&lt;/code&gt;. Edit the &lt;code&gt;hostname:&lt;/code&gt; line there directly, then also run &lt;code&gt;sudo hostnamectl set-hostname &amp;lt;name&amp;gt;&lt;/code&gt; and reboot again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;3. Install k3s&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;On master ONLY:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-sfL&lt;/span&gt; https://get.k3s.io &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; -&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confirm it&#39;s running:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl status k3s
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; k3s kubectl get nodes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Get the join token:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /var/lib/rancher/k3s/server/node-token&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;On each worker (NOT master):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-sfL&lt;/span&gt; https://get.k3s.io &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;K3S_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;https://&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;master-ip&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;:6443 &lt;span class=&quot;token assign-left variable&quot;&gt;K3S_TOKEN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;paste-token&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; -&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Verify from master:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; wide&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All nodes should show &lt;code&gt;Ready&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;4. Configure kubectl for the Ubuntu User&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I use Zsh on my nodes, so the examples below use &lt;code&gt;~/.zshrc&lt;/code&gt;. If you&#39;re using Ubuntu&#39;s default Bash shell, use &lt;code&gt;~/.bashrc&lt;/code&gt; instead.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; ~/.kube
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; /etc/rancher/k3s/k3s.yaml ~/.kube/config
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chown&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-u&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ~/.kube/config

&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;KUBECONFIG&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=~&lt;/span&gt;/.kube/config
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;export KUBECONFIG=~/.kube/config&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; ~/.zshrc
&lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;5. Install Helm + cert-manager&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt;
helm version&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;helm repo &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; jetstack https://charts.jetstack.io
helm repo update
kubectl create namespace cert-manager
helm &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; cert-manager jetstack/cert-manager &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--namespace&lt;/span&gt; cert-manager &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;crds.enabled&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confirm all 3 cert-manager pods are &lt;code&gt;Running&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get pods &lt;span class=&quot;token parameter variable&quot;&gt;--namespace&lt;/span&gt; cert-manager&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;6. Local DNS for Rancher&lt;/h2&gt;
&lt;p&gt;I&#39;m using a UDM/Dream Machine in my homelab. This is how I set up local DNS for &lt;code&gt;rancher.lan&lt;/code&gt; on the UDM/Dream Machine:
On UDM/Dream Machine: &lt;strong&gt;Network app → Settings → DNS/Policy → Create Policy&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type: &lt;strong&gt;DNS&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Rule type: &lt;strong&gt;Host (A)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Domain Name: &lt;code&gt;rancher.lan&lt;/code&gt; // replace with your desired local domain name&lt;/li&gt;
&lt;li&gt;IP Address: &lt;code&gt;xxx.xx.x.xx&lt;/code&gt; (master)&lt;/li&gt;
&lt;li&gt;TTL: Auto&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;7. Install Rancher&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create namespace cattle-system

helm repo &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; rancher-latest https://releases.rancher.com/server-charts/latest
helm repo update

helm &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; rancher rancher-latest/rancher &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--namespace&lt;/span&gt; cattle-system &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;rancher.lan &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;bootstrapPassword&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;temporary-bootstrap-password&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;temporary-bootstrap-password&gt; with a temporary password of your choice. You&#39;ll use it for the initial Rancher login and replace it with a permanent password afterward.&lt;/temporary-bootstrap-password&gt;&lt;/p&gt;
&lt;p&gt;Watch rollout:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; cattle-system get pods &lt;span class=&quot;token parameter variable&quot;&gt;-w&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Press Ctrl+C to exit watch mode. This doesn&#39;t stop anything; it only stops streaming the pod status to your terminal.&lt;/p&gt;
&lt;h3&gt;Known issue on Pi hardware: startup probe timeout&lt;/h3&gt;
&lt;p&gt;Rancher&#39;s default startup probe only allows ~2 minutes to come up, which can be too short on Pi 4 CPU speed (especially during the initial Helm chart catalog restore). If pods keep restarting with &lt;code&gt;Error&lt;/code&gt; / exit code 137 and logs show it&#39;s still mid-catalog-restore, patch the probe:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; cattle-system patch deployment rancher &lt;span class=&quot;token parameter variable&quot;&gt;--type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;json&#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[
  {&quot;op&quot;: &quot;replace&quot;, &quot;path&quot;: &quot;/spec/template/spec/containers/0/startupProbe/failureThreshold&quot;, &quot;value&quot;: 60}
]&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This extends the window to 10 minutes. Watch pods again, a new ReplicaSet spins up with the patched setting. Old pods terminate as replacements come up. Some &lt;code&gt;Terminating&lt;/code&gt; → &lt;code&gt;Error&lt;/code&gt; transitions during this are normal/cosmetic, not new failures.&lt;/p&gt;
&lt;p&gt;Once &lt;code&gt;kubectl -n cattle-system rollout status deploy/rancher&lt;/code&gt; reports success and all replicas show &lt;code&gt;1/1 Running&lt;/code&gt;, log into &lt;code&gt;https://rancher.lan&lt;/code&gt; with the bootstrap password and set a real password immediately.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: joining a new node later does NOT automatically move/add Rancher replicas to it — Kubernetes only schedules on pod creation, not retroactively. Scale replicas or manually delete/recreate a pod if you want it rebalanced.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/rancher-400w-XTxrcxxPY6.webp 400w, https://j-riv.com/img/rancher-800w-XTxrcxxPY6.webp 800w, https://j-riv.com/img/rancher-1200w-XTxrcxxPY6.webp 1200w, https://j-riv.com/img/rancher-1600w-XTxrcxxPY6.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/rancher-400w-XTxrcxxPY6.jpeg&quot; alt=&quot;Rancher running on the finished five-node Raspberry Pi k3s cluster.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;890&quot; srcset=&quot;https://j-riv.com/img/rancher-400w-XTxrcxxPY6.jpeg 400w, https://j-riv.com/img/rancher-800w-XTxrcxxPY6.jpeg 800w, https://j-riv.com/img/rancher-1200w-XTxrcxxPY6.jpeg 1200w, https://j-riv.com/img/rancher-1600w-XTxrcxxPY6.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Rancher running on the finished five-node Raspberry Pi k3s cluster.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr /&gt;
&lt;h2&gt;8. SSH Key Setup (Passwordless Login)&lt;/h2&gt;
&lt;p&gt;Passwordless SSH is needed for the shutdown script below (and is generally more convenient than entering a password every time you connect to a node).&lt;/p&gt;
&lt;p&gt;Check for an existing SSH key on your Mac:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-la&lt;/span&gt; ~/.ssh/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look for a matching key pair, such as &lt;code&gt;id_ed25519&lt;/code&gt; / &lt;code&gt;id_ed25519.pub&lt;/code&gt; or &lt;code&gt;id_rsa&lt;/code&gt; / &lt;code&gt;id_rsa.pub&lt;/code&gt;. If one already exists, you can skip generating a new one.&lt;/p&gt;
&lt;p&gt;If you don&#39;t have one, generate an Ed25519 key:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-keygen &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt; ed25519&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Press Enter to accept the default save location. Leave the passphrase blank (press Enter twice) if you want scripts to use the key unattended without relying on &lt;code&gt;ssh-agent&lt;/code&gt; to cache the passphrase.&lt;/p&gt;
&lt;p&gt;Copy the public key to each of the five nodes. You&#39;ll be prompted for each node&#39;s password one last time:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-copy-id &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519.pub ubuntu@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;master-ip&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
ssh-copy-id &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519.pub ubuntu@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;worker-01-ip&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
ssh-copy-id &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519.pub ubuntu@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;worker-02-ip&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
ssh-copy-id &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519.pub ubuntu@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;worker-03-ip&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
ssh-copy-id &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519.pub ubuntu@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;worker-04-ip&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&#39;re using a different key, replace the &lt;code&gt;-i&lt;/code&gt; path with the appropriate public key, such as &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Test the connection:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; ubuntu@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;master-ip&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should connect without being prompted for the node&#39;s password. Once this works on all five nodes, the SSH keys combined with the passwordless &lt;code&gt;shutdown&lt;/code&gt; sudo rule below allow &lt;code&gt;clusterdown&lt;/code&gt; to shut down the entire cluster without prompting for credentials.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;9. Shutdown script (Mac or Linux)&lt;/h2&gt;
&lt;p&gt;I don&#39;t keep my cluster on 24/7, so I use a shutdown script to power it down cleanly when not in use.
Shut workers down first, master last, so it closes cleanly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One-time setup per node — passwordless sudo for shutdown only:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ubuntu ALL=(ALL) NOPASSWD: /usr/sbin/shutdown&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tee&lt;/span&gt; /etc/sudoers.d/ubuntu-shutdown&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Script — save as &lt;code&gt;~/cluster-shutdown.sh&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;WORKERS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;worker-01-ip&gt; &amp;lt;worker-02-ip&gt; &amp;lt;worker-03-ip&gt; &amp;lt;worker-04-ip&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;MASTER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;master-ip&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Shutting down cluster...&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$WORKERS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;→ Shutting down worker &lt;span class=&quot;token variable&quot;&gt;$ip&lt;/span&gt;...&quot;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; ubuntu@&lt;span class=&quot;token variable&quot;&gt;$ip&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sudo shutdown -h now&quot;&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;  done, waiting 5s...&quot;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;→ Shutting down master &lt;span class=&quot;token variable&quot;&gt;$MASTER&lt;/span&gt;...&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; ubuntu@&lt;span class=&quot;token variable&quot;&gt;$MASTER&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sudo shutdown -h now&quot;&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cluster shutdown complete.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; +x ~/cluster-shutdown.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Optional alias&lt;/strong&gt; (add to &lt;code&gt;~/.zshrc&lt;/code&gt; or &lt;code&gt;~/.bashrc&lt;/code&gt; if using Zsh or Bash):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;clusterdown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;~/cluster-shutdown.sh&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Startup: power everything back on in any order, workers will retry connecting to master until it&#39;s up, self-healing within a minute or two.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/pi4-5-node-cluster-400w-2l0vGSjw6T.webp 400w, https://j-riv.com/img/pi4-5-node-cluster-800w-2l0vGSjw6T.webp 800w, https://j-riv.com/img/pi4-5-node-cluster-1200w-2l0vGSjw6T.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/pi4-5-node-cluster-400w-2l0vGSjw6T.jpeg&quot; alt=&quot;Raspberry Pi 4 Five-Node Cluster&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;913&quot; srcset=&quot;https://j-riv.com/img/pi4-5-node-cluster-400w-2l0vGSjw6T.jpeg 400w, https://j-riv.com/img/pi4-5-node-cluster-800w-2l0vGSjw6T.jpeg 800w, https://j-riv.com/img/pi4-5-node-cluster-1200w-2l0vGSjw6T.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Raspberry Pi 4 Five-Node Cluster&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr /&gt;
&lt;h2&gt;Troubleshooting notes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you accidentally ran the plain &lt;code&gt;curl ... | sh -&lt;/code&gt; install command on a worker, it installs a second server instead of joining as an agent. Uninstall it with:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; /usr/local/bin/k3s-uninstall.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then reinstall using the correct &lt;code&gt;K3S_URL&lt;/code&gt; / &lt;code&gt;K3S_TOKEN&lt;/code&gt; command for joining the cluster (example: &lt;code&gt;K3S_URL=https://&amp;lt;master-ip&amp;gt;:6443 K3S_TOKEN=&amp;lt;token&amp;gt; sh -&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    <summary>Rebuilding my five-node Raspberry Pi 4 homelab cluster with Ubuntu Server, k3s, Rancher, Helm, and cert-manager.</summary>
  </entry>
  
  <entry>
    <title>Learning to live with Canine Diabetes</title>
    <link href="https://j-riv.com/blog/posts/2026-08-25-learning-to-live-with-canine-diabetes/"/>
    <updated>2026-08-25T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2026-08-25-learning-to-live-with-canine-diabetes/</id>
    <content type="html">&lt;p&gt;Henry has been part of my life for a long time. He was born April 2, 2015, and for most of his life his biggest concerns were figuring out when his next meal was coming and finding the most comfortable place in the house to sleep.&lt;/p&gt;
&lt;p&gt;Then he was diagnosed with diabetes.&lt;/p&gt;
&lt;p&gt;We knew diabetes would mean insulin injections and some changes to our routine. What we didn&#39;t realize was how much of our lives would eventually revolve around numbers, schedules, medications, glucose readings, and trying to figure out what his body was doing.&lt;/p&gt;
&lt;p&gt;It has easily been one of the hardest things we&#39;ve gone through together.&lt;/p&gt;
&lt;h2&gt;Learning to Live With Diabetes&lt;/h2&gt;
&lt;p&gt;Henry started on Vetsulin, with insulin given twice a day.&lt;/p&gt;
&lt;p&gt;Our schedule quickly became centered around 7:00 AM and 7:00 PM. He eats, gets his medications, and gets his insulin. Twelve hours later, we do it again.&lt;/p&gt;
&lt;p&gt;Every day.&lt;/p&gt;
&lt;p&gt;Giving the injections themselves eventually became the easy part. The difficult part was learning that treating diabetes isn&#39;t as simple as giving a certain amount of insulin twice a day and calling it done.&lt;/p&gt;
&lt;p&gt;Blood glucose can change considerably throughout the day, and Henry wasn&#39;t always predictable.&lt;/p&gt;
&lt;p&gt;Sometimes his glucose would stay extremely high. Other times the same insulin dose could bring him much lower than expected.&lt;/p&gt;
&lt;p&gt;We started learning about glucose curves, nadirs, insulin duration, injection sites, food timing, and all kinds of things we never expected to know.&lt;/p&gt;
&lt;p&gt;Then Cushing&#39;s disease made everything more complicated.&lt;/p&gt;
&lt;h2&gt;Diabetes and Cushing&#39;s&lt;/h2&gt;
&lt;p&gt;Henry was also diagnosed with Cushing&#39;s disease, which can make diabetes much harder to control because of its effect on insulin resistance.&lt;/p&gt;
&lt;p&gt;We started treating the Cushing&#39;s with Trilostane.&lt;/p&gt;
&lt;p&gt;In early January 2026, Henry was taking 20 mg of Trilostane twice a day while also receiving 8 units of Vetsulin twice daily.&lt;/p&gt;
&lt;p&gt;Then January 9 happened.&lt;/p&gt;
&lt;h2&gt;The Seizures&lt;/h2&gt;
&lt;p&gt;Henry started having seizures.&lt;/p&gt;
&lt;p&gt;He had multiple seizures at home. During one of them, we used Karo syrup because we were worried his blood sugar had dropped too low. He came around, but the seizures continued.&lt;/p&gt;
&lt;p&gt;We rushed him to the emergency vet.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-at-veg-san-diego-400w-OfHY-z_Xi-.webp 400w, https://j-riv.com/img/henry-at-veg-san-diego-800w-OfHY-z_Xi-.webp 800w, https://j-riv.com/img/henry-at-veg-san-diego-1200w-OfHY-z_Xi-.webp 1200w, https://j-riv.com/img/henry-at-veg-san-diego-1600w-OfHY-z_Xi-.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-at-veg-san-diego-400w-OfHY-z_Xi-.jpeg&quot; alt=&quot;Henry at VEG San Diego&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;2133&quot; srcset=&quot;https://j-riv.com/img/henry-at-veg-san-diego-400w-OfHY-z_Xi-.jpeg 400w, https://j-riv.com/img/henry-at-veg-san-diego-800w-OfHY-z_Xi-.jpeg 800w, https://j-riv.com/img/henry-at-veg-san-diego-1200w-OfHY-z_Xi-.jpeg 1200w, https://j-riv.com/img/henry-at-veg-san-diego-1600w-OfHY-z_Xi-.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Henry at VEG San Diego.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;He had another seizure there.&lt;/p&gt;
&lt;p&gt;Henry ended up spending about 24 hours in the ER receiving anti-seizure medication, fluids, oxygen, and monitoring.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-veg-san-diego-laying-400w-M2I2iLfFIO.webp 400w, https://j-riv.com/img/henry-veg-san-diego-laying-800w-M2I2iLfFIO.webp 800w, https://j-riv.com/img/henry-veg-san-diego-laying-1200w-M2I2iLfFIO.webp 1200w, https://j-riv.com/img/henry-veg-san-diego-laying-1600w-M2I2iLfFIO.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-veg-san-diego-laying-400w-M2I2iLfFIO.jpeg&quot; alt=&quot;Henry resting at VEG San Diego.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;1200&quot; srcset=&quot;https://j-riv.com/img/henry-veg-san-diego-laying-400w-M2I2iLfFIO.jpeg 400w, https://j-riv.com/img/henry-veg-san-diego-laying-800w-M2I2iLfFIO.jpeg 800w, https://j-riv.com/img/henry-veg-san-diego-laying-1200w-M2I2iLfFIO.jpeg 1200w, https://j-riv.com/img/henry-veg-san-diego-laying-1600w-M2I2iLfFIO.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Henry resting at VEG San Diego.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It was terrifying.&lt;/p&gt;
&lt;p&gt;When he was discharged, we stopped the Trilostane and reduced his insulin significantly. He also came home on Keppra, an anti-seizure medication that he has continued taking twice a day.&lt;/p&gt;
&lt;p&gt;At that point, treating Henry became a balancing act.&lt;/p&gt;
&lt;p&gt;We needed to control his diabetes, but we also had to treat the Cushing&#39;s, monitor his electrolytes, and avoid pushing anything too far in either direction.&lt;/p&gt;
&lt;h2&gt;Starting Over&lt;/h2&gt;
&lt;p&gt;After the hospitalization, we slowly began working our way back up with his insulin.&lt;/p&gt;
&lt;p&gt;His Vetsulin went from 4 units twice daily after the ER visit, to 5, then 6, 7, and eventually back to 8 units.&lt;/p&gt;
&lt;p&gt;We also cautiously restarted the Trilostane, initially at 20 mg once daily instead of twice daily.&lt;/p&gt;
&lt;p&gt;Bloodwork later showed that Henry&#39;s sodium was trending downward, so we adjusted again. His Trilostane was reduced to 15 mg once daily using a compounded liquid medication.&lt;/p&gt;
&lt;p&gt;It felt like every time we got one number under control, something else changed.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-riding-to-the-vet-400w-j2ubsCJkLS.webp 400w, https://j-riv.com/img/henry-riding-to-the-vet-800w-j2ubsCJkLS.webp 800w, https://j-riv.com/img/henry-riding-to-the-vet-1200w-j2ubsCJkLS.webp 1200w, https://j-riv.com/img/henry-riding-to-the-vet-1600w-j2ubsCJkLS.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-riding-to-the-vet-400w-j2ubsCJkLS.jpeg&quot; alt=&quot;Henry riding to the vet.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;2133&quot; srcset=&quot;https://j-riv.com/img/henry-riding-to-the-vet-400w-j2ubsCJkLS.jpeg 400w, https://j-riv.com/img/henry-riding-to-the-vet-800w-j2ubsCJkLS.jpeg 800w, https://j-riv.com/img/henry-riding-to-the-vet-1200w-j2ubsCJkLS.jpeg 1200w, https://j-riv.com/img/henry-riding-to-the-vet-1600w-j2ubsCJkLS.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Henry on one of his regular trips to the vet.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Then Henry Went Blind&lt;/h2&gt;
&lt;p&gt;Not long after all of this, Henry lost his vision.&lt;/p&gt;
&lt;p&gt;It happened incredibly fast.&lt;/p&gt;
&lt;p&gt;Diabetic dogs are particularly susceptible to cataracts, and suddenly the dog who had spent his entire life being able to see us couldn&#39;t anymore.&lt;/p&gt;
&lt;p&gt;That was probably one of the hardest changes for us to accept.&lt;/p&gt;
&lt;p&gt;Henry, however, adapted better than we expected.&lt;/p&gt;
&lt;p&gt;He learned how to navigate the house. He knows where his food and water are. He knows where we are. He still finds his way to the kitchen with absolutely no problem when there&#39;s food involved.&lt;/p&gt;
&lt;p&gt;He&#39;s still Henry.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-with-hoop-in-kitchen-400w-I_00QHwx7R.webp 400w, https://j-riv.com/img/henry-with-hoop-in-kitchen-800w-I_00QHwx7R.webp 800w, https://j-riv.com/img/henry-with-hoop-in-kitchen-1200w-I_00QHwx7R.webp 1200w, https://j-riv.com/img/henry-with-hoop-in-kitchen-1600w-I_00QHwx7R.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-with-hoop-in-kitchen-400w-I_00QHwx7R.jpeg&quot; alt=&quot;Henry wearing his blind dog harness.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;2133&quot; srcset=&quot;https://j-riv.com/img/henry-with-hoop-in-kitchen-400w-I_00QHwx7R.jpeg 400w, https://j-riv.com/img/henry-with-hoop-in-kitchen-800w-I_00QHwx7R.jpeg 800w, https://j-riv.com/img/henry-with-hoop-in-kitchen-1200w-I_00QHwx7R.jpeg 1200w, https://j-riv.com/img/henry-with-hoop-in-kitchen-1600w-I_00QHwx7R.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Henry hanging out in the kitchen with his blind dog harness, waiting for food and not letting blindness slow him down.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Turning Henry Into a Cyborg&lt;/h2&gt;
&lt;p&gt;Around the same time, we started using a FreeStyle Libre 3 Plus continuous glucose monitor.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-napping-400w-eNOCGZPEJ4.webp 400w, https://j-riv.com/img/henry-napping-800w-eNOCGZPEJ4.webp 800w, https://j-riv.com/img/henry-napping-1200w-eNOCGZPEJ4.webp 1200w, https://j-riv.com/img/henry-napping-1600w-eNOCGZPEJ4.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-napping-400w-eNOCGZPEJ4.jpeg&quot; alt=&quot;Henry wearing a FreeStyle Libre continuous glucose monitor.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;2133&quot; srcset=&quot;https://j-riv.com/img/henry-napping-400w-eNOCGZPEJ4.jpeg 400w, https://j-riv.com/img/henry-napping-800w-eNOCGZPEJ4.jpeg 800w, https://j-riv.com/img/henry-napping-1200w-eNOCGZPEJ4.jpeg 1200w, https://j-riv.com/img/henry-napping-1600w-eNOCGZPEJ4.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Henry wearing his FreeStyle Libre 3 Plus continuous glucose monitor.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The sensor sits near his shoulder blade and continuously measures his glucose.&lt;/p&gt;
&lt;p&gt;Having that information changed everything.&lt;/p&gt;
&lt;p&gt;Instead of checking a few individual points during the day, we could actually see the shape of his glucose curve. We could see when the insulin started working, how quickly his glucose was dropping, where his lowest point was, and when it started climbing again.&lt;/p&gt;
&lt;p&gt;Of course, nothing involving Henry&#39;s diabetes could be that simple.&lt;/p&gt;
&lt;p&gt;We&#39;ve dealt with signal loss, sensor errors, sensors failing early, and readings that didn&#39;t seem to match what Henry was doing.&lt;/p&gt;
&lt;p&gt;So the Libre became another tool rather than something we could blindly trust.&lt;/p&gt;
&lt;p&gt;When a reading doesn&#39;t look right, especially when he&#39;s running low, we confirm it with an AlphaTrak blood glucose meter.&lt;/p&gt;
&lt;p&gt;Our house basically started looking like a tiny veterinary clinic.&lt;/p&gt;
&lt;h2&gt;The Numbers Take Over&lt;/h2&gt;
&lt;p&gt;One of the hardest parts of managing diabetes is trying not to become obsessed with the numbers.&lt;/p&gt;
&lt;p&gt;When the Libre says &lt;strong&gt;HI&lt;/strong&gt;, you want the glucose to come down.&lt;/p&gt;
&lt;p&gt;Then it starts coming down and suddenly you&#39;re watching it thinking:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Okay... maybe not that fast.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You learn that a number by itself doesn&#39;t tell the whole story. The direction it&#39;s moving matters. How quickly it&#39;s moving matters. When Henry last ate matters. When he received insulin matters. How active he&#39;s been matters.&lt;/p&gt;
&lt;p&gt;We&#39;ve spent plenty of nights watching his glucose readings instead of sleeping.&lt;/p&gt;
&lt;p&gt;There have been times when we&#39;ve sat next to him with an AlphaTrak, kibble, turkey, and Karo syrup nearby while waiting to see where his glucose was going.&lt;/p&gt;
&lt;p&gt;You start celebrating numbers that would mean absolutely nothing to anyone else.&lt;/p&gt;
&lt;h2&gt;Changing Insulin&lt;/h2&gt;
&lt;p&gt;Eventually, controlling Henry&#39;s diabetes with Vetsulin became difficult enough that we decided to try insulin glargine.&lt;/p&gt;
&lt;p&gt;That brought another learning curve.&lt;/p&gt;
&lt;p&gt;The initial dose brought his glucose down much more aggressively than we expected. We had readings in the 80s and 90s and spent hours monitoring him, feeding small snacks, checking the Libre, confirming with the AlphaTrak, and trying to decide what to do with his next dose.&lt;/p&gt;
&lt;p&gt;So we adjusted again.&lt;/p&gt;
&lt;p&gt;That&#39;s probably the biggest lesson Henry&#39;s diabetes has taught us: &lt;strong&gt;there isn&#39;t always an easy answer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You collect information, watch what happens, work with the vet, adjust, and repeat.&lt;/p&gt;
&lt;h2&gt;Our New Normal&lt;/h2&gt;
&lt;p&gt;At this point, diabetes is simply part of our routine.&lt;/p&gt;
&lt;p&gt;There are insulin pens, glucose meters, Libre sensors, test strips, medications, syringes, and emergency Karo syrup around the house.&lt;/p&gt;
&lt;p&gt;Meals happen on schedule.&lt;/p&gt;
&lt;p&gt;Medications happen on schedule.&lt;/p&gt;
&lt;p&gt;Insulin happens on schedule.&lt;/p&gt;
&lt;p&gt;Glucose gets checked.&lt;/p&gt;
&lt;p&gt;Then checked again.&lt;/p&gt;
&lt;p&gt;Henry doesn&#39;t understand any of that.&lt;/p&gt;
&lt;p&gt;He just knows that he gets fed at 7:00.&lt;/p&gt;
&lt;p&gt;And we&#39;re pretty sure that&#39;s the only part of the treatment plan he actually approves of.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-listening-to-music-400w-0XVjlCU8gm.webp 400w, https://j-riv.com/img/henry-listening-to-music-800w-0XVjlCU8gm.webp 800w, https://j-riv.com/img/henry-listening-to-music-1200w-0XVjlCU8gm.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-listening-to-music-400w-0XVjlCU8gm.jpeg&quot; alt=&quot;Henry listening to music.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1594&quot; srcset=&quot;https://j-riv.com/img/henry-listening-to-music-400w-0XVjlCU8gm.jpeg 400w, https://j-riv.com/img/henry-listening-to-music-800w-0XVjlCU8gm.jpeg 800w, https://j-riv.com/img/henry-listening-to-music-1200w-0XVjlCU8gm.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Henry listening to music. We like to think he lays by the speakers to feel the music. When you can&#39;t see, you listen a little closer.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Still Henry&lt;/h2&gt;
&lt;p&gt;Diabetes has changed a lot about Henry&#39;s life. Cushing&#39;s complicated it. The seizures scared the hell out of us. Losing his vision was difficult. There have been ER visits, medication changes, failed sensors, sleepless nights, and more glucose readings than we could possibly count.&lt;/p&gt;
&lt;p&gt;But none of those things define him.&lt;/p&gt;
&lt;p&gt;He&#39;s still stubborn.&lt;/p&gt;
&lt;p&gt;He&#39;s still obsessed with food.&lt;/p&gt;
&lt;p&gt;He still manages to find the kitchen despite being blind.&lt;/p&gt;
&lt;p&gt;He still wants to be wherever we are.&lt;/p&gt;
&lt;p&gt;And he&#39;s still the same Henry.&lt;/p&gt;
&lt;p&gt;Taking care of a diabetic dog can be exhausting, frustrating, expensive, and sometimes scary. There are days when you think you&#39;ve finally figured everything out, followed immediately by a day that makes absolutely no sense.&lt;/p&gt;
&lt;p&gt;But he depends on us.&lt;/p&gt;
&lt;p&gt;So we adjust.&lt;/p&gt;
&lt;p&gt;We check the numbers.&lt;/p&gt;
&lt;p&gt;We give him his medicine.&lt;/p&gt;
&lt;p&gt;And at 7:00, we do it all over again.&lt;/p&gt;
</content>
    <summary>Life with a diabetic dog isn&#39;t as simple as giving insulin twice a day. Henry&#39;s journey has included Cushing&#39;s disease, seizures, blindness, glucose monitors, medication changes, and a lot of sleepless nights—but through all of it, he&#39;s still Henry.</summary>
  </entry>
  
  <entry>
    <title>The Home Lab Revisited</title>
    <link href="https://j-riv.com/blog/posts/2024-11-28-the-homelab-revisited/"/>
    <updated>2024-11-28T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2024-11-28-the-homelab-revisited/</id>
    <content type="html">&lt;p&gt;It&#39;s been a while since I last posted an update on my homelab, and quite a bit has changed since then.&lt;/p&gt;
&lt;h2&gt;Moving to OPNsense&lt;/h2&gt;
&lt;p&gt;A few months after my last homelab update, I retired both of my Netgear Nighthawk routers and replaced them with a mini PC running OPNsense.&lt;/p&gt;
&lt;p&gt;The goal was to get more control over my network and move away from relying on consumer routers. The mini PC took over firewall, routing, and VPN duties while giving me significantly more flexibility over how the network was configured.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/opnsense-router-mini-pc-400w-VyF2iLwBOo.webp 400w, https://j-riv.com/img/opnsense-router-mini-pc-800w-VyF2iLwBOo.webp 800w, https://j-riv.com/img/opnsense-router-mini-pc-1200w-VyF2iLwBOo.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/opnsense-router-mini-pc-400w-VyF2iLwBOo.jpeg&quot; alt=&quot;OPNsense Router Mini PC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1500&quot; srcset=&quot;https://j-riv.com/img/opnsense-router-mini-pc-400w-VyF2iLwBOo.jpeg 400w, https://j-riv.com/img/opnsense-router-mini-pc-800w-VyF2iLwBOo.jpeg 800w, https://j-riv.com/img/opnsense-router-mini-pc-1200w-VyF2iLwBOo.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The mini PC running OPNsense for improved network performance and flexibility.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I ran OPNsense for a few months and was really impressed with what it could do. Compared to the Nighthawks, I had much more control over network management, firewall rules, VPNs, and the network as a whole.&lt;/p&gt;
&lt;p&gt;Of course, that eventually sent me down another rabbit hole.&lt;/p&gt;
&lt;h2&gt;Moving to UniFi&lt;/h2&gt;
&lt;p&gt;After spending some time with OPNsense, I started looking into Ubiquiti&#39;s UniFi ecosystem and eventually picked up a UniFi Dream Machine Special Edition (UDM-SE).&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/homelab-update-2-400w-nrj4GjNEuh.webp 400w, https://j-riv.com/img/homelab-update-2-800w-nrj4GjNEuh.webp 800w, https://j-riv.com/img/homelab-update-2-1200w-nrj4GjNEuh.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/homelab-update-2-400w-nrj4GjNEuh.jpeg&quot; alt=&quot;The updated network rack with the UniFi Dream Machine Special Edition (UDM-SE)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1471&quot; srcset=&quot;https://j-riv.com/img/homelab-update-2-400w-nrj4GjNEuh.jpeg 400w, https://j-riv.com/img/homelab-update-2-800w-nrj4GjNEuh.jpeg 800w, https://j-riv.com/img/homelab-update-2-1200w-nrj4GjNEuh.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The updated network rack with the UniFi Dream Machine Special Edition (UDM-SE).&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The UDM-SE simplified a lot of the network management I had been doing manually while still giving me the features I actually cared about. It also gave me a central platform for adding and managing other UniFi equipment as the network continues to grow.&lt;/p&gt;
&lt;p&gt;OPNsense was great and gave me a lot of control, but for a home network I&#39;ve really enjoyed having everything managed through the UniFi interface.&lt;/p&gt;
&lt;h2&gt;Adding More Compute&lt;/h2&gt;
&lt;p&gt;The network wasn&#39;t the only thing that got an upgrade.&lt;/p&gt;
&lt;p&gt;I also picked up a Lenovo ThinkStation P710 to add some more compute capacity to the homelab.&lt;/p&gt;
&lt;p&gt;These older enterprise workstations can usually be found pretty cheap through online marketplaces and refurbished hardware vendors, and they make surprisingly capable home servers.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/lenovo-thinkstation-p710-internals-400w-S1pqWdNlr0.webp 400w, https://j-riv.com/img/lenovo-thinkstation-p710-internals-800w-S1pqWdNlr0.webp 800w, https://j-riv.com/img/lenovo-thinkstation-p710-internals-1200w-S1pqWdNlr0.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/lenovo-thinkstation-p710-internals-400w-S1pqWdNlr0.jpeg&quot; alt=&quot;Lenovo ThinkStation P710 Internals&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1500&quot; srcset=&quot;https://j-riv.com/img/lenovo-thinkstation-p710-internals-400w-S1pqWdNlr0.jpeg 400w, https://j-riv.com/img/lenovo-thinkstation-p710-internals-800w-S1pqWdNlr0.jpeg 800w, https://j-riv.com/img/lenovo-thinkstation-p710-internals-1200w-S1pqWdNlr0.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The Lenovo ThinkStation P710 workstation added to the homelab for additional computing power.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;My P710 came with dual Intel Xeon processors for a total of 28 cores. I upgraded it to &lt;strong&gt;192 GB of RAM&lt;/strong&gt;, giving me plenty of room for virtual machines, containers, and whatever else I decide to throw at it.&lt;/p&gt;
&lt;p&gt;It&#39;s definitely overkill for some of what I use it for, but that&#39;s half the fun of having a homelab.&lt;/p&gt;
&lt;h2&gt;The Homelab Today&lt;/h2&gt;
&lt;p&gt;The setup has changed quite a bit from where it started. What was originally built around consumer networking hardware has gradually turned into a more capable environment for experimenting with networking, virtualization, containers, Linux, and whatever else I happen to be working on.&lt;/p&gt;
&lt;p&gt;And, as always, the entire operation is closely supervised by the head of IT.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-head-of-it-400w-_6tR8pCpzt.webp 400w, https://j-riv.com/img/henry-head-of-it-800w-_6tR8pCpzt.webp 800w, https://j-riv.com/img/henry-head-of-it-1200w-_6tR8pCpzt.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-head-of-it-400w-_6tR8pCpzt.jpeg&quot; alt=&quot;Henry, Head of IT&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1500&quot; srcset=&quot;https://j-riv.com/img/henry-head-of-it-400w-_6tR8pCpzt.jpeg 400w, https://j-riv.com/img/henry-head-of-it-800w-_6tR8pCpzt.jpeg 800w, https://j-riv.com/img/henry-head-of-it-1200w-_6tR8pCpzt.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Henry, age 10. Semi-retired Head of IT. Likes include short walks to the kitchen and anything involving food. Dislikes taking baths.&lt;/figcaption&gt;&lt;/figure&gt;
</content>
    <summary>My homelab has changed quite a bit since the last update, moving from consumer routers to OPNsense and eventually UniFi, while adding a dual-Xeon ThinkStation P710 with 192 GB of RAM for virtualization, containers, and more tinkering.</summary>
  </entry>
  
  <entry>
    <title>Harley Davidson Low Rider ST (FXLRST)</title>
    <link href="https://j-riv.com/blog/posts/2024-11-21-hd-fxlrst/"/>
    <updated>2024-11-21T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2024-11-21-hd-fxlrst/</id>
    <content type="html">&lt;p&gt;Well, I finally did it. I got myself a Low Rider ST.&lt;/p&gt;
&lt;p&gt;Over time, I found myself slowly turning my Street Bob into my own version of a Low Rider. Once I started looking into inverted forks and a dual-disc front brake conversion, I realized what I had to do.&lt;/p&gt;
&lt;p&gt;It was still a hard decision. I really liked the FXBBS. It was a great bike, and I had put a lot of work into making it my own. But I wanted something better suited for longer rides, and the Low Rider ST checked a lot of boxes right out of the gate: a larger engine, 5-gallon tank, better brakes, improved suspension, and much better wind protection.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxlrst-front-up-work-400w-mU8U46G4uc.webp 400w, https://j-riv.com/img/fxlrst-front-up-work-800w-mU8U46G4uc.webp 800w, https://j-riv.com/img/fxlrst-front-up-work-1200w-mU8U46G4uc.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxlrst-front-up-work-400w-mU8U46G4uc.jpeg&quot; alt=&quot;Harley Davidson FXLRST, front view.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1600&quot; srcset=&quot;https://j-riv.com/img/fxlrst-front-up-work-400w-mU8U46G4uc.jpeg 400w, https://j-riv.com/img/fxlrst-front-up-work-800w-mU8U46G4uc.jpeg 800w, https://j-riv.com/img/fxlrst-front-up-work-1200w-mU8U46G4uc.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Harley Davidson FXLRST, front view.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Deciding to Make the Switch&lt;/h2&gt;
&lt;p&gt;About six months earlier, I had test ridden both the FXLRS (Low Rider S) and FXLRST (Low Rider ST).&lt;/p&gt;
&lt;p&gt;The Low Rider S didn&#39;t feel like enough of an upgrade over my modified Street Bob, and at the time I wasn&#39;t completely sold on the bags or fairing on the Low Rider ST. I decided to run some numbers on the ST anyway, but the dealer and I couldn&#39;t come to an agreement on the price.&lt;/p&gt;
&lt;p&gt;So I went home and started thinking about what I liked about the Low Rider and what I could bring over to my Street Bob instead.&lt;/p&gt;
&lt;p&gt;I started with some of the cheaper changes, like raising the rear suspension, along with a few cosmetic modifications like a license plate relocation kit.&lt;/p&gt;
&lt;p&gt;But after a few more months of riding the Street Bob, I started researching inverted front ends and converting the bike to dual front discs.&lt;/p&gt;
&lt;p&gt;At that point, I had to ask myself what I was actually doing.&lt;/p&gt;
&lt;p&gt;I kept looking at the Low Rider ST and couldn&#39;t get it out of my head. With the 2025 models coming soon and motorcycle sales slowing down, I decided it was finally time. I traded in the Street Bob and came home with a Low Rider ST.&lt;/p&gt;
&lt;p&gt;I couldn&#39;t be happier with the decision. My only regret is not doing it sooner it probably would have saved me some money.&lt;/p&gt;
&lt;h2&gt;Making the ST Mine&lt;/h2&gt;
&lt;p&gt;Of course, I couldn&#39;t leave it stock for long.&lt;/p&gt;
&lt;p&gt;The first things to go were the stock seat and shotgun exhaust.&lt;/p&gt;
&lt;h3&gt;Saddlemen SDC Pro Gripper&lt;/h3&gt;
&lt;p&gt;This time around, I went with a Saddlemen SDC Pro Gripper. I wasn&#39;t sure how I felt about the backrest at first, but since it&#39;s removable, I decided to get it anyway.&lt;/p&gt;
&lt;p&gt;So far, so good.&lt;/p&gt;
&lt;h3&gt;SPC Big Bore 2-Into-1&lt;/h3&gt;
&lt;p&gt;For the exhaust, I went with an SPC Big Bore 2-into-1 paired with a Dynojet Power Vision tuner.&lt;/p&gt;
&lt;p&gt;I had run Vance &amp;amp; Hines Short Shots on the Street Bob, but I wanted to go in a different direction with the ST and move to a 2-into-1 setup.&lt;/p&gt;
&lt;h3&gt;Lucky Dave&#39;s Lucky 13s&lt;/h3&gt;
&lt;p&gt;The stock bars actually felt okay, but I really liked the T-bars I had on my FXBBS, so I went back to Lucky Dave&#39;s.&lt;/p&gt;
&lt;p&gt;This time I chose 11-inch Lucky 13s to get some additional pullback.&lt;/p&gt;
&lt;p&gt;Since I was already changing the bars, I figured I might as well change the grips too. I went with brown ODI Vans Lock-On grips to complement the bronze wheels.&lt;/p&gt;
&lt;h3&gt;MoonsMC Fly Eye V2&lt;/h3&gt;
&lt;p&gt;I also really liked the MoonsMC Fly Eye headlight I had on the Street Bob, so the ST got the newer Fly Eye V2.&lt;/p&gt;
&lt;h2&gt;What&#39;s Next?&lt;/h2&gt;
&lt;p&gt;So far, I&#39;ve been really happy with both the bike and the modifications.&lt;/p&gt;
&lt;p&gt;There are still a few things I want to change, but I&#39;m going to take my time and enjoy the bike for a while instead of immediately tearing everything apart.&lt;/p&gt;
&lt;p&gt;One of the next things I&#39;m looking at is a new taillight. Aside from changing the look, I&#39;m hoping a lighter taillight assembly might reduce some of the stress on the rear fender. I&#39;ve seen several reports of the ST rear fender developing cracks around the taillight area, so I&#39;d rather get ahead of that if I can.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxlrst-laidlaws-hd-400w-52VdTgtyq7.webp 400w, https://j-riv.com/img/fxlrst-laidlaws-hd-800w-52VdTgtyq7.webp 800w, https://j-riv.com/img/fxlrst-laidlaws-hd-1200w-52VdTgtyq7.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxlrst-laidlaws-hd-400w-52VdTgtyq7.jpeg&quot; alt=&quot;Harley Davidson FXLRST at Laidlaw&#39;s Harley-Davidson.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1600&quot; srcset=&quot;https://j-riv.com/img/fxlrst-laidlaws-hd-400w-52VdTgtyq7.jpeg 400w, https://j-riv.com/img/fxlrst-laidlaws-hd-800w-52VdTgtyq7.jpeg 800w, https://j-riv.com/img/fxlrst-laidlaws-hd-1200w-52VdTgtyq7.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Harley Davidson FXLRST at Laidlaw&#39;s Harley-Davidson.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The Street Bob was a great bike and taught me a lot about what I actually wanted out of a Harley. In the end, I spent a couple of years modifying it toward something Harley already made.&lt;/p&gt;
&lt;p&gt;Sometimes you just have to buy the right bike.&lt;/p&gt;
</content>
    <summary>After spending a couple of years modifying my Street Bob toward a Low Rider, I finally made the jump to a Low Rider ST and, of course, immediately started making it my own.</summary>
  </entry>
  
  <entry>
    <title>Voron</title>
    <link href="https://j-riv.com/blog/posts/2024-03-07-voron/"/>
    <updated>2024-03-07T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2024-03-07-voron/</id>
    <content type="html">&lt;p&gt;Well, it&#39;s been a few months. Let&#39;s welcome the newest addition to the family. Kaos, my new Voron 2.4r2.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/voron-garage-workstation-400w-l6hBQSUqy4.webp 400w, https://j-riv.com/img/voron-garage-workstation-800w-l6hBQSUqy4.webp 800w, https://j-riv.com/img/voron-garage-workstation-1200w-l6hBQSUqy4.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/voron-garage-workstation-400w-l6hBQSUqy4.jpeg&quot; alt=&quot;Voron 2.4r2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1500&quot; srcset=&quot;https://j-riv.com/img/voron-garage-workstation-400w-l6hBQSUqy4.jpeg 400w, https://j-riv.com/img/voron-garage-workstation-800w-l6hBQSUqy4.jpeg 800w, https://j-riv.com/img/voron-garage-workstation-1200w-l6hBQSUqy4.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Kaos, my new Voron 2.4r2.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Serial V2.4726&lt;/p&gt;
&lt;p&gt;Build Volume: 350x350x350 mm&lt;/p&gt;
</content>
    <summary>Meet Kaos, my 350mm Voron 2.4r2—the inevitable result of going too far down the Klipper and 3D printing rabbit hole.</summary>
  </entry>
  
  <entry>
    <title>Homelab Update</title>
    <link href="https://j-riv.com/blog/posts/2023-01-21-homelab-update/"/>
    <updated>2023-01-21T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2023-01-21-homelab-update/</id>
    <content type="html">&lt;p&gt;I have upgraded my home lab from a simple wall mountable rack to a media / network rack. Which I then added a wood
top to use as desk space for a 3D Printer.&lt;/p&gt;
&lt;p&gt;Other changes include:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;A second Nighthawk I had laying around and made it a network wide VPN using DD-WRT.&lt;/li&gt;
  &lt;li&gt;5 Rack mounted Raspberry Pi 4s&lt;/li&gt;
  &lt;li&gt;Netgear 16 Port POE Switch to power the Pis&lt;/li&gt;
  &lt;li&gt;Dell Optiplex running OPNSENSE firewall&lt;/li&gt;
  &lt;li&gt;Dell T5600 running Ubuntu Server. This runs a full stack of containers that power the media server, ex: Plex.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/rack-mounted-raspberry-pi-400w-AYHpZw7CiB.webp 400w, https://j-riv.com/img/rack-mounted-raspberry-pi-800w-AYHpZw7CiB.webp 800w, https://j-riv.com/img/rack-mounted-raspberry-pi-1200w-AYHpZw7CiB.webp 1200w, https://j-riv.com/img/rack-mounted-raspberry-pi-1536w-AYHpZw7CiB.webp 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/rack-mounted-raspberry-pi-400w-AYHpZw7CiB.jpeg&quot; alt=&quot;Rack Mounted Raspberry Pi&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1536&quot; height=&quot;2048&quot; srcset=&quot;https://j-riv.com/img/rack-mounted-raspberry-pi-400w-AYHpZw7CiB.jpeg 400w, https://j-riv.com/img/rack-mounted-raspberry-pi-800w-AYHpZw7CiB.jpeg 800w, https://j-riv.com/img/rack-mounted-raspberry-pi-1200w-AYHpZw7CiB.jpeg 1200w, https://j-riv.com/img/rack-mounted-raspberry-pi-1536w-AYHpZw7CiB.jpeg 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The updated home lab rack setup with rack mounted Raspberry Pi 4s.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/home-lab-current-400w-jBy8_Vs2d4.webp 400w, https://j-riv.com/img/home-lab-current-800w-jBy8_Vs2d4.webp 800w, https://j-riv.com/img/home-lab-current-1200w-jBy8_Vs2d4.webp 1200w, https://j-riv.com/img/home-lab-current-1536w-jBy8_Vs2d4.webp 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/home-lab-current-400w-jBy8_Vs2d4.jpeg&quot; alt=&quot;Current Home Lab Setup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1536&quot; height=&quot;2048&quot; srcset=&quot;https://j-riv.com/img/home-lab-current-400w-jBy8_Vs2d4.jpeg 400w, https://j-riv.com/img/home-lab-current-800w-jBy8_Vs2d4.jpeg 800w, https://j-riv.com/img/home-lab-current-1200w-jBy8_Vs2d4.jpeg 1200w, https://j-riv.com/img/home-lab-current-1536w-jBy8_Vs2d4.jpeg 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The updated home lab rack setup with all equipment in place.&lt;/figcaption&gt;&lt;/figure&gt;
</content>
    <summary>An update to my homelab with a larger network rack, rack-mounted Raspberry Pis, PoE networking, an OPNsense firewall, a dedicated VPN router, and a Dell T5600 running my containerized media services.</summary>
  </entry>
  
  <entry>
    <title>Klipper: The Gateway Drug to Voron</title>
    <link href="https://j-riv.com/blog/posts/2023-01-20-klipper-the-gateway-drug-to-voron/"/>
    <updated>2023-01-20T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2023-01-20-klipper-the-gateway-drug-to-voron/</id>
    <content type="html">&lt;p&gt;I bought my first 3D Printer at the beginning of 2019. An Ender 3 Pro. I played with it for a few months. Installed
&lt;a href=&quot;https://octoprint.org/&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;OctoPrint&lt;/a&gt; on a Raspberry Pi and then quickly
lost interest. About 2 years later I decided to dust it off and upgrade
it a bit.&lt;/p&gt;
&lt;p&gt;The first upgrade was a CR Touch Auto Bed Leveling Sensor. This required a 32 bit board. My Ender 3 Pro is
an older printer so it came with an 8 bit board. While I was at it I ordered a metal extruder to replace the plastic
one it came with and a dual z-axis upgrade kit.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/ender-3-pro-400w-9oKpxYix9u.webp 400w, https://j-riv.com/img/ender-3-pro-800w-9oKpxYix9u.webp 800w, https://j-riv.com/img/ender-3-pro-1200w-9oKpxYix9u.webp 1200w, https://j-riv.com/img/ender-3-pro-1536w-9oKpxYix9u.webp 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/ender-3-pro-400w-9oKpxYix9u.jpeg&quot; alt=&quot;Ender 3 Pro&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1536&quot; height=&quot;2048&quot; srcset=&quot;https://j-riv.com/img/ender-3-pro-400w-9oKpxYix9u.jpeg 400w, https://j-riv.com/img/ender-3-pro-800w-9oKpxYix9u.jpeg 800w, https://j-riv.com/img/ender-3-pro-1200w-9oKpxYix9u.jpeg 1200w, https://j-riv.com/img/ender-3-pro-1536w-9oKpxYix9u.jpeg 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;My Ender 3 Pro after the upgrades.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Installing the CR Touch required a firmware upgrade. I decided to compile Marlin with the necessary changes myself,
instead of using the Creality supplied CR Touch firmware. This turned out to be relatively easy. But as always I was
bored again. Bored with stability, I needed something else to tinker with. I needed a second printer.&lt;/p&gt;
&lt;p&gt;I ordered an Ender 3 S1 Pro. Initially I had issues with OctoPrint and the S1. This was due to Creality&#39;s version of
the Marlin Firmware. This gave me the perfect excuse to try &lt;a href=&quot;https://www.klipper3d.org/&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;Klipper&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/sonic-pad-s1-400w-zdLjMxX4Lt.webp 400w, https://j-riv.com/img/sonic-pad-s1-800w-zdLjMxX4Lt.webp 800w, https://j-riv.com/img/sonic-pad-s1-1200w-zdLjMxX4Lt.webp 1200w, https://j-riv.com/img/sonic-pad-s1-1600w-zdLjMxX4Lt.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/sonic-pad-s1-400w-zdLjMxX4Lt.jpeg&quot; alt=&quot;Ender 3 S1 Pro&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;2133&quot; srcset=&quot;https://j-riv.com/img/sonic-pad-s1-400w-zdLjMxX4Lt.jpeg 400w, https://j-riv.com/img/sonic-pad-s1-800w-zdLjMxX4Lt.jpeg 800w, https://j-riv.com/img/sonic-pad-s1-1200w-zdLjMxX4Lt.jpeg 1200w, https://j-riv.com/img/sonic-pad-s1-1600w-zdLjMxX4Lt.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;My Ender 3 S1 Pro after the upgrades.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I ordered a Sonic Pad thinking this would be the easiest way to install Klipper on the S1, but again I ran into issues. Advertised features failed to work and the pad was very buggy. What worked for some didn&#39;t work for me. I
started looking into running Klipper off of a Raspberry Pi and decided to give it a go with the Ender 3 Pro. Within an
hour I had Klipper running successfully via the Fluidd interface. The issues I had with the Sonic Pad were non
existent on the Pi. To make the change permanent I printed some parts and got a 5&amp;quot; screen and installed &lt;a href=&quot;https://klipperscreen.readthedocs.io/en/latest/&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;KlipperScreen&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/klipperscreen-pi3-400w-0qb_ElhqAj.webp 400w, https://j-riv.com/img/klipperscreen-pi3-800w-0qb_ElhqAj.webp 800w, https://j-riv.com/img/klipperscreen-pi3-1200w-0qb_ElhqAj.webp 1200w, https://j-riv.com/img/klipperscreen-pi3-1536w-0qb_ElhqAj.webp 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/klipperscreen-pi3-400w-0qb_ElhqAj.jpeg&quot; alt=&quot;Raspberry Pi 3 + BTT PITFT50 v2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1536&quot; height=&quot;2048&quot; srcset=&quot;https://j-riv.com/img/klipperscreen-pi3-400w-0qb_ElhqAj.jpeg 400w, https://j-riv.com/img/klipperscreen-pi3-800w-0qb_ElhqAj.jpeg 800w, https://j-riv.com/img/klipperscreen-pi3-1200w-0qb_ElhqAj.jpeg 1200w, https://j-riv.com/img/klipperscreen-pi3-1536w-0qb_ElhqAj.jpeg 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Raspberry Pi 3 + BTT PITFT50 v2.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/klipperscreen-pi3-front-400w-qS-ShSRZmT.webp 400w, https://j-riv.com/img/klipperscreen-pi3-front-800w-qS-ShSRZmT.webp 800w, https://j-riv.com/img/klipperscreen-pi3-front-1200w-qS-ShSRZmT.webp 1200w, https://j-riv.com/img/klipperscreen-pi3-front-1536w-qS-ShSRZmT.webp 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/klipperscreen-pi3-front-400w-qS-ShSRZmT.jpeg&quot; alt=&quot;Raspberry Pi 3 + BTT PITFT50 v2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1536&quot; height=&quot;2048&quot; srcset=&quot;https://j-riv.com/img/klipperscreen-pi3-front-400w-qS-ShSRZmT.jpeg 400w, https://j-riv.com/img/klipperscreen-pi3-front-800w-qS-ShSRZmT.jpeg 800w, https://j-riv.com/img/klipperscreen-pi3-front-1200w-qS-ShSRZmT.jpeg 1200w, https://j-riv.com/img/klipperscreen-pi3-front-1536w-qS-ShSRZmT.jpeg 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Raspberry Pi 3 + BTT PITFT50 v2.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;After the success with the Pi, I made a second one to use on the S1. I know that Klipper is capable of running more
than 1 printer, but since I wanted it mounted on the printer I decided to have 1 Pi per printer.&lt;/p&gt;
&lt;p&gt;A few months into Klipper and now I have found the newest thing I never knew I always needed, a &lt;a href=&quot;https://vorondesign.com/&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;Voron&lt;/a&gt;!&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/creality-printers-400w-vrTZDfbBtQ.webp 400w, https://j-riv.com/img/creality-printers-800w-vrTZDfbBtQ.webp 800w, https://j-riv.com/img/creality-printers-1200w-vrTZDfbBtQ.webp 1200w, https://j-riv.com/img/creality-printers-1536w-vrTZDfbBtQ.webp 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/creality-printers-400w-vrTZDfbBtQ.jpeg&quot; alt=&quot;Creality Ender 3 Pro and Ender 3 S1 Pro running Klipper.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1536&quot; height=&quot;2048&quot; srcset=&quot;https://j-riv.com/img/creality-printers-400w-vrTZDfbBtQ.jpeg 400w, https://j-riv.com/img/creality-printers-800w-vrTZDfbBtQ.jpeg 800w, https://j-riv.com/img/creality-printers-1200w-vrTZDfbBtQ.jpeg 1200w, https://j-riv.com/img/creality-printers-1536w-vrTZDfbBtQ.jpeg 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Creality Ender 3 Pro and Ender 3 S1 Pro running Klipper.&lt;/figcaption&gt;&lt;/figure&gt;
</content>
    <summary>How upgrading an old Ender 3 Pro led me from Marlin and OctoPrint to Klipper, Raspberry Pis, KlipperScreen, a second 3D printer, and eventually down the Voron rabbit hole.</summary>
  </entry>
  
  <entry>
    <title>Harley Davidson Street Bob (FXBBS) - 5-Gallon Tank Swap</title>
    <link href="https://j-riv.com/blog/posts/2023-01-05-hd-fxbbs-5-gal-tank/"/>
    <updated>2023-01-05T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2023-01-05-hd-fxbbs-5-gal-tank/</id>
    <content type="html">&lt;p&gt;A 3.5-gallon tank looks cool, but it will only get you so far, literally.&lt;/p&gt;
&lt;p&gt;I&#39;d been searching for a 5-gallon Softail tank for a while, but all I could find were dented tanks or ones with ridiculous asking prices. Eventually, a Low Rider S tank showed up on eBay for a decent price, so I decided to pull the trigger.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxlrs-tank-400w-3RNuMRTOKX.webp 400w, https://j-riv.com/img/fxlrs-tank-800w-3RNuMRTOKX.webp 800w, https://j-riv.com/img/fxlrs-tank-1200w-3RNuMRTOKX.webp 1200w, https://j-riv.com/img/fxlrs-tank-1600w-3RNuMRTOKX.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxlrs-tank-400w-3RNuMRTOKX.jpeg&quot; alt=&quot;Harley Davidson FXLRS 5 Gallon Tank.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;1177&quot; srcset=&quot;https://j-riv.com/img/fxlrs-tank-400w-3RNuMRTOKX.jpeg 400w, https://j-riv.com/img/fxlrs-tank-800w-3RNuMRTOKX.jpeg 800w, https://j-riv.com/img/fxlrs-tank-1200w-3RNuMRTOKX.jpeg 1200w, https://j-riv.com/img/fxlrs-tank-1600w-3RNuMRTOKX.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Harley Davidson FXLRS 5 Gallon Tank.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The tank swap itself was pretty easy. The FXLRS tank is a direct bolt-on replacement for the Street Bob, but I did need a different fuel pump assembly.&lt;/p&gt;
&lt;p&gt;You could reuse the stock FXBBS fuel pump assembly, but you wouldn&#39;t be able to use all five gallons of fuel, which kind of defeats the purpose of doing the swap in the first place.&lt;/p&gt;
&lt;p&gt;The Low Rider S (FXLRS) fuel pump has an additional pickup that pulls fuel from the other side of the larger tank. It also uses a different fuel-level sender, which is needed for the bike to display the correct fuel level and range.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxlrs-tank-fuel-pump-400w-ABzvPwOnip.webp 400w, https://j-riv.com/img/fxlrs-tank-fuel-pump-800w-ABzvPwOnip.webp 800w, https://j-riv.com/img/fxlrs-tank-fuel-pump-1200w-ABzvPwOnip.webp 1200w, https://j-riv.com/img/fxlrs-tank-fuel-pump-1536w-ABzvPwOnip.webp 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxlrs-tank-fuel-pump-400w-ABzvPwOnip.jpeg&quot; alt=&quot;Harley Davidson FXLRS 5 Gallon Tank Fuel Pump.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1536&quot; height=&quot;2048&quot; srcset=&quot;https://j-riv.com/img/fxlrs-tank-fuel-pump-400w-ABzvPwOnip.jpeg 400w, https://j-riv.com/img/fxlrs-tank-fuel-pump-800w-ABzvPwOnip.jpeg 800w, https://j-riv.com/img/fxlrs-tank-fuel-pump-1200w-ABzvPwOnip.jpeg 1200w, https://j-riv.com/img/fxlrs-tank-fuel-pump-1536w-ABzvPwOnip.jpeg 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Harley Davidson FXLRS 5 Gallon Tank Fuel Pump.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Parts List&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;FXLRS Tank&lt;/li&gt;
&lt;li&gt;FXLRS Fuel Pump Module — &lt;code&gt;61200042&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tank Vent Plug x2 — &lt;code&gt;10500098&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tank Front Right Trim — &lt;code&gt;61400485&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tank Front Left Trim — &lt;code&gt;61400486&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tank Rear Right Trim — &lt;code&gt;61400487&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tank Rear Left Trim — &lt;code&gt;61400488&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Console Trim (should include gasket) — &lt;code&gt;70901156A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Console Screw — &lt;code&gt;10200141&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Console Washer — &lt;code&gt;10300128&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Console Retention Nut — &lt;code&gt;60900064&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Console Screw — &lt;code&gt;10201251&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Console Nut Clip — &lt;code&gt;8144&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxxbs-tank-swap-400w-IEdkrYB7-6.webp 400w, https://j-riv.com/img/fxxbs-tank-swap-800w-IEdkrYB7-6.webp 800w, https://j-riv.com/img/fxxbs-tank-swap-1200w-IEdkrYB7-6.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxxbs-tank-swap-400w-IEdkrYB7-6.jpeg&quot; alt=&quot;Harley Davidson FXLRS 5 Gallon Tank Installed.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1500&quot; srcset=&quot;https://j-riv.com/img/fxxbs-tank-swap-400w-IEdkrYB7-6.jpeg 400w, https://j-riv.com/img/fxxbs-tank-swap-800w-IEdkrYB7-6.jpeg 800w, https://j-riv.com/img/fxxbs-tank-swap-1200w-IEdkrYB7-6.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Harley Davidson FXLRS 5 Gallon Tank Installed.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The finished swap looks almost factory, which is exactly what I wanted. The larger tank fits the Softail frame really well and gives the Street Bob considerably more range without looking oversized.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-400w-zHoBDlBLoH.webp 400w, https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-800w-zHoBDlBLoH.webp 800w, https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-1200w-zHoBDlBLoH.webp 1200w, https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-1600w-zHoBDlBLoH.webp 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-400w-zHoBDlBLoH.jpeg&quot; alt=&quot;Harley Davidson Street Bob (FXBBS) with FXLRS 5 Gallon Tank Installed.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;2000&quot; srcset=&quot;https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-400w-zHoBDlBLoH.jpeg 400w, https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-800w-zHoBDlBLoH.jpeg 800w, https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-1200w-zHoBDlBLoH.jpeg 1200w, https://j-riv.com/img/fxbbs-fxlrs-tank-swap-top-view-1600w-zHoBDlBLoH.jpeg 1600w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Harley Davidson Street Bob (FXBBS) with FXLRS 5 Gallon Tank Installed. AKA the Street Rider.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;And there it is the &lt;strong&gt;Street Rider&lt;/strong&gt;.&lt;/p&gt;
</content>
    <summary>Swapping the Street Bob&#39;s 3.5-gallon tank for a 5-gallon Low Rider S tank, including the FXLRS fuel pump, sender, trim pieces, and everything needed to make the conversion work properly.</summary>
  </entry>
  
  <entry>
    <title>Harley Davidson Street Bob (FXBBS)</title>
    <link href="https://j-riv.com/blog/posts/2022-11-24-hd-fxbbs/"/>
    <updated>2022-11-24T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-11-24-hd-fxbbs/</id>
    <content type="html">&lt;p&gt;I went to the local Harley dealer just to look around and somehow came home with a brand new 2023 Street Bob 114 (FXBBS).&lt;/p&gt;
&lt;p&gt;I initially went in to look at two bikes: the Street Bob and the Low Rider S. Both are built on Harley&#39;s Softail platform, but they&#39;re pretty different bikes. The Low Rider S is more performance-oriented, with inverted forks, dual front disc brakes, and a generally more aggressive setup. The Street Bob, on the other hand, is a stripped-down bobber that&#39;s basically a blank canvas.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxbbs-stock-photo-400w-hWdaWDNCGP.webp 400w, https://j-riv.com/img/fxbbs-stock-photo-800w-hWdaWDNCGP.webp 800w, https://j-riv.com/img/fxbbs-stock-photo-1200w-hWdaWDNCGP.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxbbs-stock-photo-400w-hWdaWDNCGP.jpeg&quot; alt=&quot;Harley Davidson Street Bob (FXBBS)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;800&quot; srcset=&quot;https://j-riv.com/img/fxbbs-stock-photo-400w-hWdaWDNCGP.jpeg 400w, https://j-riv.com/img/fxbbs-stock-photo-800w-hWdaWDNCGP.jpeg 800w, https://j-riv.com/img/fxbbs-stock-photo-1200w-hWdaWDNCGP.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;My new 2023 Harley Davidson Street Bob 114 (FXBBS).&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Ultimately, I went with the Street Bob. The biggest factor was price, it was about $4,000 cheaper than the Low Rider S. That left a lot more money for mods and customization, and the stripped-down nature of the Street Bob meant I could build it into exactly what I wanted.&lt;/p&gt;
&lt;p&gt;I wasn&#39;t much of a fan of the orange tank graphic, but I figured I&#39;d deal with that later.&lt;/p&gt;
&lt;h2&gt;Time to void the warranty&lt;/h2&gt;
&lt;p&gt;After having the Street Bob for a few months, it was finally time to void the warranty.&lt;/p&gt;
&lt;p&gt;I mean, install some mods. :laughing:&lt;/p&gt;
&lt;p&gt;First on the list was getting rid of the stock exhaust, replacing the seat, and adding some sort of fairing to make highway riding a little more comfortable.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxbbs-first-mods-400w-twlnr1VMGr.webp 400w, https://j-riv.com/img/fxbbs-first-mods-800w-twlnr1VMGr.webp 800w, https://j-riv.com/img/fxbbs-first-mods-1200w-twlnr1VMGr.webp 1200w, https://j-riv.com/img/fxbbs-first-mods-1536w-twlnr1VMGr.webp 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxbbs-first-mods-400w-twlnr1VMGr.jpeg&quot; alt=&quot;Harley Davidson Street Bob (FXBBS)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1536&quot; height=&quot;2048&quot; srcset=&quot;https://j-riv.com/img/fxbbs-first-mods-400w-twlnr1VMGr.jpeg 400w, https://j-riv.com/img/fxbbs-first-mods-800w-twlnr1VMGr.jpeg 800w, https://j-riv.com/img/fxbbs-first-mods-1200w-twlnr1VMGr.jpeg 1200w, https://j-riv.com/img/fxbbs-first-mods-1536w-twlnr1VMGr.jpeg 1536w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Street Bob after the first round of modifications.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;Vance &amp;amp; Hines Short Shots&lt;/h3&gt;
&lt;p&gt;The stock exhaust was replaced with a set of Vance &amp;amp; Hines Short Shots. I had the same exhaust on my Sportster and always liked the way it looked, so this was an easy choice.&lt;/p&gt;
&lt;h3&gt;Saddlemen Step Up&lt;/h3&gt;
&lt;p&gt;The stock seat was fine around town, but anything longer than about an hour got uncomfortable pretty quickly. I replaced it with a Saddlemen Step Up, which also fit the direction I wanted to take the bike.&lt;/p&gt;
&lt;h3&gt;Memphis Shades Road Warrior&lt;/h3&gt;
&lt;p&gt;Since the Street Bob is a bobber, I was initially skeptical about putting a fairing on it. Eventually, I decided on a Memphis Shades Road Warrior and started leaning into more of a club-style look.&lt;/p&gt;
&lt;p&gt;While I was at it, I inverted the mirrors. To make that work, I used the turn signal mounts from a Low Rider S. It&#39;s a small change, but I think the front end looks much cleaner this way.&lt;/p&gt;
&lt;h2&gt;12-inch Lucky Dave&#39;s T-Bars&lt;/h2&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxbbs-tbar-install-400w-vvK21t0EEv.webp 400w, https://j-riv.com/img/fxbbs-tbar-install-800w-vvK21t0EEv.webp 800w, https://j-riv.com/img/fxbbs-tbar-install-1200w-vvK21t0EEv.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxbbs-tbar-install-400w-vvK21t0EEv.jpeg&quot; alt=&quot;Lucky Dave&#39;s The San Diego 12in T-Bars&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1500&quot; srcset=&quot;https://j-riv.com/img/fxbbs-tbar-install-400w-vvK21t0EEv.jpeg 400w, https://j-riv.com/img/fxbbs-tbar-install-800w-vvK21t0EEv.jpeg 800w, https://j-riv.com/img/fxbbs-tbar-install-1200w-vvK21t0EEv.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Lucky Dave&#39;s The San Diego 12-inch T-Bars.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;To keep the club-style theme going, the next modification was a set of 12-inch T-bars.&lt;/p&gt;
&lt;p&gt;Originally, I wanted IMZZ Dive Bars, but they were out of stock for months. I eventually went with Lucky Dave&#39;s The San Diego bars instead.&lt;/p&gt;
&lt;p&gt;The installation was actually pretty straightforward. With some patience and help from a friend, we got everything installed without much trouble. If you&#39;re comfortable working on your own bike, I&#39;d recommend doing the install yourself. It can save you a few hundred bucks in labor.&lt;/p&gt;
&lt;h2&gt;Getting rid of the orange&lt;/h2&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/fxbbs-black-tank-400w-jd5sDdpCbT.webp 400w, https://j-riv.com/img/fxbbs-black-tank-800w-jd5sDdpCbT.webp 800w, https://j-riv.com/img/fxbbs-black-tank-1200w-jd5sDdpCbT.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/fxbbs-black-tank-400w-jd5sDdpCbT.jpeg&quot; alt=&quot;2020 Street Bob Black Tank Swap&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1499&quot; srcset=&quot;https://j-riv.com/img/fxbbs-black-tank-400w-jd5sDdpCbT.jpeg 400w, https://j-riv.com/img/fxbbs-black-tank-800w-jd5sDdpCbT.jpeg 800w, https://j-riv.com/img/fxbbs-black-tank-1200w-jd5sDdpCbT.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;2020 Street Bob Black Tank Swap.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Remember that orange tank graphic I wasn&#39;t a fan of?&lt;/p&gt;
&lt;p&gt;Luckily, I found a black tank from a 2020 Street Bob on OfferUp. The Street Bobs that year were available with solid-color tanks, so swapping to the 2020 tank gave me the cleaner all-black look I wanted without having to repaint the original.&lt;/p&gt;
&lt;p&gt;That one change made a huge difference in the overall look of the bike.&lt;/p&gt;
&lt;h2&gt;Other mods&lt;/h2&gt;
&lt;p&gt;A few of the other modifications I&#39;ve added along the way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IMZZ OG Crash Bar&lt;/li&gt;
&lt;li&gt;Death Metal Racing clutch and brake levers&lt;/li&gt;
&lt;li&gt;Inverted mirrors&lt;/li&gt;
&lt;li&gt;Low Rider S turn signal mounts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, the bike looks quite a bit different from the Street Bob I originally rode home from the dealership, which was pretty much the plan from the beginning.&lt;/p&gt;
&lt;p&gt;There&#39;s still more I want to change, but that&#39;s part of the reason I chose the Street Bob in the first place. It&#39;s a simple platform with a ton of room to make it your own.&lt;/p&gt;
</content>
    <summary>From bringing home a new 2023 Street Bob 114 to making it my own with an exhaust, Saddlemen seat, Road Warrior fairing, T-bars, and a cleaner all-black tank swap.</summary>
  </entry>
  
  <entry>
    <title>Raspberry Pi 4 USB Boot</title>
    <link href="https://j-riv.com/blog/posts/2022-09-30-rasperry-pi-4-usb-boot/"/>
    <updated>2022-09-30T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-09-30-rasperry-pi-4-usb-boot/</id>
    <content type="html">&lt;p&gt;Raspberry Pi 1 - 3 contained all of their firmware on the SD Card. This has changed with the Raspberry Pi 4. The
device now has onboard upgradeable firmware stored on an EEPROM chip seperate from your storage. Updating this
firmware is very important as the newer updates reduce power usage, which in turn reduces how hot it gets.&lt;/p&gt;
&lt;p&gt;Theres a new utility called &lt;i&gt;rpi-eeprom&lt;/i&gt; to update bootloader firmware. To upgrade the firmware you should be
running the latest version of Raspberry Pi OS. Even if you do not plan on running this distribution this is easiest
way to update the firmware. After you&#39;ve successfully upgraded you can run whatever OS you want. I recommend keeping
an sd card with Raspberry Pi OS just for the purpose of upgrading the firmware every couple of months or so.&lt;/p&gt;
&lt;p&gt;Install rpi-eeprom (you should already have it installed but just in case).&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update
  &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; full-upgrade
  &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; rpi-eeprom&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that rpi-eeprom is installed, your pi will check for firmware updates at boot.&lt;/p&gt;
&lt;p&gt;Check for updates.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; rpi-eeprom-update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the firmware is not up to date this will let you know. If you need to update it run this command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; rpi-eeprom-update &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should now get a message telling you to reboot. Go ahead and change the boot order before rebooting.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; raspi-config&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will find the boot options under the advanced section. Select w/e you want and reboot. Your pi should now be able
to boot from USB. Go ahead and install w/e distribution you prefer on w/e usb storage you prefer.&lt;/p&gt;
&lt;p&gt;For my usb mass storage device, I personally chose to go with an M.2 SSD. You can get one of these for relatively
cheap these days. Do not go for an expensive one as your speed will be limited by the usb port. I got a PNY M.2 SSD
for around $24 on Amazon.&lt;/p&gt;
&lt;p&gt;I mounted the SSD via an expansion board, it gives it a cleaner look, compared to
running an ssd off of a usb dongle. You can pick one of these up on &lt;a href=&quot;https://www.amazon.com/gp/product/B088HCY4TH/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;psc=1&quot;&gt;Amazon&lt;/a&gt;&lt;/p&gt;
</content>
    <summary>How to update the Raspberry Pi 4&#39;s EEPROM bootloader, change its boot order, and move from an SD card to USB storage using an M.2 SSD for a cleaner and more reliable setup.</summary>
  </entry>
  
  <entry>
    <title>Raspberry Pi Cluster</title>
    <link href="https://j-riv.com/blog/posts/2022-05-01-raspberry-pi-cluster/"/>
    <updated>2022-05-01T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-05-01-raspberry-pi-cluster/</id>
    <content type="html">&lt;p&gt;I originally built this Raspberry Pi Cluster to learn how to use Kubernetes. It&#39;s built with 4 Raspberry Pi 4 8gb
boards and currently running Kubernetes with MicroK8s on Ubuntu Server 20.04 LTS.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/rpi-cluster-poe-with-switch-400w-G_KAV0mylP.webp 400w, https://j-riv.com/img/rpi-cluster-poe-with-switch-800w-G_KAV0mylP.webp 800w, https://j-riv.com/img/rpi-cluster-poe-with-switch-1080w-G_KAV0mylP.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/rpi-cluster-poe-with-switch-400w-G_KAV0mylP.jpeg&quot; alt=&quot;Raspberry Pi Cluster with PoE HATs and PoE switch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1440&quot; srcset=&quot;https://j-riv.com/img/rpi-cluster-poe-with-switch-400w-G_KAV0mylP.jpeg 400w, https://j-riv.com/img/rpi-cluster-poe-with-switch-800w-G_KAV0mylP.jpeg 800w, https://j-riv.com/img/rpi-cluster-poe-with-switch-1080w-G_KAV0mylP.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The cluster setup with PoE.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I had been looking for a way to power all 4 with one PSU, instead of 4 separate ones. At first I thought about using
some sort of powered USB hub but I don&#39;t think I would be able to get consistent power. I&#39;ve had issues before with
BrownOuts. I had seen people use desktop power supplies and convert them to 5v to power multiple Raspberry Pis but I
wanted something smaller and I wanted less cables. I already had to have the ethernet cables running to each Pi.&lt;/p&gt;
&lt;p&gt;So why not just use the Ethernet cables and ditch everything else? Well that&#39;s exactly what I did. Power over Ethernet
(PoE) is a technology that passes electric power over a twisted-pair Ethernet cable to powered devices (PD), such as
wireless access points, IP cameras, and VoIP phones in addition to the data that cable usually carries. It enables one
RJ45 cable to provide both data connection and electric power to PDs instead of having a separate cable for each. But
this wouldn&#39;t work without having to upgrade each Rasperry Pi first. So I picked up 4 Poe Hats. The PoE HAT allows you
to power your Raspberry Pi using Power over Ethernet–enabled networks; for this product to be used, the network it is
connected to needs to have power-sourcing equipment installed. So I also picked up a PoE switch, in my case I went
with the Zyxel 5 port Gigabit Switch (GS1005HP) due to it&#39;s small form factor.&lt;/p&gt;
&lt;p&gt;Now the real question, what should I do with it?&lt;/p&gt;
</content>
    <summary>Upgrading my four-node Raspberry Pi Kubernetes cluster with PoE HATs and a PoE switch, replacing separate power supplies with a cleaner single-cable setup for both power and networking.</summary>
  </entry>
  
  <entry>
    <title>The Mac Pro is Back</title>
    <link href="https://j-riv.com/blog/posts/2022-01-21-the-mac-pro-is-back/"/>
    <updated>2022-01-21T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-01-21-the-mac-pro-is-back/</id>
    <content type="html">&lt;p&gt;My first Mac Pro was from 2008 (MacPro3,1). I loved that thing everything about it was expandable. When my work
computer began to fail I was given a 2013 Mac Pro. What a difference in form factor. It went from a full blown tower
to a trash can looking thing. This was very different from my old Mac Pro. The exandability was very minimal. I loved
the old tower design. Everything was so easy to get to. The ram had its own boards that you could pull out to upgrade.
The hard drives were mounted on rails that you could easily get to and swap out.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/mac-pro-2013-uncovered-400w-Sqy0ugN0X2.webp 400w, https://j-riv.com/img/mac-pro-2013-uncovered-800w-Sqy0ugN0X2.webp 800w, https://j-riv.com/img/mac-pro-2013-uncovered-1080w-Sqy0ugN0X2.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/mac-pro-2013-uncovered-400w-Sqy0ugN0X2.jpeg&quot; alt=&quot;Mac Pro 2013 Uncovered&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;870&quot; srcset=&quot;https://j-riv.com/img/mac-pro-2013-uncovered-400w-Sqy0ugN0X2.jpeg 400w, https://j-riv.com/img/mac-pro-2013-uncovered-800w-Sqy0ugN0X2.jpeg 800w, https://j-riv.com/img/mac-pro-2013-uncovered-1080w-Sqy0ugN0X2.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The Mac Pro 2013 with its internals exposed.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;My biggest issue with the Mac Pro 2013 was that you had to use a bunch of dongles. So you ended up with a bunch of
wires coming out of it with the power button being on the same side. I also couldn&#39;t tell what the front or back was,
maybe that was just me. So I ended up trying to hide the cables by making them face the back and now I had to reach
the back of it to turn it on. It was also not very upgradeable, but at least the ram was.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/mac-pro-2019-open-400w-cVL0TR8Irl.webp 400w, https://j-riv.com/img/mac-pro-2019-open-800w-cVL0TR8Irl.webp 800w, https://j-riv.com/img/mac-pro-2019-open-1080w-cVL0TR8Irl.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/mac-pro-2019-open-400w-cVL0TR8Irl.jpeg&quot; alt=&quot;Mac Pro 2019 Open&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1440&quot; srcset=&quot;https://j-riv.com/img/mac-pro-2019-open-400w-cVL0TR8Irl.jpeg 400w, https://j-riv.com/img/mac-pro-2019-open-800w-cVL0TR8Irl.jpeg 800w, https://j-riv.com/img/mac-pro-2019-open-1080w-cVL0TR8Irl.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The Mac Pro 2019 with its internals exposed.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It was now time to upgrade my work setup again. This time I was given a Mac Pro 2019. Let&#39;s just say the Mac Pro is
back! The tower form factor is back and with it upgradability and expandability. I&#39;m not much of a fan of the new
cheese grater front panel design but I&#39;m happy that they returned to the tower form factor.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/mac-pro-2019-ram-upgrade-400w-1rFev_OznM.webp 400w, https://j-riv.com/img/mac-pro-2019-ram-upgrade-800w-1rFev_OznM.webp 800w, https://j-riv.com/img/mac-pro-2019-ram-upgrade-1080w-1rFev_OznM.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/mac-pro-2019-ram-upgrade-400w-1rFev_OznM.jpeg&quot; alt=&quot;Mac Pro 2019 RAM Upgrade&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1440&quot; srcset=&quot;https://j-riv.com/img/mac-pro-2019-ram-upgrade-400w-1rFev_OznM.jpeg 400w, https://j-riv.com/img/mac-pro-2019-ram-upgrade-800w-1rFev_OznM.jpeg 800w, https://j-riv.com/img/mac-pro-2019-ram-upgrade-1080w-1rFev_OznM.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The Mac Pro 2019 with its RAM upgrade exposed.&lt;/figcaption&gt;&lt;/figure&gt;
</content>
    <summary>After years with the compact and limited 2013 Mac Pro, moving to the 2019 model feels like a return to what made the original Mac Pro great: a proper tower with accessible, upgradeable hardware.</summary>
  </entry>
  
  <entry>
    <title>Dell T620</title>
    <link href="https://j-riv.com/blog/posts/2022-01-20-dell-t620/"/>
    <updated>2022-01-20T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-01-20-dell-t620/</id>
    <content type="html">&lt;p&gt;I finally got a real server to play with. I bought a used Dell PowerEdge T620 Server. It came with dual Xeon 8 Core
Processors, 32gb of ram, 4 600gb SAS drives and dual 750w power supplies.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/dell-t620-front-400w-7w75k85P5o.webp 400w, https://j-riv.com/img/dell-t620-front-800w-7w75k85P5o.webp 800w, https://j-riv.com/img/dell-t620-front-1080w-7w75k85P5o.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/dell-t620-front-400w-7w75k85P5o.jpeg&quot; alt=&quot;Dell T620 Front&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1440&quot; srcset=&quot;https://j-riv.com/img/dell-t620-front-400w-7w75k85P5o.jpeg 400w, https://j-riv.com/img/dell-t620-front-800w-7w75k85P5o.jpeg 800w, https://j-riv.com/img/dell-t620-front-1080w-7w75k85P5o.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The front view of the Dell PowerEdge T620 server.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I purchased this server to mess with virtualization environments. I wasn&#39;t really going to use it for anything
serious so I decided to run the SAS drives in RAID 0 and I got 2 Samsung EVOs for my boot drive and ran them in RAID
0 as well. I found some cheap used Cisco ram on eBay so I upgraded the ram to 192gb.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/dell-t620-open_full-400w-HaHa4y9Pxr.webp 400w, https://j-riv.com/img/dell-t620-open_full-800w-HaHa4y9Pxr.webp 800w, https://j-riv.com/img/dell-t620-open_full-1080w-HaHa4y9Pxr.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/dell-t620-open_full-400w-HaHa4y9Pxr.jpeg&quot; alt=&quot;Dell T620 Open&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1440&quot; srcset=&quot;https://j-riv.com/img/dell-t620-open_full-400w-HaHa4y9Pxr.jpeg 400w, https://j-riv.com/img/dell-t620-open_full-800w-HaHa4y9Pxr.jpeg 800w, https://j-riv.com/img/dell-t620-open_full-1080w-HaHa4y9Pxr.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The open view of the Dell PowerEdge T620 server.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This Dell T620 can currently run 8 hard drives and can either boot from a hard drive or from an internal flash drive.
It did not come with an OS. They usually have some sort of Windows Server installed. I opted to install Ubuntu Server
20.04 LTS, since I&#39;m pretty familiar with it, but I plan on eventually trying out VMWare ESXi.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/dell-t620-front-open-400w-ygeH88rNyu.webp 400w, https://j-riv.com/img/dell-t620-front-open-800w-ygeH88rNyu.webp 800w, https://j-riv.com/img/dell-t620-front-open-1080w-ygeH88rNyu.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/dell-t620-front-open-400w-ygeH88rNyu.jpeg&quot; alt=&quot;Dell PowerEdge T620 - Open Front Panel&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1440&quot; srcset=&quot;https://j-riv.com/img/dell-t620-front-open-400w-ygeH88rNyu.jpeg 400w, https://j-riv.com/img/dell-t620-front-open-800w-ygeH88rNyu.jpeg 800w, https://j-riv.com/img/dell-t620-front-open-1080w-ygeH88rNyu.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Dell PowerEdge T620 - Open Front Panel&lt;/figcaption&gt;&lt;/figure&gt;
</content>
    <summary>Adding my first real enterprise server to the homelab: a used Dell PowerEdge T620 with dual Xeons, RAID storage, and 192 GB of RAM for experimenting with virtualization and server infrastructure.</summary>
  </entry>
  
  <entry>
    <title>How to Install Arch Linux on RPi4 with USB Boot</title>
    <link href="https://j-riv.com/blog/posts/2022-01-18-how-to-install-arch-linux-on-rpi4-with-usb-boot/"/>
    <updated>2022-01-18T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-01-18-how-to-install-arch-linux-on-rpi4-with-usb-boot/</id>
    <content type="html">&lt;p&gt;In this tutorial I will cover a step by step Arch Linux Installation on a Raspberry Pi 4 with usb boot.&lt;/p&gt;
&lt;p&gt;This is the way it worked for me, there must be an easier way, if so please let me know.&lt;/p&gt;
&lt;p&gt;We will first have to install Arch on an SD card and then re-install it on an SSD (or copy it over to the SSD).&lt;/p&gt;
&lt;h3&gt;Install Arch on an SD Card&lt;/h3&gt;
&lt;p&gt;Replace &lt;strong&gt;sdX&lt;/strong&gt; in the following instructions with the device name for the SSD as it appears on your computer.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fdisk&lt;/span&gt; /dev/sdX&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the fdisk prompt, delete old partitions and create a new one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type &lt;strong&gt;o&lt;/strong&gt;. This will clear out any partitions on the drive.&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;p&lt;/strong&gt; to list partitions. There should be no partitions left.&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;n&lt;/strong&gt;, then &lt;strong&gt;p&lt;/strong&gt; for primary, &lt;strong&gt;1&lt;/strong&gt; for the first partition on the drive, press ENTER to accept the default first sector, then type &lt;strong&gt;+200M&lt;/strong&gt; for the last sector.&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;t&lt;/strong&gt;, then &lt;strong&gt;c&lt;/strong&gt; to set the first partition to type W95 FAT32 (LBA).&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;n&lt;/strong&gt;, then &lt;strong&gt;p&lt;/strong&gt; for primary, &lt;strong&gt;2&lt;/strong&gt; for the second partition on the drive, and then press ENTER twice to accept the default first and last sector.&lt;/li&gt;
&lt;li&gt;Write the partition table and exit by typing &lt;strong&gt;w&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Create and mount the FAT Filesystem:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.vfat /dev/sdX1
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; boot
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; /dev/sdX1 boot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create and mount the ext4 Filesystem:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.ext4 /dev/sdX2
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; root
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; /dev/sdX2 root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Download and extract the root filesystem (as root, not via sudo):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz
bsdtar &lt;span class=&quot;token parameter variable&quot;&gt;-xpf&lt;/span&gt; ArchLinuxARM-rpi-armv7-latest.tar.gz &lt;span class=&quot;token parameter variable&quot;&gt;-C&lt;/span&gt; root
&lt;span class=&quot;token function&quot;&gt;sync&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Move boot files to the first partition:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mv&lt;/span&gt; root/boot/* boot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before unmounting the partitions, update /etc/fstab for the different SD block device compared to the Raspberry Pi 3:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;s/mmcblk0/mmcblk1/g&#39;&lt;/span&gt; root/etc/fstab&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unmount the two partitions:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;umount&lt;/span&gt; boot root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Insert the SD card into the Raspberry Pi, connect ethernet, and apply 5v power. Connect your SSD via one of the available USB 3s.&lt;/p&gt;
&lt;p&gt;Use the serial console or SSH to the IP address given to the board by your router.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Login as the default user alarm with the password alarm.&lt;/li&gt;
&lt;li&gt;The default root password is root.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you&#39;re logged in we will now re-start the installation, this time on the SSD.&lt;/p&gt;
&lt;p&gt;Replace &lt;strong&gt;sdX&lt;/strong&gt; in the following instructions with the device name for the SSD as it appears on your computer.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fdisk&lt;/span&gt; /dev/sdX&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the fdisk prompt, delete old partitions and create a new one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type &lt;strong&gt;o&lt;/strong&gt;. This will clear out any partitions on the drive.&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;p&lt;/strong&gt; to list partitions. There should be no partitions left.&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;n&lt;/strong&gt;, then &lt;strong&gt;p&lt;/strong&gt; for primary, &lt;strong&gt;1&lt;/strong&gt; for the first partition on the drive, press ENTER to accept the default first sector, then type &lt;strong&gt;+200M&lt;/strong&gt; for the last sector.&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;t&lt;/strong&gt;, then &lt;strong&gt;c&lt;/strong&gt; to set the first partition to type W95 FAT32 (LBA).&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;n&lt;/strong&gt;, then &lt;strong&gt;p&lt;/strong&gt; for primary, &lt;strong&gt;2&lt;/strong&gt; for the second partition on the drive, and then press ENTER twice to accept the default first and last sector.&lt;/li&gt;
&lt;li&gt;Write the partition table and exit by typing &lt;strong&gt;w&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Create and mount the FAT Filesystem:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.vfat /dev/sdX1
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; boot
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; /dev/sdX1 boot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create and mount the ext4 Filesystem:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.ext4 /dev/sdX2
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; root
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; /dev/sdX2 root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Download and extract the root filesystem (as root, not via sudo):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz
bsdtar &lt;span class=&quot;token parameter variable&quot;&gt;-xpf&lt;/span&gt; ArchLinuxARM-rpi-armv7-latest.tar.gz &lt;span class=&quot;token parameter variable&quot;&gt;-C&lt;/span&gt; root
&lt;span class=&quot;token function&quot;&gt;sync&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Move boot files to the first partition:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mv&lt;/span&gt; root/boot/* boot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add pcie_brcmstb into Modules in /etc/mkinitcpio.conf and root/etc/mkinitcpio.conf:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /etc/mkinitcpio.conf
&lt;span class=&quot;token comment&quot;&gt;# add pcie_brcmstb into MODULES and save&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; root/etc/mkinitcpio.conf
&lt;span class=&quot;token comment&quot;&gt;# add pcie_brcmstb into MODULES and save&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkinitcpio &lt;span class=&quot;token parameter variable&quot;&gt;-P&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copy the 2 files it created in the host /boot (SD Card) to the boot directory you have /dev/sdX1 mounted on.&lt;/p&gt;
</content>
    <summary>A step-by-step guide to installing Arch Linux ARM on a Raspberry Pi 4 and configuring it to boot from an SSD over USB instead of relying on an SD card.</summary>
  </entry>
  
  <entry>
    <title>What&#39;s a Raspberry Pi?</title>
    <link href="https://j-riv.com/blog/posts/2022-01-16-whats-a-raspberrry-pi/"/>
    <updated>2022-01-16T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-01-16-whats-a-raspberrry-pi/</id>
    <content type="html">&lt;p&gt;The Raspberry Pi is a low cost, credit-card sized computer that plugs into a computer monitor or tv. It was
originally developed by the Raspberry Pi Foundation to promote teaching of basic computer science in schools and
developing countries. It has grown to be much, much more. It&#39;s low cost and portability has made it popular outside
its target market for uses such as web servers, media centers, game emulators, robotics and maker projects. As of
December 2019, more than thirty million boards have been sold.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/raspberry-pi-400w-gf2gCh-km4.webp 400w, https://j-riv.com/img/raspberry-pi-800w-gf2gCh-km4.webp 800w, https://j-riv.com/img/raspberry-pi-1080w-gf2gCh-km4.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/raspberry-pi-400w-gf2gCh-km4.jpeg&quot; alt=&quot;Raspberry Pi&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;785&quot; srcset=&quot;https://j-riv.com/img/raspberry-pi-400w-gf2gCh-km4.jpeg 400w, https://j-riv.com/img/raspberry-pi-800w-gf2gCh-km4.jpeg 800w, https://j-riv.com/img/raspberry-pi-1080w-gf2gCh-km4.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;A Raspberry Pi board.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There have been several generations of Raspberry Pis released. All models feature a Broadcom system on a chip (SoC)
with an integrated ARM-compatible CPU and on-chip GPU. Processor speeds range from 700 MHz to 1.5GHz and RAM ranges
from 256 MiB to 8 GiB depending on model and generation.&lt;/p&gt;
&lt;h2&gt;What can you do with one?&lt;/h2&gt;
&lt;p&gt;There are many things you can do or make with a Raspberry Pi. For instance:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;You can use a Raspberry Pi as a desktop computer and learn to code with Scratch or any of the included software
        (&lt;a href=&quot;https://www.raspberrypi.org/downloads/raspberry-pi-os/&quot; target=&quot;_blank&quot;&gt;Raspbian or Raspberry Pi
            OS)&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;Learn how to use Linux without the fear of messing up your computer.&lt;/li&gt;
    &lt;li&gt;Create a website and run it on your very own web server.&lt;/li&gt;
    &lt;li&gt;Build a robot.&lt;/li&gt;
    &lt;li&gt;Run it as a media center with something like &lt;a href=&quot;https://osmc.tv/&quot; target=&quot;_blank&quot;&gt;OSMC&lt;/a&gt; or &lt;a href=&quot;https://libreelec.tv/&quot; target=&quot;_blank&quot;&gt;LibreELEC&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;Create a VPN to access your home network from anywhere.&lt;/li&gt;
    &lt;li&gt;Retro Game Emulator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can tell I love the Pi. Tinkering with a Raspberry Pi has quickly become a hobby of mine. It&#39;s amazing what
you can create with a bit of imagination and time.&lt;/p&gt;
</content>
    <summary>An introduction to the Raspberry Pi, the inexpensive ARM-powered computer that became a favorite among developers and makers, along with some of the projects and experiments you can build with one.</summary>
  </entry>
  
  <entry>
    <title>Dell T5600</title>
    <link href="https://j-riv.com/blog/posts/2022-01-11-dell-t5600/"/>
    <updated>2022-01-11T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-01-11-dell-t5600/</id>
    <content type="html">&lt;p&gt;I picked up a Dell T5600 Precision Workstation to use for home automation / virtualization, but hadn&#39;t really done
anything with it. Today I decided to make it run my Plex Server, some services and some minor home automation like lights, and all this will run
within containers.&lt;/p&gt;
&lt;p&gt;First I needed to upgrade the boot drive from a 500gb hard drive (spinning rust), to an SSD. I had a spare 500gb SSD
laying around so I decided to use that. I also needed at least one other hard drive to use for storage. I decided to
go with 2 WD Red NAS hard drives. I picked up a 12tb and 14tb on Amazon during a flash sale. The size difference
didn&#39;t really matter to me since I wasn&#39;t going to be running them in Raid. I upgraded the ram to 128gb, got the ram
for pretty cheap on eBay. The final specs are: dual Xeon E5-2670 8 Core processors, for a total of 16 cores / 32
threads. 128 gb of ram, 500gb SSD boot drive and 26tb of storage.&lt;/p&gt;
&lt;p&gt;For the OS I decided to go with &lt;a href=&quot;https://ubuntu.com/download/server&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt; Ubuntu
Server 20.04 LTS&lt;/a&gt;. I don&#39;t need a desktop environment on this since it&#39;s just going to
run services in the background. If and when I need to connect to it I will simply ssh into the machine. From there I
installed &amp;lt;a href=&amp;quot;https://docs.docker.com/engine/install/&amp;quot; rel=norefferer&amp;quot;&amp;gt;docker and &amp;lt;a
href=&amp;quot;https://docs.docker.com/compose/install/&amp;quot; rel=norefferer&amp;quot;&amp;gt;docker-compose. I could have gone with podman
but I&#39;m just currently more familiar with docker.&lt;/p&gt;
&lt;p&gt;For my reverse proxy I decided to use Traefik due to it&#39;s &lt;a href=&quot;https://doc.traefik.io/traefik/https/acme/&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;automatic HTTPS&lt;/a&gt; via Let&#39;s Encrypt. From there I just use a basic docker compose
file. You can find a docker-compose / Traefik v2 example &lt;a href=&quot;https://github.com/j-Riv/rpi_docker&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;here&lt;/a&gt; (Rasbperry Pi Version).&lt;/p&gt;
&lt;p&gt;The docker-compose file lists 4 containers: Tautulli, Plex, NetData and Home API.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Tautulli is a web app to monitor, view analytics, and receive notifications about your Plex Media Server.&lt;/li&gt;
  &lt;li&gt;Plex is a global streaming media service and a client–server media player platform.&lt;/li&gt;
  &lt;li&gt;Netdata is an open source tool designed to collect real-time metrics, such as CPU usage, disk activity, bandwidth
    usage, website visits, etc., and then display them in live, easy-to-interpret charts&lt;/li&gt;
  &lt;li&gt;Home API is a custom REST API I made to control my Philips Hue Lights, by using the Philips Hue API. You can view
    it &lt;a href=&quot;https://github.com/j-Riv/home_api&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;here&lt;/a&gt;. Currently it can only
    control Philips Hue
    Lights but as necessity grows and time permits I will keep adding to it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use Tautulli to send notifications (webhooks) to my Home API which then turns on, turns off or dims the lights
according to the Plex triggers set. For example turning off the lights when the video starts playing. Turning on the
lights when the video stops playing, or pauses. The Home API uses the Philips Hue API to control the lights. This
could also be accomplished by using a service like &lt;a href=&quot;https://ifttt.com/&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;IFTT&lt;/a&gt;, they have integrations for everything. I just wanted to keep it all in my network.&lt;/p&gt;
&lt;p&gt;Thanks to containers, I can bring down, bring up, destroy and rebuild this stack whenever I want and the data is&lt;/p&gt;
&lt;p&gt;persistant and stored in docker volumes on bare metal.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/t5600-neofetch-400w-e46t_IStrK.webp 400w, https://j-riv.com/img/t5600-neofetch-800w-e46t_IStrK.webp 800w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/t5600-neofetch-400w-e46t_IStrK.jpeg&quot; alt=&quot;Dell T5600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;800&quot; srcset=&quot;https://j-riv.com/img/t5600-neofetch-400w-e46t_IStrK.jpeg 400w, https://j-riv.com/img/t5600-neofetch-800w-e46t_IStrK.jpeg 800w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The Dell T5600 workstation.&lt;/figcaption&gt;&lt;/figure&gt;
</content>
    <summary>Turning a Dell Precision T5600 into a 16-core, 128 GB homelab server running Plex, monitoring, and custom home automation services with Ubuntu Server, Docker, Traefik, and a custom Philips Hue API.</summary>
  </entry>
  
  <entry>
    <title>Thinkpad T14 Fedora</title>
    <link href="https://j-riv.com/blog/posts/2022-01-10-thinkpad-t14-fedora/"/>
    <updated>2022-01-10T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-01-10-thinkpad-t14-fedora/</id>
    <content type="html">&lt;p&gt;I&#39;m starting to prefer developing on Linux, instead of on macOS. Only issue I have with Linux is the lack of Adobe
support when I have to open any Adobe files. I have a 2018 MacBook Pro but I wanted a new Linux laptop. I&#39;ve always
heard about how wonderful the ThinkPad keyboards were. I really dislike the MacBook&#39;s butterfly keyboard and the XPS
keyboard isn&#39;t great either. Both are chicklet style.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/dell-xps-13-arch-linux-400w-uRwIG-gTbY.webp 400w, https://j-riv.com/img/dell-xps-13-arch-linux-800w-uRwIG-gTbY.webp 800w, https://j-riv.com/img/dell-xps-13-arch-linux-1200w-uRwIG-gTbY.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/dell-xps-13-arch-linux-400w-uRwIG-gTbY.jpeg&quot; alt=&quot;Dell XPS 13 running Arch Linux &quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;900&quot; srcset=&quot;https://j-riv.com/img/dell-xps-13-arch-linux-400w-uRwIG-gTbY.jpeg 400w, https://j-riv.com/img/dell-xps-13-arch-linux-800w-uRwIG-gTbY.jpeg 800w, https://j-riv.com/img/dell-xps-13-arch-linux-1200w-uRwIG-gTbY.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Dell XPS 13 running Arch Linux&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;My Dell XPS 13 only has 8gb of ram. Surprisingly I don&#39;t really notice the limitation. But I am running Arch Linux on
it, which may be why. In my next Linux Developer Laptop I wanted to have at least 16gb of ram, preferably 32gb. The
XPS has sodered ram, so what you get is what you get. You cannot upgrade it later. I didn&#39;t want to make that mistake
again. I also wanted a CPU with more cores. So I decided to go with an AMD Ryzen.&lt;/p&gt;
&lt;p&gt;I started doing my research and found that Lenovo now makes a T14 with an AMD Ryzen chip. Lenovo&#39;s site had a 3 month
wait for the specs I wanted. I wanted at least a 500gb ssd, preferably NVMe. 16gb of ram or better, let&#39;s face it the
more the merrier :P. I also wanted a Ryzen 5 or 7. Originally I was worried about cooling issues with the Ryzen 7.
Since I had read that the T14&#39;s predecessor, the ThinkPad T495 had cooling issues. After watching a few reviews I
decided to go with the Ryzen 7 version. I looked online for something close to the specs I wanted and found an Amazon
listing for a T14 with a 1tb NVMe, 32gb of ram, and a Ryzen 7. The only spec I wasn&#39;t a fan of was the touch screen. I
would have preferred a non-touch screen. I believe I can swap it out later but it&#39;s not really an issue other than
battery life. I didn&#39;t want to wait 3 months for it to be built by Lenovo, so I purchased it on Amazon and It arrived
fairly quickly.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/thinkpad-t14-fedora-400w-vwiVuz-CS-.webp 400w, https://j-riv.com/img/thinkpad-t14-fedora-800w-vwiVuz-CS-.webp 800w, https://j-riv.com/img/thinkpad-t14-fedora-1200w-vwiVuz-CS-.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/thinkpad-t14-fedora-400w-vwiVuz-CS-.jpeg&quot; alt=&quot;ThinkPad T14 running Fedora&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;900&quot; srcset=&quot;https://j-riv.com/img/thinkpad-t14-fedora-400w-vwiVuz-CS-.jpeg 400w, https://j-riv.com/img/thinkpad-t14-fedora-800w-vwiVuz-CS-.jpeg 800w, https://j-riv.com/img/thinkpad-t14-fedora-1200w-vwiVuz-CS-.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;ThinkPad T14 running Fedora&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The ThinkPad arrived with Windows 10 installed. I now had to choose what Linux distro to use. I tend to preffer Arch,
or Arch based distros like Manjaro. My Dell XPS 13 and desktop PC are both currently running Arch. So Arch was very
appealing. But I also like Fedora and Lenovo had just certified Fedora and Ubuntu on their machines. You could now
purchase a &lt;a href=&quot;https://fedoramagazine.org/lenovo-fedora-now-available/&quot; alt=&quot;Now available: Fedora on Lenovo Laptops!&quot; rel=&quot;noreferrer&quot;&gt;ThinkPad with Fedora pre-installed&lt;/a&gt;. So I decided
to give Fedora 33 a try. To my surprise everything just worked. From the touchscreen to the fingerprint reader. Even
the firmware updater was flawless. Fedora has done a great job.&lt;/p&gt;
&lt;p&gt;I might end up swapping Fedora for Arch on this machine in the future, but for now it just works and I like having
both a Fedora and an Arch machine. So far I would recommend the Lenovo ThinkPad T14 to anyone looking for a Laptop to
run Linux on.&lt;/p&gt;
</content>
    <summary>My search for a better Linux development laptop led me to the AMD-powered ThinkPad T14. Here&#39;s why I chose it, how Fedora handled the hardware, and my experience moving away from macOS for development.</summary>
  </entry>
  
  <entry>
    <title>Intel Nuc Home Server</title>
    <link href="https://j-riv.com/blog/posts/2022-01-06-intel-nuc-home-server/"/>
    <updated>2022-01-06T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-01-06-intel-nuc-home-server/</id>
    <content type="html">&lt;p&gt;I like to mess with computers. This hobby could get pretty expensive. So I often scour places like craigslist,
offerup, eBay and the facebook marketplace for deals. I recently picked up 2 Intel NUCs. I was looking for something
small to use as a home server. I have used Raspberry Pis for this but I kind of wanted something a bit more powerful.
The Intel NUC is a small form factor x86 PC. You get full sized PC power in the palm of your hand. NUC stands for
&lt;em&gt;Next Unit of Computing&lt;/em&gt;.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/intel-nuc-arch-linux-400w-DmqvTtvThI.webp 400w, https://j-riv.com/img/intel-nuc-arch-linux-800w-DmqvTtvThI.webp 800w, https://j-riv.com/img/intel-nuc-arch-linux-1080w-DmqvTtvThI.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/intel-nuc-arch-linux-400w-DmqvTtvThI.jpeg&quot; alt=&quot;Intel NUC with Arch Linux&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;752&quot; srcset=&quot;https://j-riv.com/img/intel-nuc-arch-linux-400w-DmqvTtvThI.jpeg 400w, https://j-riv.com/img/intel-nuc-arch-linux-800w-DmqvTtvThI.jpeg 800w, https://j-riv.com/img/intel-nuc-arch-linux-1080w-DmqvTtvThI.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The Intel NUC running Arch Linux.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The NUC is basically a laptop without the keyboard and display. It is available with ATOM, Celeron, Pentium and all
three variants of core ultra-low power (U) processors. Unlike CPUs intended for a more traditional ATX-based build,
NUC processors are hard-soldered to the mainboard, and are&#39;t intended to be installed, uninstalled, or swapped
out by the end-user. The NUC is sold as a full operational system with different specs, or as a kit. The kit does not
come with ram, storage or an operating system.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/intel-nuc-skull-canyon-400w-WIl4b50Ksg.webp 400w, https://j-riv.com/img/intel-nuc-skull-canyon-800w-WIl4b50Ksg.webp 800w, https://j-riv.com/img/intel-nuc-skull-canyon-1080w-WIl4b50Ksg.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/intel-nuc-skull-canyon-400w-WIl4b50Ksg.jpeg&quot; alt=&quot;Intel NUC Skull Canyon&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1350&quot; srcset=&quot;https://j-riv.com/img/intel-nuc-skull-canyon-400w-WIl4b50Ksg.jpeg 400w, https://j-riv.com/img/intel-nuc-skull-canyon-800w-WIl4b50Ksg.jpeg 800w, https://j-riv.com/img/intel-nuc-skull-canyon-1080w-WIl4b50Ksg.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The Intel NUC Skull Canyon model.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I picked an Intel NUC Skull Canyon (NUC6i7KYK) which is supposed to be the performance edition, geared towards gaming
and a base Intel NUC (NUC7i5BNK). The Skull Canyon came with a 6th generation i7, 480gb ssd and 16gb of ram. The base
NUC came with a 7th generation Intel i5, 512gb ssd and 8gb of ram. Both of the NUCs I purchased were complete and
operational, but I decided to upgrade and max out the ram at 32gb.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/intel-nuc-400w-QlrsatWRY8.webp 400w, https://j-riv.com/img/intel-nuc-800w-QlrsatWRY8.webp 800w, https://j-riv.com/img/intel-nuc-1080w-QlrsatWRY8.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/intel-nuc-400w-QlrsatWRY8.jpeg&quot; alt=&quot;Intel NUC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1350&quot; srcset=&quot;https://j-riv.com/img/intel-nuc-400w-QlrsatWRY8.jpeg 400w, https://j-riv.com/img/intel-nuc-800w-QlrsatWRY8.jpeg 800w, https://j-riv.com/img/intel-nuc-1080w-QlrsatWRY8.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The Intel NUC.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Both NUCs came pre-installed with Windows. I opted to install Arch Linux on them instead. Once I installed the OS
everything ran smooth on the base NUC, the Skull Canyon on the other hand had display issues. After some
troubleshooting and some help from forums and twitter I figured out there was an issue with the HDMI firmware on
Linux. The fix was only available on Windows, but there was a workaround, a displayport to HDMI adapter. This seemed
to fix the issue.&lt;/p&gt;
&lt;p&gt;Overall I&#39;m pretty happy with both NUCs. I&#39;ll probably end up getting rid of the Skull Canyon as I prefer the base NUC
form factor but both would make great tv computers or media players. Now the search begins for a real production grade
server.&lt;/p&gt;
</content>
    <summary>Turning a pair of used Intel NUCs into compact Arch Linux home servers, including hardware upgrades, a troublesome Skull Canyon HDMI issue, and my experience using NUCs as more powerful Raspberry Pi alternatives.</summary>
  </entry>
  
  <entry>
    <title>Dogs</title>
    <link href="https://j-riv.com/blog/posts/2022-01-01-dogs/"/>
    <updated>2022-01-01T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2022-01-01-dogs/</id>
    <content type="html">&lt;p&gt;It&#39;s been awhile since I wrote anything on here, I&#39;ve been pretty busy with work and life in general. Even more now
that I got a second dog. I wasn&#39;t looking for another dog, since I already had one, but life happens. I have a 6 year
old pug named Henry. You can find him &lt;a href=&quot;https://henrythepug.com/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; or follow him on
Instagram at &lt;a href=&quot;https://instagram.com/puganddestroy&quot; target=&quot;_blank&quot;&gt;@puganddestroy&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-not-happy-about-nero-400w-EZ94D8vcMG.webp 400w, https://j-riv.com/img/henry-not-happy-about-nero-800w-EZ94D8vcMG.webp 800w, https://j-riv.com/img/henry-not-happy-about-nero-1080w-EZ94D8vcMG.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-not-happy-about-nero-400w-EZ94D8vcMG.jpeg&quot; alt=&quot;Henry Not Happy About Nero&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;944&quot; srcset=&quot;https://j-riv.com/img/henry-not-happy-about-nero-400w-EZ94D8vcMG.jpeg 400w, https://j-riv.com/img/henry-not-happy-about-nero-800w-EZ94D8vcMG.jpeg 800w, https://j-riv.com/img/henry-not-happy-about-nero-1080w-EZ94D8vcMG.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Henry the pug looking unhappy about Nero the German Shepherd.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I adopted a 7 month old German Shepherd. All I was told was he was 7 months old and had already had 3 homes. His
previous owners had returned him because he was too high energy, too destructive, didn&#39;t get along with other dogs and
was basically too much &amp;quot;trouble&amp;quot;. Because of this, I was hesitant to take him on at first. I kept thinking what kind`
of devil is this little guy? I didn&#39;t want to bring a dog into my home that would harm my pug. I thought it over for a
week and then told myself &amp;quot;How bad could he really be?&amp;quot;. I didn&#39;t want him to end up at the shelter so I took him and
I&#39;m really glad I did. We named him &lt;strong&gt;Nero&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;When I first got Nero about 2 months ago I couldn&#39;t take him anywhere. He was dog reactive, and he would lunge and
chase anything that moved. He was super high energy. He just woudn&#39;t stop, no off switch. He still doesn&#39;t. He&#39;s got
one speed and that&#39;s &lt;strong&gt;GO&lt;/strong&gt;. I began to think maybe I had made a mistake, maybe he was too much dog for
me too, but I wasn&#39;t about to give him up. Instead I did the only thing I know how to do and thats read the docs. In
this case, I joined forums and facebook groups. I started watching and listening to dog training videos and dog
training podcasts. I even got a few books to read. I also enrolled him in training to give me a base to build upon
from. I made it my goal to make this work and make this, his fourth and final home. His forever home.&lt;/p&gt;
&lt;p&gt;It&#39;s been 2 months of consistent training, and you can already see the difference. He&#39;s not perfect, but practice
will make perfect. If his previous owners had just taken the time to give him the structure that he needed, he
wouldn&#39;t have had such a shitty first few months of life. They failed him, not the other way around.&lt;/p&gt;
&lt;p&gt;Nero wasn&#39;t and isn&#39;t a bad dog. He&#39;s just a Shepherd puppy. German Shepherd&#39;s are bred to do a job. They need a job.
If you don&#39;t give them a job, they will find a job and it will more than likely not be something you want them doing.
You don&#39;t get a herding dog and then complain that he herds. That&#39;s what they do. People need to really do
their research before they go out and get a dog. Dog&#39;s are not something you should just get on a whim or just throw
away like yesterdays trash. Getting a dog is and should be a commitment. Your committing to having this dog for it&#39;s
entire life, this could be 10+ years.&lt;/p&gt;
&lt;p&gt;I used to think that training your dog was unecessary. I guess I was just lucky with my pug, Henry. We bonded really
well and I&#39;ve never had issues with him even though I&#39;ve never really trained him. He just seems to always want to be
around me and make me happy. Now I believe training is a must. There is no better feeling than having a dog you can
trust and depend on to make the right decisions. If people trained their dogs there would be less dogs at the shelter.
Most shelter dogs are there because of obedience problems. Training your dog will make you and your dog happier as
well as your bond stronger.&lt;/p&gt;
&lt;p&gt;Nero is now at his forever home. We will have our good and bad days, but I will never give up on him because thats
what I signed up for when I adopted him. You can follow his journey on Instagram at &lt;a href=&quot;https://instagram.com/nerothedestroyer&quot; target=&quot;_blank&quot;&gt;@nerothedestroyer&lt;/a&gt;, or at &lt;a href=&quot;https://nerotheshepherd.com/&quot; rel=&quot;noreferrer&quot;&gt;nerotheshepherd.com&lt;/a&gt;&lt;/p&gt;
</content>
    <summary>The story of adopting Nero, a high-energy seven-month-old German Shepherd already on his fourth home, and how consistent training, structure, and patience helped turn a difficult start into his forever home.</summary>
  </entry>
  
  <entry>
    <title>How to Install Arch Linux</title>
    <link href="https://j-riv.com/blog/posts/2021-06-01-how-to-install-arch-linux/"/>
    <updated>2021-06-01T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2021-06-01-how-to-install-arch-linux/</id>
    <content type="html">&lt;p&gt;Arch Linux, as the name implies, is a Linux distribution. Most of the more popular Linux distributions offer some sort of installer, graphical or CLI. Arch does not, what you do get are a set of scripts. The installation ISO contains a very basic system with the basic tools required to install a new system.&lt;/p&gt;
&lt;p&gt;Below I will try and show you how to install Arch on your system. This is a minimal UEFI base system installation. You will have to configure the rest of your system yourself. This will get you up and running.&lt;/p&gt;
&lt;h2&gt;Step 1: Download Arch Linux&lt;/h2&gt;
&lt;p&gt;You can download the iso &lt;a href=&quot;https://www.archlinux.org/download/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Step 2: Create a live USB&lt;/h2&gt;
&lt;p&gt;Use &lt;a href=&quot;https://www.balena.io/etcher/&quot;&gt;Etcher&lt;/a&gt; to create the live USB.&lt;/p&gt;
&lt;h2&gt;Step 3: Boot from the live USB&lt;/h2&gt;
&lt;p&gt;You might have to disable secure boot on your system&#39;s bios to boot from USB. Once your system boots, select the Boot Arch Linux option from the menu.&lt;/p&gt;
&lt;h2&gt;Step 4: Disk Partition&lt;/h2&gt;
&lt;p&gt;Use fdisk to partition your disk(s).&lt;/p&gt;
&lt;p&gt;To list the partitions use the command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fdisk&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The hard disk should be labelled &lt;em&gt;&lt;code&gt;/dev/sda&lt;/code&gt;&lt;/em&gt; or &lt;em&gt;&lt;code&gt;/dev/nvme0n1&lt;/code&gt;&lt;/em&gt;. Please use the appropriate disk labelling for your system. I&#39;ll be displaying all commands with &lt;code&gt;/dev/sda&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Select the disk to format and partition.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fdisk&lt;/span&gt; /dev/sda&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Delete any existing partitions with the command &lt;code&gt;d&lt;/code&gt;. Now, let&#39;s create new partitions.&lt;/p&gt;
&lt;p&gt;On UEFI systems, you must create an EFI partition at the beginning of your disk. Create an ESP partition by entering the command &lt;code&gt;n&lt;/code&gt;. It will ask you to choose a disk number, enter 1. When it asks for First Sector press enter. For last sector (partition size), enter &lt;code&gt;+512M&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Change the type of the EFI partition to EFI System (instead of Linux system) by using the command &lt;code&gt;t&lt;/code&gt;. Partition type = 1.&lt;/p&gt;
&lt;p&gt;Create the root partition. Usually most people create separate root, swap and home partitions. To keep it simple we will be creating a single root partition and put the home directory under the root directory. We will not be creating a swap partition. You could use a swapfile if you need to use swap.&lt;/p&gt;
&lt;p&gt;Create the root partition with command &lt;code&gt;n&lt;/code&gt;. Select p for primary partition. Select 2 for partition number. Press enter for first sector and press enter for last sector, this will use up all remaining space. When you are done with partitioning, enter command &lt;code&gt;w&lt;/code&gt;, to write the changes to disk and exit out of fdisk.&lt;/p&gt;
&lt;h2&gt;Step 5: Create the filesystem&lt;/h2&gt;
&lt;p&gt;You should now have 2 partitions, EFI and root. Create a FAT32 file system on the first one (EFI). (Remember to replace &lt;code&gt;/dev/sda1&lt;/code&gt; and &lt;code&gt;/dev/sda2&lt;/code&gt; with your own system&#39;s partition labels.)&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.fat &lt;span class=&quot;token parameter variable&quot;&gt;-F32&lt;/span&gt; /dev/sda1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create an EXT4 file system for the root partition.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfs.ext4 /dev/sda2&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Step 6: Connect to the Internet&lt;/h2&gt;
&lt;p&gt;If you are installing on a laptop or you don&#39;t have a wired connection, you can connect to WiFi using wifi-menu.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;wifi-menu&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test your internet connection with:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ping&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
    <summary>A step-by-step guide to installing a minimal Arch Linux system on UEFI hardware, covering disk partitioning, filesystems, networking, and the basics needed to get a new installation up and running.</summary>
  </entry>
  
  <entry>
    <title>Love for Linux</title>
    <link href="https://j-riv.com/blog/posts/2021-05-19-love-for-linux/"/>
    <updated>2021-05-19T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2021-05-19-love-for-linux/</id>
    <content type="html">&lt;p&gt;I haven&#39;t always had love for Linux, but one thing is for sure I&#39;ve never had love for Windows :P. My first love was macOS, but back then it was referred
to as Mac OS X code named Tiger. I didn&#39;t really do anything with it, except for maybe some internet browsing.&lt;/p&gt;
&lt;p&gt;My first taste of Linux came with Ubuntu 12.04 (Precise Pangolin). From then on it was an on and off relationship, macOS was just really simple to use, it
was really hard to get myself to use anything else. Years passed by and my technical ability got better, or maybe I just learned to actually read :P. Either way,
I started finding myself using Linux more and more. I forced myself to learn how to really use Linux by installing and using it on bare metal instead of VMs.&lt;/p&gt;
&lt;p&gt;These day&#39;s I run the latest Ubuntu LTS on my servers and Arch on my regular machines. There&#39;s just something about Arch and Pacman that I love. Pacman has
quickly become my favorite package manager by far. I love the simplicity of it. You can grab and build straight from git with a single command. Combine that with
the AUR and the possibilities are endless.&lt;/p&gt;
&lt;p&gt;Why do people love Linux? Well here are a few reasons. Linux is free, like in &amp;quot;no cost&amp;quot;. Who doesn&#39;t want free stuff? It&#39;s safe, secure and powers about 96%
of the internet. The Linux community is amazing and you&#39;re almost guaranteed to find the solution to any problems you may encounter. It&#39;s open source. That means
even YOU can contribute to it. You don&#39;t need to code, you can write how-to&#39;s or documentation. Lastly and maybe the most important it&#39;s not Windows. Only joking.&lt;/p&gt;
&lt;p&gt;Microsoft and Windows have gotten better. WSL2 is great and it&#39;s a step forward. But it&#39;s still windows. Why not just run Linux.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/dell-xps-13-closeup-arch-linux-badge-400w-Hhbx7bqe9H.webp 400w, https://j-riv.com/img/dell-xps-13-closeup-arch-linux-badge-800w-Hhbx7bqe9H.webp 800w, https://j-riv.com/img/dell-xps-13-closeup-arch-linux-badge-1200w-Hhbx7bqe9H.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/dell-xps-13-closeup-arch-linux-badge-400w-Hhbx7bqe9H.jpeg&quot; alt=&quot;Dell XPS 13 with Arch Linux&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;1500&quot; srcset=&quot;https://j-riv.com/img/dell-xps-13-closeup-arch-linux-badge-400w-Hhbx7bqe9H.jpeg 400w, https://j-riv.com/img/dell-xps-13-closeup-arch-linux-badge-800w-Hhbx7bqe9H.jpeg 800w, https://j-riv.com/img/dell-xps-13-closeup-arch-linux-badge-1200w-Hhbx7bqe9H.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;A close-up of my Dell XPS 13 running Arch Linux.&lt;/figcaption&gt;&lt;/figure&gt;
</content>
    <summary>How I went from an on-and-off relationship with Linux to running Ubuntu on my servers and Arch on my everyday machines, and why Linux eventually became my operating system of choice.</summary>
  </entry>
  
  <entry>
    <title>Pinebook Pro</title>
    <link href="https://j-riv.com/blog/posts/2020-10-20-pinebook-pro/"/>
    <updated>2020-10-20T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2020-10-20-pinebook-pro/</id>
    <content type="html">&lt;p&gt;Picked up a Pinebook Pro over the weekend. It’s currently running Manjaro Arm - KDE Plasma. So far so good, even got it looking like Gnome so I feel right at home.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/manjaro-arm-pinebook-400w-td8UatX0Yd.webp 400w, https://j-riv.com/img/manjaro-arm-pinebook-800w-td8UatX0Yd.webp 800w, https://j-riv.com/img/manjaro-arm-pinebook-1080w-td8UatX0Yd.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/manjaro-arm-pinebook-400w-td8UatX0Yd.jpeg&quot; alt=&quot;Pinebook Pro&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1080&quot; srcset=&quot;https://j-riv.com/img/manjaro-arm-pinebook-400w-td8UatX0Yd.jpeg 400w, https://j-riv.com/img/manjaro-arm-pinebook-800w-td8UatX0Yd.jpeg 800w, https://j-riv.com/img/manjaro-arm-pinebook-1080w-td8UatX0Yd.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;My Pinebook Pro running Manjaro Arm - KDE Plasma.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I wouldn’t replace my laptop with it that’s for sure, but it’s not aimed at doing just that. It’s a device aimed at hobbyists and tinkerers. Overall it’s pretty cool for its inexpensive hardware design. I think I might keep it.&lt;/p&gt;
</content>
    <summary>My first impressions of the Pinebook Pro running Manjaro ARM with KDE Plasma—an inexpensive ARM laptop built more for Linux enthusiasts and tinkerers than replacing your everyday laptop.</summary>
  </entry>
  
  <entry>
    <title>henrythepug.com</title>
    <link href="https://j-riv.com/blog/posts/2020-09-04-henry-the-pug-com/"/>
    <updated>2020-09-04T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2020-09-04-henry-the-pug-com/</id>
    <content type="html">&lt;p&gt;I recently rebuilt my dog&#39;s website. I originally built it in 2016 using WordPress and the Instagram API, as a photo blog to store some photos and watch how much he grew. This time around I wanted something different. I didn&#39;t want to use PHP, and since JavaScript frameworks are all the rage I decided to build it using Gatsby. I still wanted to have some sort of CMS so I kept WordPress and am now running it headless. It&#39;s blazing fast. I kept the site design pretty much the same, it&#39;s still powered by the Instagram API, just swapped the tech stack. The Gatsby Front-End is hosted on the &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby Cloud&lt;/a&gt; and the WordPress CMS is hosted on &lt;a href=&quot;https://www.hostgator.com/&quot;&gt;Hostgator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Posts get created by a cron job and script on the server. The script will retrieve the Instagram Token from the database. It will then use this token to generate a new one via the Instagram Graph API. The new token gets saved to the database. The script will then hit the Instagram Graph API again this time getting the latest 25 posts. It will then format each Instagram post creation date timestamp into a date / time string, ex: &lt;em&gt;12-19-2021_22-10-38-pm&lt;/em&gt;. This date / time string will be used as the post&#39;s title when saving to WordPress. It will also be used to see if the post already exists in WordPress. If the post does not exist a post will be created and the Image / Video Cover will be attached to the WordPress post. This post creation then triggers a web hook that then triggers a new site build on Gatsby Cloud.&lt;/p&gt;
&lt;p&gt;You can view the site at &lt;a href=&quot;https://henrythepug.com/&quot;&gt;henrythepug.com&lt;/a&gt;, the WordPress post creation script will be posted below.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/henry-the-pug-com-site-400w-PHAjRrOHZt.webp 400w, https://j-riv.com/img/henry-the-pug-com-site-800w-PHAjRrOHZt.webp 800w, https://j-riv.com/img/henry-the-pug-com-site-1200w-PHAjRrOHZt.webp 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/henry-the-pug-com-site-400w-PHAjRrOHZt.jpeg&quot; alt=&quot;henrythepug.com&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;808&quot; srcset=&quot;https://j-riv.com/img/henry-the-pug-com-site-400w-PHAjRrOHZt.jpeg 400w, https://j-riv.com/img/henry-the-pug-com-site-800w-PHAjRrOHZt.jpeg 800w, https://j-riv.com/img/henry-the-pug-com-site-1200w-PHAjRrOHZt.jpeg 1200w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;The rebuilt henrythepug.com website.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;The Config&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_NAME&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DATABASE NAME&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_USER&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DATABASE USER&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_PASSWORD&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DATABASE PASSWORD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_HOST&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_TABLE&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DATABASE TABLE&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The Script&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;WP_USE_THEMES&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DOCUMENT_ROOT&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/wp-blog-header.php&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;require_once&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ABSPATH&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/wp-admin/includes/post.php&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;require_once&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ABSPATH&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/wp-admin/includes/image.php&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;set_time_limit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// script will run for an infinite amount of time&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;ini_set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;default_socket_timeout&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// server settings&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;session_start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// starts new or resume existing session&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// MySQL settings - You can get this info from your web host&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$database&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;ig-grabber-config.php&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_NAME&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_NAME&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// WordPress Database Name&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_USER&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_USER&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// MySQL Database Username&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_PASSWORD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_PASSWORD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// MySQL Database Password&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_HOST&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_HOST&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// MySQL Hostname&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_TABLE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DB_TABLE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// MySQL Table&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
* Gets the old token data from the database.
* @returns {string} - The Access Token
*/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;getOldToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Create connection&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;mysqli&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DB_HOST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DB_USER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DB_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DB_NAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Check connection&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;connect_error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;die&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Connection failed: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;connect_error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token variable&quot;&gt;$sql&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;SELECT access_token, token_type, expires_in FROM &quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DB_TABLE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; WHERE ID = 1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$sql&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;num_rows&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch_assoc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;0 results&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;access_token&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
* Updates the token data in the database.
* @param {string} $token - The Access Token
* @param {string} $type - The Token Type
* @param {string} $expiration - The Token&#39;s Expiration
*/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;updateToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$expiration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Create connection&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;mysqli&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DB_HOST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DB_USER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DB_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DB_NAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Check connection&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;connect_error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;die&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Connection failed: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;connect_error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token variable&quot;&gt;$sql&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;UPDATE &quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DB_TABLE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; SET access_token=&#39;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$token&lt;/span&gt;&lt;/span&gt;&#39;, token_type=&#39;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$type&lt;/span&gt;&lt;/span&gt;&#39;, expires_in=&#39;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$expiration&lt;/span&gt;&lt;/span&gt;&#39; WHERE ID=1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$sql&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;New Token Saved Successfully&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;Error: &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$sql&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token variable&quot;&gt;$conn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
* Gets a new &#39;Long-Lived Token&#39; from Instagram.
*/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;getNewToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$old_token&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getOldToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&amp;amp;access_token=&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$old_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token variable&quot;&gt;$ch&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl_init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//used to transfer data with a url&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;curl_setopt_array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// sets options for a curl transfer&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CURLOPT_URL&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// the url&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CURLOPT_RETURNTRANSFER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// return the results if successful&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CURLOPT_SSL_VERIFYPEER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// we dont need to verify any certificates&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CURLOPT_SSL_VERIFYHOST&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// we wont verify host&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl_exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// executue the transfer&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;curl_close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// close the curl session&lt;/span&gt;

  &lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;json_decode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;property_exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;access_token&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;is_null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;updateToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;token_type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;expires_in&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
* Gets Instagram media.
* @param {string} $url - The User Media Edge
* @returns - {object} - Media Data Object
*/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;getInstagramMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$ch&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl_init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// used to transfer data with a url&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;curl_setopt_array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// sets options for a curl transfer&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CURLOPT_URL&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// the url&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CURLOPT_RETURNTRANSFER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// return the results if successful&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CURLOPT_SSL_VERIFYPEER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// we dont need to verify any certificates&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CURLOPT_SSL_VERIFYHOST&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// we wont verify host&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl_exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// executue the transfer&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;curl_close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// close the curl session&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
* Prints media to screen for verification while
* posts and media are created and saved.
*/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;printImages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;https://graph.instagram.com/me/media?fields=id,media_type,media_url,thumbnail_url,caption,timestamp&amp;amp;access_token=&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$instagramData&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getInstagramMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;json_decode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$instagramData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;data&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$image_url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;media_url&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;timestamp&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;caption&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;explode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;#&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;m-d-Y_H-i-s-a&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;h2&gt;FORMATTED_TIME =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;/h2&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post_exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;media_type&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;VIDEO&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$image_url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;thumbnail_url&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$video_url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;media_url&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;savePicture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$image_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;saveVideo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$video_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;elseif&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;media_type&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;IMAGE&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$image_url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;media_url&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;savePicture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$image_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br/&gt;&amp;lt;b&gt;POST EXISTS SKIPPING&amp;lt;/b&gt;&amp;lt;br/&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
* Saves images to database and creates blog post.
*/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;savePicture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$image_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Print to screen&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;IMAGE_URL =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$image_url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;CREATED_TIME =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$filenameWithExt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;.jpg&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;FILENAME =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;FULL FILENAME =&gt; &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filenameWithExt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;CAPTION =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Create post object&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$my_post_data&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_title&#39;&lt;/span&gt;    &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_content&#39;&lt;/span&gt;  &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_status&#39;&lt;/span&gt;   &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;publish&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_author&#39;&lt;/span&gt;   &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_category&#39;&lt;/span&gt;  &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Default empty.&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post_exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Insert the post into the database&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$post_id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wp_insert_post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$my_post_data&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// SELECT * FROM pics WHERE filename=$filename ---- if no matches, continue&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$upload_dir&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wp_upload_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wp_mkdir_p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$upload_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;path&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$upload_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;path&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filenameWithExt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$upload_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;basedir&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filenameWithExt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;file_put_contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;file_get_contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$image_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Save Picture to Uploads Folder&lt;/span&gt;

    &lt;span class=&quot;token variable&quot;&gt;$wp_filetype&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wp_check_filetype&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$filenameWithExt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$attachment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_mime_type&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$wp_filetype&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;type&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_title&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sanitize_file_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_content&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_status&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;inherit&#39;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Attach Featured Image to Post&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$attach_id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wp_insert_attachment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$attachment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$post_id&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$attach_data&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wp_generate_attachment_metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$attach_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;wp_update_attachment_metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$attach_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token variable&quot;&gt;$attach_data&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;update_post_meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$post_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;_thumbnail_id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$attach_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;update_post_meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$attach_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;_wp_attachment_image_alt&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;set_post_thumbnail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$post_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$attach_id&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br/&gt;&amp;lt;b&gt;POST EXISTS SKIPPING&amp;lt;/b&gt;&amp;lt;br/&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
* Saves videos to database.
*/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;saveVideo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$video_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Print to screen&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;VIDEO_URL =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$video_url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;CREATED_TIME =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$created_time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;.mp4&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;FILENAME =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;CAPTION =&gt; &#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$caption&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;//SELECT * FROM pics WHERE filename=$filename ---- if no matches, continue&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$upload_dir&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wp_upload_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wp_mkdir_p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$upload_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;path&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$upload_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;path&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$upload_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;basedir&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;br /&gt;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;file_put_contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;file_get_contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$video_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Save Video to Uploads Folder&lt;/span&gt;

    &lt;span class=&quot;token variable&quot;&gt;$wp_filetype&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wp_check_filetype&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$attachment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_mime_type&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$wp_filetype&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;type&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_title&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sanitize_file_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_content&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;post_status&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;inherit&#39;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// run&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNewToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;printImages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;ERROR, NO ACCESS TOKEN&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
    <summary>Rebuilding my dog&#39;s WordPress photo blog with Gatsby and a headless WordPress CMS, while automating content creation from Instagram with the Graph API, cron jobs, and Gatsby Cloud builds.</summary>
  </entry>
  
  <entry>
    <title>Hackintosh</title>
    <link href="https://j-riv.com/blog/posts/2020-04-17-hackintosh/"/>
    <updated>2020-04-17T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2020-04-17-hackintosh/</id>
    <content type="html">&lt;p&gt;I built my first Hackintosh in 2016, basically out of boredom and because my Macbook Pro 2013 was getting a bit old
and I wanted a destop running macOS. I didn&#39;t even know about the compatibility of parts. I just cleared a weekend and
went straight at it. It took me 2 days of trial and error but I finally got it to boot up.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/hackintosh-neofetch-400w-ZztlllzODp.webp 400w, https://j-riv.com/img/hackintosh-neofetch-800w-ZztlllzODp.webp 800w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/hackintosh-neofetch-400w-ZztlllzODp.jpeg&quot; alt=&quot;Hackintosh Neofetch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;800&quot; srcset=&quot;https://j-riv.com/img/hackintosh-neofetch-400w-ZztlllzODp.jpeg 400w, https://j-riv.com/img/hackintosh-neofetch-800w-ZztlllzODp.jpeg 800w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;Hackintosh Neofetch&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;My original parts list:&lt;/p&gt;
  &lt;ul&gt;
  &lt;li&gt;ASRock Fatal1ty Z97 Killer Intel Motherboard&lt;/li&gt;
  &lt;li&gt;Intel Core i7-4790K - Devil&#39;s Canyon Quad Core CPU&lt;/li&gt;
  &lt;li&gt;MSI Radeon R7 370 4GB Graphics Card&lt;/li&gt;
  &lt;li&gt;G.Skill Ripjaws X Series 16gb (2 x 8gb)&lt;/li&gt;
  &lt;li&gt;Thermaltake SP-750P Power Supply&lt;/li&gt;
  &lt;li&gt;NZXT Case&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over the years I swapped the graphics card from the R7 to an EVGA GeForce GTX 960 SSC FTW and finally ended up on a
Saphire Rx 580 due to Nvidia graphics drivers issues on macOS.&lt;/p&gt;
&lt;p&gt;The bootloader I originally used was Clover, but when I get enough time I will try to change it and use OpenCore
instead. Since I have heard that it is far more reliable. Surprisingly I&#39;ve had less issues updating the Hackintosh
partition, compared to updating my Windows partition. I&#39;m currently on macOS Catalina.&lt;/p&gt;
</content>
    <summary>A look back at the Hackintosh I built in 2016 with almost no planning, how the hardware evolved over the years, and my experience running macOS on a custom-built PC.</summary>
  </entry>
  
  <entry>
    <title>Multi-Boot</title>
    <link href="https://j-riv.com/blog/posts/2019-12-28-multi-boot/"/>
    <updated>2019-12-28T00:00:00Z</updated>
    <id>https://j-riv.com/blog/posts/2019-12-28-multi-boot/</id>
    <content type="html">&lt;p&gt;The most essential component of a computer is its operating system. Why should you have to choose just one? To multi-boot or not multi-boot? That is the question.&lt;/p&gt;
&lt;figure class=&quot;post-figure&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://j-riv.com/img/multi-boot-400w-JR2e6__lb8.webp 400w, https://j-riv.com/img/multi-boot-800w-JR2e6__lb8.webp 800w, https://j-riv.com/img/multi-boot-1080w-JR2e6__lb8.webp 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;img src=&quot;https://j-riv.com/img/multi-boot-400w-JR2e6__lb8.jpeg&quot; alt=&quot;Multi-Boot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1080&quot; height=&quot;1350&quot; srcset=&quot;https://j-riv.com/img/multi-boot-400w-JR2e6__lb8.jpeg 400w, https://j-riv.com/img/multi-boot-800w-JR2e6__lb8.jpeg 800w, https://j-riv.com/img/multi-boot-1080w-JR2e6__lb8.jpeg 1080w&quot; sizes=&quot;100vw&quot; /&gt;&lt;/picture&gt;&lt;figcaption&gt;An example of a multi-boot setup.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Multi-booting&lt;/h2&gt;
&lt;p&gt;Dual-booting or multi-booting is the act of installing multiple operating systems on a single computer, and being able to choose which one to boot. The most popular combination is Windows / Linux although that may be starting to change with &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/wsl/install-win10&quot;&gt;WSL2&lt;/a&gt;. More on that on a future post.&lt;/p&gt;
&lt;h2&gt;Why would you need to dual boot?&lt;/h2&gt;
&lt;p&gt;Well sometimes the apps or programs you need to use, perform better or are only available on a certain operating system. Take Adobe for example. If you need to use Photoshop or Illustrator you&#39;re pretty much stuck with Windows or macOS. I know there are open source alternatives (ex: Gimp, Inkscape) but that&#39;s besides the point.&lt;/p&gt;
&lt;p&gt;Sometimes there&#39;s a better operating system for the work you&#39;re trying to do. From my experience Linux and or macOS provide a better and easier experience when it comes to development. Linux / macOS support most programming languages out of the box and their terminal apps are superior to the Windows command line. The popular Bash shell is available in macOS as well as most Linux distributions. The latest macOS version has switched to ZSH by default.&lt;/p&gt;
&lt;p&gt;Why couldn&#39;t you just use a VM? I mean I guess you could but running an OS natively gives you full access to the host machine. If you plan on doing CPU or GPU intensive workloads it&#39;s better to go with a multi-boot setup instead.&lt;/p&gt;
&lt;h2&gt;My Personal Experience&lt;/h2&gt;
&lt;p&gt;My first dual-boot setup was macOS / Windows via bootcamp on an old Macbook Pro. Eventually I added Ubuntu but that just added complexity and problems. Somehow I got locked out of Windows and when I managed to fix Windows I lost access to grub. I got it working with rEFInd as my boot manager. I finally had the Holy Trinity of macOS, Windows &amp;amp; Linux.&lt;/p&gt;
&lt;p&gt;I&#39;ve spent a lot of time playing around with multi-booting various operating systems. My current setup is from 2014. I&#39;m still using rEFInd as my boot manager but I&#39;m up to a penta-boot. Why I can&#39;t really tell you since I mostly just use one or two operating systems. Currently I&#39;m running Windows 10, Arch, Ubuntu, Fedora and macOS. This PC started its life like any PC with Windows. Then I turned it into a Hackintosh via the Clover EFI boot loader. Surprisingly I&#39;ve had less trouble updating the Hackintosh partition compared to the Windows partition.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;If you&#39;re going to try and multi-boot your system I suggest you use different hard drives and not just partitions. It keeps things much simpler. You have a much less chance of overriding other partitions this way.&lt;/p&gt;
&lt;p&gt;Eventually I will have to upgrade my computer and with AMD chips doing so well it might be an all AMD build. Will I multi-boot again? Maybe a dual-boot. I do want to give installing macOS via OpenCore a try.&lt;/p&gt;
</content>
    <summary>Why settle for one operating system? A look at multi-booting, why you might want multiple operating systems on the same PC, and my experience running Windows, Linux, and macOS together.</summary>
  </entry>
  
</feed>
