<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tony Metzidis</title>
    <description>The latest articles on DEV Community by Tony Metzidis (@tonymet).</description>
    <link>https://dev.to/tonymet</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F135364%2F24669483-d466-4474-a9dc-a7b238e7b59c.jpeg</url>
      <title>DEV Community: Tony Metzidis</title>
      <link>https://dev.to/tonymet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tonymet"/>
    <language>en</language>
    <item>
      <title>How to Finally (and Iteratively) Kill Every Last 'npm audit'</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Thu, 02 Apr 2026 19:24:53 +0000</pubDate>
      <link>https://dev.to/tonymet/how-to-finally-and-iteratively-kill-every-last-npm-audit-51ep</link>
      <guid>https://dev.to/tonymet/how-to-finally-and-iteratively-kill-every-last-npm-audit-51ep</guid>
      <description>&lt;p&gt;Let’s be honest: &lt;code&gt;npm audit&lt;/code&gt; is a necessary evil. If you manage a monorepo, a large scale-backend microservice architecture, or even just have fifty toy projects in your &lt;code&gt;/dev&lt;/code&gt; folder, you know the dread. You run an audit, get 400 vulnerabilities, and standard &lt;code&gt;npm audit fix&lt;/code&gt; just breaks things.&lt;/p&gt;

&lt;p&gt;The real problem isn't fixing the vulnerability; the problem is the &lt;em&gt;management&lt;/em&gt; of the vulnerabilities.&lt;/p&gt;

&lt;p&gt;Manually &lt;code&gt;cd&lt;/code&gt;-ing into 30 different directories, running the audit, deciphering the output, deciding which &lt;code&gt;package.json&lt;/code&gt; to edit, and &lt;em&gt;then&lt;/em&gt; doing the work? That's an efficient way to burn out an afternoon.&lt;/p&gt;

&lt;p&gt;Here is the tool you didn’t know you needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: Multi-Directory Triage
&lt;/h3&gt;

&lt;p&gt;You are working across multiple contexts (multiple directories). You have dozens of tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Find the &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Navigate to that folder.&lt;/li&gt;
&lt;li&gt; Run the audit.&lt;/li&gt;
&lt;li&gt; Decide if it’s a manual fix (Mocha 11x, looking at you) or an &lt;code&gt;audit fix --force&lt;/code&gt; candidate.&lt;/li&gt;
&lt;li&gt; Mark it done and move on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The standard Unix toolbox doesn’t have a built-in interactive "loop through directories and run commands, pausing for input" command.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution: &lt;code&gt;fzf&lt;/code&gt; as an Interactive Runner
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;/home/tonymet/dev/
&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;api-gateway-service                                                  │ Path: ./api-gateway-service
&lt;span class="go"&gt;  auth-provider                                                       │ 
  legacy-reporting-tool                                               │ 🔒 npm audit report
  frontend-dashboard                                                  │ 
  shared-auth-library                                                 │ 📉 Low             1
                                                                      │ 📈 High            3
                                                                      │ 💥 Critical        1
                                                                      │ 
                                                                      │ Found 5 vulnerabilities in 890 scanned packages.
                                                                      │ 3 vulnerabilities require manual review.
                                                                      │ 
                                                                      │ Run `npm audit fix` to fix 2 of them.
                                                                      │ 
                                                                      │ =========================================================
                                                                      │ Critical: Remote Code Execution
                                                                      │ Package: serialize-javascript
                                                                      │ Dependency of: mocha [dev]
&lt;/span&gt;&lt;span class="gp"&gt;                                                                      │ Path: mocha &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;serialize-javascript
&lt;span class="go"&gt;                                                                      │ More info: https://github.com/advisories/GHSA-hxcc-f52p
                                                                      │ 
                                                                      │ =========================================================
                                                                      │ High: Prototype Pollution
                                                                      │ ... (rest of audit output scrolled)
[5/5] -----------------------------------------------------------------│
&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The solution is combining the powerhouse finder &lt;strong&gt;&lt;code&gt;fzf&lt;/code&gt;&lt;/strong&gt; with some standard &lt;code&gt;find&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;We are going to use &lt;code&gt;fzf&lt;/code&gt; &lt;em&gt;not&lt;/em&gt; just to select a file, but as an interactive dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  The One Command to Rule Them All
&lt;/h3&gt;

&lt;p&gt;Here is the command (Unix/Linux/macOS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"package.json"&lt;/span&gt; &lt;span class="nt"&gt;-not&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;"*/node_modules/*"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
| fzf &lt;span class="nt"&gt;--preview&lt;/span&gt; &lt;span class="s1"&gt;'echo $(dirname {}) &amp;amp;&amp;amp; cd $(dirname {}) &amp;amp;&amp;amp; npm audit'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--preview-window&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;right:80%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  What is happening here?
&lt;/h4&gt;

&lt;p&gt;This looks complicated, but it's remarkably elegant:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;find . -name "package.json" -not -path "*/node_modules/*"&lt;/code&gt;&lt;/strong&gt;: This is our discovery engine. It searches the entire directory tree (&lt;code&gt;.&lt;/code&gt;) for &lt;code&gt;package.json&lt;/code&gt; files, but critically skips anything &lt;em&gt;inside&lt;/em&gt; a &lt;code&gt;node_modules&lt;/code&gt; folder (we don’t want to audit dependencies' dependencies, only the root projects). This feeds a clean list of file paths to the next command.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;| fzf&lt;/code&gt;&lt;/strong&gt;: We pipe that list into &lt;code&gt;fzf&lt;/code&gt;, the interactive finder. This creates the interface.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;--preview '...'&lt;/code&gt;&lt;/strong&gt;: This is the magic. When you highlight a path in &lt;code&gt;fzf&lt;/code&gt;, this entire script runs in the side-pane:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;echo $(dirname {})&lt;/code&gt;: Shows you the clean path to the &lt;em&gt;directory&lt;/em&gt; containing the &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cd $(dirname {})&lt;/code&gt;: Temporarily navigates the preview process into that directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm audit&lt;/code&gt;: Executes the audit &lt;em&gt;specifically inside that folder&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;--preview-window=right:80%&lt;/code&gt;&lt;/strong&gt;: We give the preview window 80% of the screen. Why? Because &lt;code&gt;npm audit&lt;/code&gt; output is verbose, and you need to be able to read the specifics of the dependency tree to make triage decisions.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  How to Use the Interface
&lt;/h3&gt;

&lt;p&gt;When you run this command, your terminal transforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Left Side:&lt;/strong&gt; A list of every project in your &lt;code&gt;/dev&lt;/code&gt; folder that has a &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right Side:&lt;/strong&gt; The &lt;em&gt;live&lt;/em&gt; output of &lt;code&gt;npm audit&lt;/code&gt; for whichever project you highlight.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you can triage! Use the up and down arrow keys to quickly review the security status of every project without leaving the dashboard.&lt;/p&gt;

&lt;h4&gt;
  
  
  Actually "Doing Work"
&lt;/h4&gt;

&lt;p&gt;The standard configuration above is a &lt;strong&gt;read-only view&lt;/strong&gt;. It lets you quickly see where the major problems are (e.g., "Oh, all these old 2022 projects need Mocha 12").&lt;/p&gt;

&lt;p&gt;If you want to actually &lt;em&gt;execute&lt;/em&gt; fixes from within the interface, we need to bind a key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"package.json"&lt;/span&gt; &lt;span class="nt"&gt;-not&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;"*/node_modules/*"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
| fzf &lt;span class="nt"&gt;--preview&lt;/span&gt; &lt;span class="s1"&gt;'echo $(dirname {}) &amp;amp;&amp;amp; cd $(dirname {}) &amp;amp;&amp;amp; cat package.json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--preview-window&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;right:80% &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--bind&lt;/span&gt; &lt;span class="s1"&gt;'enter:execute(cd $(dirname {}) &amp;amp;&amp;amp; npm audit fix &amp;amp;&amp;amp; echo -n DONE | read)+down'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this version does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Default Preview:&lt;/strong&gt; Shows &lt;code&gt;package.json&lt;/code&gt; (running &lt;code&gt;audit&lt;/code&gt; constantly in preview can be slow).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enter (Binding):&lt;/strong&gt; When you hit &lt;code&gt;Enter&lt;/code&gt;:

&lt;ol&gt;
&lt;li&gt; It runs &lt;code&gt;npm audit fix&lt;/code&gt; in that folder.&lt;/li&gt;
&lt;li&gt; It uses &lt;code&gt;echo -n DONE | read&lt;/code&gt; to pause the interface (pressing any key resumes).&lt;/li&gt;
&lt;li&gt; &lt;code&gt;+down&lt;/code&gt;: After you resume, it automatically moves the selection to the next directory on the list.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It mimics the exact "triage and advance" workflow of an interactive rebase.&lt;/p&gt;

&lt;p&gt;When the interface is painless, you are more likely to run it. When the effort of auditing 100 directories is reduced to "holding down the down arrow," security gets addressed.&lt;/p&gt;

</description>
      <category>security</category>
      <category>automation</category>
      <category>npm</category>
      <category>node</category>
    </item>
    <item>
      <title>Stop Paying the "Security Tax": Reclaiming 30% Performance in WSL 2 on Windows 11</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Wed, 25 Mar 2026 05:51:27 +0000</pubDate>
      <link>https://dev.to/tonymet/stop-paying-the-security-tax-reclaiming-30-performance-in-wsl-2-on-windows-11-kdo</link>
      <guid>https://dev.to/tonymet/stop-paying-the-security-tax-reclaiming-30-performance-in-wsl-2-on-windows-11-kdo</guid>
      <description>&lt;p&gt;If you develop in WSL 2, you are likely sacrificing nearly a third of your CPU performance to kernel-level security mitigations. In a recent deep dive, I benchmarked a Go-based backend project and found that disabling these protections (Spectre/Meltdown patches) reduced wall-clock compilation times by &lt;strong&gt;31.7%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The "System Time" nearly doubled with mitigations enabled, proving that the constant context-switching required for security "handshakes" acts as a massive throttle on syscall-heavy workloads like compiling and linking.&lt;/p&gt;

&lt;h4&gt;
  
  
  Go Build Benchmark (&lt;code&gt;time go build ./...&lt;/code&gt;)
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Mitigations &lt;strong&gt;OFF&lt;/strong&gt;
&lt;/th&gt;
&lt;th&gt;Mitigations &lt;strong&gt;ON&lt;/strong&gt; (Default)&lt;/th&gt;
&lt;th&gt;Delta (Penalty)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;13.51s&lt;/td&gt;
&lt;td&gt;24.89s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+84.2%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total (Wall) Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;18.31s&lt;/td&gt;
&lt;td&gt;26.98s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+47.3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;CPU Efficiency&lt;/strong&gt; (&lt;em&gt;higher is better&lt;/em&gt;)&lt;/td&gt;
&lt;td&gt;522%&lt;/td&gt;
&lt;td&gt;395%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-127%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The good news is that the fix is a one line change added to &lt;code&gt;.wslconfig&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Read the full technical breakdown, including &lt;code&gt;.wslconfig&lt;/code&gt; examples and &lt;code&gt;perf bench&lt;/code&gt; audit commands, at the link below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full Post:&lt;/strong&gt; &lt;a href="https://tonym.us/wsl2-security-tax-reclaiming-performance.html" rel="noopener noreferrer"&gt;The "Security Tax": Reclaiming 30% Performance in WSL 2 // Tony Metzidis&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>go</category>
      <category>performance</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>Archive Legacy Github Repos with Subtree</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Tue, 05 Aug 2025 00:47:08 +0000</pubDate>
      <link>https://dev.to/tonymet/archive-legacy-github-repos-with-subtree-1dj3</link>
      <guid>https://dev.to/tonymet/archive-legacy-github-repos-with-subtree-1dj3</guid>
      <description>&lt;p&gt;If you're like me your github account is littered with hundreds of legacy experimental repos that you don't want to toss. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;git subtree&lt;/code&gt; is the magic needed to consolidate them into an archive, preserving all of the commit history . Once consolidated, all of those legacy repos can be archived to your cloud storage and deleted from github.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clone the Archive Repo
&lt;/h3&gt;

&lt;p&gt;First step is to choose (or create) your archive repo that will contain all of your experiments&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USERNAME=tony
REPO=archive
git clone git@github.com:$USERNAME/$REPO.git
cd $REPO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clone one or more Experiment Repos (you would like to delete)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USERNAME=tony
REPO=experiment-web
git clone git@github.com:$USERNAME/$REPO.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add the local experiment-web as a "remote"
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;note&lt;/em&gt;: Git remotes can be copies from a local directory. This is the magical source of subtree's power to fan-in or fan-out repos&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd archive
name=experiment-web ; git remote add subtree/$name ../$name  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do this any number of times for all of your experiment Repos&lt;/p&gt;

&lt;h3&gt;
  
  
  Subtree The Repo and Test the Results
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# stay within Archive
name=experiment-web
git subtree add -P $name subtree/$name master # or any branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test that all the contents match exactly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd $name
diff -r . ../../$name
# Only in ../../experiment-web: .git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test that the subtree'd log matches the log of the original repo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log --graph -4
*   a19d970 - (HEAD -&amp;gt; master, tonymet/master) Add 'oh-my-zsh/' from commit '9f3f282699dccc11221debbdbec4be654c63ac83' (11 minutes ago) &amp;lt;tony&amp;gt;
|\
| * 9f3f282 - (subtree/oh-my-zsh-origin/anthony) macbook (14 minutes ago) 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Archive and Delete The Repo
&lt;/h2&gt;

&lt;p&gt;Now you can archive the repo to your cloud storage ( Google Cloud , etc).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Save to TGZ file and copy to your Google Drive
name=experiment-web &amp;amp;&amp;amp; tar -zcf archive/$name-`date +%Y-%m-%d`.tgz $name &amp;amp;&amp;amp;  rm -rf $name  
# Visit repo on the web to delete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>github</category>
      <category>git</category>
    </item>
    <item>
      <title>How to Put Everything in Git</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Fri, 03 Jan 2025 19:21:56 +0000</pubDate>
      <link>https://dev.to/tonymet/how-to-put-everything-in-git-2b3d</link>
      <guid>https://dev.to/tonymet/how-to-put-everything-in-git-2b3d</guid>
      <description>&lt;p&gt;It's good to get in the habit of putting everything into a git repo, and that means having a canonical remote for experiments. Creating remotes for each experiment becomes a clutter of keys and repos. So it's best to merge all of those experiments into a larger &lt;em&gt;experiments&lt;/em&gt; repo and just push that repo to github.&lt;/p&gt;

&lt;p&gt;Instead of thousands of repos, consolidate your configs and experiments into a single repo on your development machine like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgljeok86kiz0kl0agt3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgljeok86kiz0kl0agt3h.png" alt="Diagram of Putting multiple experiments and configs into a single repo" width="770" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case I needed a simple &lt;code&gt;main.c&lt;/code&gt; to test ARM support for NEON (like SSE on intel) on Raspberry PI. The directory was primitive, but I still wanted to retain the experiment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - arm_neon/ 
      - main.c
      - .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To preserve this repo, I still use git init and manage commits within &lt;em&gt;arm_neon&lt;/em&gt; locally, but "subtree" it into an experiments repo using &lt;code&gt;git subtree add&lt;/code&gt; . Here are the steps. &lt;/p&gt;

&lt;h3&gt;
  
  
  1. Initialize and Commit the Experiment locally on Raspberry Pi
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd arm_neon
git init
git add -u
git commit -m "arm register test working"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Add the &lt;em&gt;arm_neon&lt;/em&gt; Experiment Remote
&lt;/h3&gt;

&lt;p&gt;On the development machine , add the &lt;em&gt;arm_neon&lt;/em&gt; experiment as a remote within the &lt;em&gt;experiments&lt;/em&gt; repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd experiments
git remote add arm_neon ssh://pi@pi4.local/home/pi/test/arm_neon
git fetch arm_neon
# git warns you the two repos have nothing in common-- as expected
warning: no common commits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the subtree using &lt;em&gt;arm_neon&lt;/em&gt; as the prefix (the directory)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PREFIX=arm_neon
REMOTE=arm_neon
git subtree add -P $PREFIX $REMOTE master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test that it worked&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log -1
93dc44e - (tag: arm_neon_latest, tonymet/master) Add 'arm_neon/' from commit '083a748c92a4b04caa667c3573de4fb0c46c86fc' (33 minutes ago) &amp;lt;Anthony Metzidis&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Push the Experiments to Github
&lt;/h3&gt;

&lt;p&gt;Now &lt;em&gt;experiments&lt;/em&gt; contains &lt;em&gt;arm_neon&lt;/em&gt; and hundreds of others.  Push it up to github.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push github HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Continue Experimentation &amp;amp; Tracking Changes
&lt;/h3&gt;

&lt;p&gt;Now that the two repos are linked, you can continue making changes to arm_neon and use &lt;em&gt;git subtree merge&lt;/em&gt; to incorporate the latest commits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# on raspberry pi, a new commit has been made
 git log
3d7315a - (HEAD -&amp;gt; master) improve docs (11 seconds ago) &amp;lt;Anthony Metzidis&amp;gt;
083a748 - arm neon call (26 minutes ago) &amp;lt;Anthony Metzidis&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now merge those changes into the experiments repo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# get latest changes on development machine
git fetch arm_neon
# merge those into the subtree .
git subtree merge arm_neon/master -P arm_neon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the &lt;em&gt;experiments&lt;/em&gt; repo contains all the latest changes from arm_neon, and can be pushed to github.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log -1
93dc44e - (HEAD -&amp;gt; master) Add 'arm_neon/' from commit '083a748c92a4b04caa667c3573de4fb0c46c86fc' (5 seconds ago) &amp;lt;Anthony Metzidis&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have one repo that contains hundreds of experiments , rather than creating hundreds of repos in your github account.&lt;/p&gt;

</description>
      <category>git</category>
      <category>development</category>
      <category>devops</category>
    </item>
    <item>
      <title>Streaming regex scanner — regexpscanner</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Thu, 05 Dec 2024 00:10:53 +0000</pubDate>
      <link>https://dev.to/tonymet/streaming-regex-scanner-regexpscanner-2ia9</link>
      <guid>https://dev.to/tonymet/streaming-regex-scanner-regexpscanner-2ia9</guid>
      <description>&lt;p&gt;Go's regexp module falls short with stream processing-- nearly all methods require a &lt;code&gt;string&lt;/code&gt; or &lt;code&gt;[]byte&lt;/code&gt;.  The &lt;em&gt;regexpscanner&lt;/em&gt; module makes it easy to extract tokens that match regular expression patterns.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pkg.go.dev/github.com/tonymet/regexpscanner" rel="noopener noreferrer"&gt;https://pkg.go.dev/github.com/tonymet/regexpscanner&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Module
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/tonymet/regexpscanner@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;use &lt;code&gt;ProcessTokens&lt;/code&gt; when a simple callback-based stream tokenizer is needed . &lt;br&gt;
&lt;code&gt;ProcessTokens&lt;/code&gt; calls handler(string) for each matching token from the Scanner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"regexp"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;

    &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="s"&gt;"github.com/tonymet/regexpscanner"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;p&amp;gt;Welcome to My Website&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;regexp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MustCompile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`&amp;lt;/?[a-z]+&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Output
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;p&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it a try and see the &lt;a href="https://pkg.go.dev/github.com/tonymet/regexpscanner" rel="noopener noreferrer"&gt;Go Module Page&lt;/a&gt; for more examples&lt;/p&gt;

</description>
      <category>go</category>
      <category>regex</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Run godoc Automatically</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Tue, 26 Nov 2024 19:32:55 +0000</pubDate>
      <link>https://dev.to/tonymet/run-godoc-automatically-4b31</link>
      <guid>https://dev.to/tonymet/run-godoc-automatically-4b31</guid>
      <description>&lt;p&gt;VSCode has a fantastic task runner, with lots of configuration options for when and how the task should be run. &lt;/p&gt;

&lt;p&gt;Let's set up &lt;code&gt;godoc&lt;/code&gt; to run whenever you open the project.  It will display a push notification linking you to godoc server within your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  STEPS to Add
&lt;/h2&gt;

&lt;p&gt;(1) Install godoc via your terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; go install golang.org/x/tools/cmd/godoc@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(2) Add the task with CTRL-SHIFT-P, "Configure Tasks" . This edits &lt;code&gt;./vscode/tasks.json&lt;/code&gt;&lt;br&gt;
(3) Add the following task to the tasks array (copy the individual task object below)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "godoc",
            "type": "shell",
            "command": "godoc",
            "options": {
                "cwd": "${workspaceFolder}",
                "shell": {
                    "args": ["-c"],
                    "executable": "/bin/sh"
                }
            },
            "runOptions": {"runOn": "folderOpen"},
            "presentation": {
                "echo": true,
                "reveal": "never",
                "focus": false,
                "panel": "shared",
                "showReuseMessage": true,
                "clear": false
            },
            "problemMatcher": []
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(4) Run the task.  You can run the task with CTRL-SHIFT-P → "Run Task" → "godoc" or by reopening your window. A notice will show linking you to godoc.  Or you can find the link using the "Ports" tab and clicking the godoc URL.&lt;/p&gt;

</description>
      <category>go</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Fighting GCP &amp; Firebase Cloud Client CLI and SDK Bloat</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Fri, 18 Oct 2024 07:00:00 +0000</pubDate>
      <link>https://dev.to/tonymet/fighting-gcp-firebase-cloud-client-cli-and-sdk-bloat-mlm</link>
      <guid>https://dev.to/tonymet/fighting-gcp-firebase-cloud-client-cli-and-sdk-bloat-mlm</guid>
      <description>&lt;p&gt;Client CLIs &amp;amp; SDKs for GCP, Firebase and other clouds are terribly bloated. GCP includes a python distro, firebase includes node+npm. This goes unnoticed on overpowered devboxes, but impacts your cloud bill with storage, vcpu, wall-time and transfer fees. If you are trying to downsize your VMs, you will find that the client SDK/ CLI pre-requisites will often hang your machine terminal by exausting vcpu and iops budgets. Cloud container services are often storage-limited to ram-disks--so CLI installs consume what little you have.&lt;/p&gt;

&lt;p&gt;To combat the bloat, I've started a few projects to offer lightweight solutions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/tonymet/gcloud-lite" rel="noopener noreferrer"&gt;gcloud-lite&lt;/a&gt; -- a stripped distro of gcloud cli that is 90% smaller&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tonymet/gcloud-go" rel="noopener noreferrer"&gt;gcloud-go&lt;/a&gt; -- a 90% smaller and faster go binary for deploying to firebase and gcloud&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benchmarks
&lt;/h2&gt;

&lt;p&gt;For example, e2-medium VMs using gcloud-lite are 86% faster to install the cli. This means your work can start nearly 90s faster than using the default CLI. You can downsize to x-small VMs which can save up to 75%&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Image&lt;/th&gt;
&lt;th&gt;Install Time&lt;/th&gt;
&lt;th&gt;Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;google-cloud-cli&lt;/td&gt;
&lt;td&gt;1m29s&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gcloud-lite&lt;/td&gt;
&lt;td&gt;12.6s&lt;/td&gt;
&lt;td&gt;86%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For firebase deployments, the image is 92% smaller, and startup is faster, meaning you can downsize VMs and container jobs will execute &amp;gt; 50% faster&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;docker image&lt;/th&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;savings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;firebase-tools&lt;/td&gt;
&lt;td&gt;245mb&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gcloud-go&lt;/td&gt;
&lt;td&gt;19mb&lt;/td&gt;
&lt;td&gt;92%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Reduced Storage
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://console.cloud.google.com/artifacts/docker/tonym-us/us-west1/gcloud-lite/gcloud-lite?hl=en&amp;amp;project=tonym-us" rel="noopener noreferrer"&gt;Runnable docker image&lt;/a&gt; — 93% smaller&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tonymet/gcloud-lite/releases" rel="noopener noreferrer"&gt;tgz tarball&lt;/a&gt; — 75% smaller&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How You Can Help
&lt;/h2&gt;

&lt;p&gt;Please start testing the projects, and file a feature request. Patches are welcome , and please share how the lightweight CLI tools are helping your project&lt;/p&gt;

</description>
      <category>google</category>
      <category>cloud</category>
      <category>go</category>
    </item>
    <item>
      <title>WSL2 Backup to OneDrive Cloud</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Wed, 31 Jan 2024 08:00:00 +0000</pubDate>
      <link>https://dev.to/tonymet/wsl2-backup-to-onedrive-cloud-4m4d</link>
      <guid>https://dev.to/tonymet/wsl2-backup-to-onedrive-cloud-4m4d</guid>
      <description>&lt;p&gt;WSL2 provides great disk performance, but it requires storing the files separately in a virtual disk that is not accessible by OneDrive. WSL2 can be backed up with &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/basic-commands#import-and-export-a-distribution" rel="noopener noreferrer"&gt;wsl --export Debian&lt;/a&gt; to a VHD or TGZ, but that is a complete disk backup of 20gb or more -- not scalable for hourly backups.&lt;/p&gt;

&lt;p&gt;With this approach, we use Windows Task Scheduler to trigger &lt;code&gt;robocopy&lt;/code&gt; to incrementally sync directories from WSL2 to Onedrive's native FS, so incremental copies are fast ( 1 s per 10k files), and OneDrive sync time remains negligible.&lt;/p&gt;

&lt;p&gt;It's also useful for snapshotting subdirectories to TGZ for offline or cloud archiving.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robocopy
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;robocopy&lt;/code&gt; is a built-in tool that recognizes file size &amp;amp; modification times to copy changes incrementally.&lt;code&gt;/xd&lt;/code&gt; param is used to exclude &lt;code&gt;node_modules&lt;/code&gt; (wasteful JS library artifacts)&lt;/p&gt;

&lt;p&gt;This script syncs a project directory &lt;code&gt;/home/USERNAME/sotion&lt;/code&gt; within WSL2 to&lt;code&gt;$HOME\OneDrive\Documents\sotion&lt;/code&gt; on Windows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# backup wsl contents on a schedule
# set &amp;amp; truncate $logfile
$logfile="$HOME\backup-wsl.log.txt"
if ((Get-Item $logfile).length -gt 128000){
    Remove-Item $logfile
}
$src="\\wsl.localhost\Debian\home\${env:Username}\sotion"
$dest=$(Join-Path ${env:OneDrive} "Documents\Sotion")
Write-EventLog -LogName Application -Source "Backup-WSL" -EventID 3001 -Message "Starting Backup"
$t0=(Get-Date)
robocopy $src $dest /W:1 /R:0 /E /xd node_modules /NFL /NDL /LOG+:$logfile
$exitcoderobo=$LASTEXITCODE
$t1=(Get-Date)
$delta =($t1-$t0)
$message="Finished Backup. Duration = $delta"
if($exitcoderobo -ne 0){
    $message="ERROR: Finished Backup. Backup failed. Duration = $delta . Check $logfile for error"
}
Write-EventLog -LogName Application -Source "Backup-WSL" -EventID 3001 -Message $message
exit $exitcoderobo

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trigger the script to test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pwsh --noprofile backup-wsl\backup-wsl.ps1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the Scheduled Task
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$time = New-ScheduledTaskTrigger -Daily -At 2pm 
$user = (whoami)
$action = New-ScheduledTaskAction -Execute "${env:ProgramFiles}\PowerShell\7\pwsh.exe" -Argument "-noninteractive -nologo -noprofile $HOME\scripts\backup-wsl\backup-wsl.ps1"
Register-ScheduledTask -TaskName "Backup-WSL" -Trigger $Time -User $User -Action $action

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trigger the script to create the task schedule&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; pwsh -noprofile .\backup-wsl\schedule-backup.ps1 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the Event Log
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New-EventLog -LogName Application -Source "Backup-WSL"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Monitoring
&lt;/h2&gt;

&lt;p&gt;Runs are logged to Windows Event Viewer. You can view them using the Event Viewer app or &lt;code&gt;Get-EventLog&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; get-eventlog -Source backup-wsl -LogName Application -Newest 1 |Select-Object message

Message
-------
ERROR: Finished Backup. Backup failed. Duration = 00:00:01.8787580 . Check C:\Users\xxx\backup-wsl.log.txt for err…

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Full Example
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/tonymet/816290ca37eab78353c9b760d127ee31" rel="noopener noreferrer"&gt;See this Gist&lt;/a&gt;&lt;/p&gt;

</description>
      <category>windows</category>
      <category>linux</category>
      <category>vm</category>
      <category>development</category>
    </item>
    <item>
      <title>Setting for "Bob made a new post..." notification?</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Tue, 28 Nov 2023 00:24:57 +0000</pubDate>
      <link>https://dev.to/tonymet/setting-for-bob-made-a-new-post-notification-3a7j</link>
      <guid>https://dev.to/tonymet/setting-for-bob-made-a-new-post-notification-3a7j</guid>
      <description>&lt;p&gt;Is there a setting to disable this notification type? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0lmgtpz55uvy3e6iwu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0lmgtpz55uvy3e6iwu6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the settings that I have available ... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmonakssa0g3orua4a1ev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmonakssa0g3orua4a1ev.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>help</category>
    </item>
    <item>
      <title>IPV6 Migration Guide for Developers using AWS EC2 -- A Primer</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Mon, 20 Nov 2023 21:03:56 +0000</pubDate>
      <link>https://dev.to/tonymet/ipv6-migration-guide-for-developers-using-aws-ec2-a-primer-50df</link>
      <guid>https://dev.to/tonymet/ipv6-migration-guide-for-developers-using-aws-ec2-a-primer-50df</guid>
      <description>&lt;p&gt;Originally on &lt;a href="https://tonym.us/ipv6-migration-guide-for-developers-using-aws-ec2-a-primer.html"&gt;tonym.us&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;With the news that AWS will be now charging about $4 / instance-month for public IPv4 addresses, many&lt;br&gt;
developers who procrastinated ipv6 migration are finally updating both ends of their development setup.&lt;/p&gt;

&lt;p&gt;It's a great time to migrate, as all the intermediate infrastructure now supports IPV6 readily.  Moreover, you'll benefit from permanent , global&lt;br&gt;
addresses for your development instances.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A single, global, stable address for EC2 instances that never changes. No need
for dynamic DNS and other hacks&lt;/li&gt;
&lt;li&gt;No need to pay for Elastic IP addresses on
dev instances&lt;/li&gt;
&lt;li&gt;Global addressing for mutual duplex services (no more NAT needed)&lt;/li&gt;
&lt;li&gt;Better flexibility and clarity for addressing, including Link Local &amp;amp; local addresses&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Time needed to migrate infra to IPV6&lt;/li&gt;
&lt;li&gt;Clumsier &amp;amp; less-memorable addresses, with unfamiliar idioms (e.g. no more
using 127.0.0.1 or 192.168.1.1 -- though there are replacements)
inherent&lt;/li&gt;
&lt;li&gt;Bugs in legacy code that assumes 32 bit &amp;amp; string-representations of ipv4
addresses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Concepts &amp;amp; Approach
&lt;/h2&gt;

&lt;p&gt;In theory, IPV6 uses 128bit addresses in place of 32 bit.  Most of the&lt;br&gt;
intermediate infra (ISP, backbone) is now compatible. The two areas of attention&lt;br&gt;
for developers would be the server side with AWS , and the client side with your&lt;br&gt;
home/office network.&lt;/p&gt;

&lt;p&gt;The two subject areas needing attention for developers are addressing &amp;amp; routing.&lt;br&gt;
On the server side this means dealing with addressing on EC2, VPC, VPC subnets &amp;amp;&lt;br&gt;
routing tables, and on your home/office network updating your home router config&lt;br&gt;
to obtain &amp;amp; allocate IPV6 addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the Client Side
&lt;/h2&gt;

&lt;p&gt;Home routers within the past 5 years support IPV6 in settings, though usually disabled for simplicity. Once enabled the WAN &amp;amp; LAN will receive two addreses.&lt;/p&gt;

&lt;p&gt;Be sure to select &lt;code&gt;NATIVE&lt;/code&gt; instead of &lt;code&gt;PASSTHROUGH&lt;/code&gt; to get complete IPV6 support&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.asus.com/support/FAQ/113990/"&gt;Asus Routers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.downloads.netgear.com/files/GDC/FVS318N/QSGIPv6_4Apr2012.pdf#:~:text=To%20configure%20the%20IPv6%20routing%20mode%3A%20Select%20Network,IPv6%20addresses.%20Click%20Apply%20to%20save%20your%20changes."&gt;Netgear Routers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Test your config using &lt;a href="https://test-ipv6.com/"&gt;Test IPV6&lt;/a&gt; . At this point you&lt;br&gt;
should have an IPV6 address for your WAN. This will be necessary for routing &amp;amp;&lt;br&gt;
security groups on the AWS side&lt;/p&gt;

&lt;h2&gt;
  
  
  VPC Changes
&lt;/h2&gt;

&lt;p&gt;AWS provides a &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6.html"&gt;thorough guide for migrating to IPV6&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update VPC with an IPV6 allocation&lt;/li&gt;
&lt;li&gt;Update each subnet with a IPV6 subnet allocation -- be sure to resize and order the subnets to the scale needed . Be sure to disable IPV4 auto address allocation, and enable IPV6 address allocation&lt;/li&gt;
&lt;li&gt;Update the routing tables to add the V6 &lt;code&gt;::/0&lt;/code&gt; route&lt;/li&gt;
&lt;li&gt;Update your security groups to add your client-side WAN IPV6 IP&lt;/li&gt;
&lt;li&gt;Choose an instance to update to &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-instance-addressing.html#assign-ipv6-address"&gt;IPV6 addressing&lt;/a&gt;. this will help you test the e2e VPC routing &amp;amp; addressing config&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this point you should be able to ping &amp;amp; SSH to the test instance using all IPV6 addressing&lt;/p&gt;

&lt;h2&gt;
  
  
  EC2 Changes
&lt;/h2&gt;

&lt;p&gt;The EC2 change above will work to add IPV6 addresses to instances, but they will still acquire IPV4 addresses until they are re-launched. This means you'll still be paying for public IPV4 IPs -- about $4 additional per instance-month&lt;/p&gt;

&lt;p&gt;To release public IPV4 IPs, the instances will need to be re-launched.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quickly Relaunch EC2 Instances Using AMI
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Stop (do not terminate) each instance&lt;/li&gt;
&lt;li&gt;Choose &lt;code&gt;Actions → Images &amp;amp; Templates → Create Image&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;create AMI&lt;/li&gt;
&lt;li&gt;Launch new instance with AMI.  Test IPV6 address &amp;amp; confirm no IPV4 address was allocated&lt;/li&gt;
&lt;li&gt;[optional] If the instance has multiple volumes, detach the volume &amp;amp; re-attach to the new instance with the same device ID&lt;/li&gt;
&lt;li&gt;Mark the old instance for termination on a later date&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Review IPV4 Address Allocation &amp;amp; Billing
&lt;/h2&gt;

&lt;p&gt;Once the EC2 migration is complete, &lt;a href="https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/"&gt;review IPV4 address usage using VPC IP&lt;br&gt;
Address&lt;br&gt;
Manager&lt;/a&gt;&lt;br&gt;
and &lt;a href="https://aws.amazon.com/aws-cost-management/aws-cost-explorer/"&gt;AWS Billing Cost&lt;br&gt;
Explorer&lt;/a&gt; (group&lt;br&gt;
by API to see EC2 networking costs)&lt;/p&gt;

&lt;h2&gt;
  
  
  More Resources &amp;amp; Guides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AWS provides a &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6.html"&gt;thorough guide for migrating to IPV6&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/"&gt;Review IPV4 address usage using VPC IP Address Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blazeclan.com/blog/an-essential-guide-to-migrating-a-vpc-from-ipv4-to-ipv6/"&gt;An Essential Guide to Migrating A VPC from IPv4 to IPv6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>networking</category>
      <category>devops</category>
    </item>
    <item>
      <title>Improve WSL Security with Read-Only Filesystem</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Wed, 04 Oct 2023 19:30:00 +0000</pubDate>
      <link>https://dev.to/tonymet/improve-wsl-security-with-read-only-filesystem-23e5</link>
      <guid>https://dev.to/tonymet/improve-wsl-security-with-read-only-filesystem-23e5</guid>
      <description>&lt;p&gt;Originally on &lt;a href="https://tonym.us/improve-wsl-security-with-read-only-filesystem.html#improve-wsl-security-with-read-only-filesystem"&gt;tonym.us&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, all Windows drives are mounted with read &amp;amp; write access (rw) within WSL . Though this is convenient for beginners, it opens up VM shell attacks on your Windows host files.&lt;/p&gt;

&lt;p&gt;Instead, we can disable the auto mount feature using &lt;code&gt;wsl.conf&lt;/code&gt; and selectively add read-only drives inside the WSL VM using &lt;code&gt;/etc/fstab&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Deactivate "auto mount" in &lt;code&gt;/etc/wsl.conf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enable fstab using &lt;code&gt;MOUNTfStAB = true&lt;/code&gt; in &lt;code&gt;wsl.conf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;test config files and mounting work well&lt;/li&gt;
&lt;li&gt;reboot the wsl VM to complete the setup&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Example WSL Config &lt;code&gt;wsl.conf&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Place this inside the /etc/ directory on the WSL VM&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Automatically mount Windows drive when the distribution is launched
[automount]

# disable auto-mounting of c:
enabled = false

# process fstab entries
mountFsTab = true

# disable launching windows exe files
[interop]
enabled = false
appendWindowsPath = false

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example &lt;code&gt;/etc/fstab&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;First, make the target directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir -p /mnt/Users/USERNAME/Downloads

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the entry to &lt;code&gt;/etc/fstab&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#file system dir type options dump pass
# READ ONLY MOUNTS
c:\\Users\\USERNAME\\Downloads /mnt/Users/USERNAME/Downloads drvfs defaults,ro 0 0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing FSTAB Before Launch
&lt;/h2&gt;

&lt;p&gt;Test by un-mounting and re-mounting via fstab&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ umount /mnt/Users/USERNAME/Downloads
$ mount -a # mount fstab entries
$ ls -l /mnt/Users/USERNAME/Downloads

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this should produce no errors and show the expected files at the target directory&lt;/p&gt;

&lt;h2&gt;
  
  
  Re-launch WSL to Complete Test
&lt;/h2&gt;

&lt;p&gt;OUTSIDE the VM, run &lt;code&gt;wsl --shutdown DISTRO&lt;/code&gt;. You can launch the VM by opening a new WSL tab in Windows terminal or via start menu&lt;/p&gt;

&lt;h2&gt;
  
  
  More Information on WSL-Conf
&lt;/h2&gt;

&lt;p&gt;Full details on the wsl config file can be found on &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/wsl-config"&gt;MS' Documentation for wsl.config&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>wsl</category>
      <category>windows</category>
    </item>
    <item>
      <title>Smokeping On Raspberry Pi Zero</title>
      <dc:creator>Tony Metzidis</dc:creator>
      <pubDate>Wed, 18 Jan 2023 08:00:00 +0000</pubDate>
      <link>https://dev.to/tonymet/smokeping-on-raspberry-pi-zero-6a</link>
      <guid>https://dev.to/tonymet/smokeping-on-raspberry-pi-zero-6a</guid>
      <description>&lt;p&gt;&lt;a href="https://oss.oetiker.ch/smokeping/"&gt;Smokeping&lt;/a&gt; is a self-contained network monitoring app , capable of monitoring using ICMP/Ping, HTTP, DNS -- as well as other signals generated from CLI monitoring tools (e.g. curl, dig, mtr etc). It provides a web-based monitoring UI to chart the probe measurements so no further monitoring apps (like Prometheus) are needed.&lt;/p&gt;

&lt;p&gt;Running smokeping on a $5 Raspberry Pi Zero is a fun experiment in lightweight computing . Using Apache Mod FastCGI makes the app usable on the meager hardware.&lt;/p&gt;

&lt;p&gt;By the end of the exercise you'll have the smokeping probes running to test network performance and the UX available on your local network on&lt;code&gt;http://raspberrypi.local/smokeping&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Pi Zero&lt;/li&gt;
&lt;li&gt;MicroSD 4GB+ &lt;/li&gt;
&lt;li&gt;A windows or mac machine to run image installation &amp;amp; configuration&lt;/li&gt;
&lt;li&gt;wifi for installing packages&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Install RaspberryPi OS using the Imager
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Download &amp;amp; Install &lt;a href="https://www.raspberrypi.com/software/"&gt;Raspberry Pi Imager&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Select RaspberryPi OS Lite 32bit from the Advanced menu&lt;/li&gt;
&lt;li&gt;[new] Use the cog / settings menu to enable SSH, set hostname &amp;amp; set WIFI credentials . ⚠️ Don't Skip this step: RaspberryPi OS no longer supports default user credentials.&lt;/li&gt;
&lt;li&gt;Write the image to your Micro SD&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Boot &amp;amp; SSH into the device and update the device (optional)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;SSH into the device e.g. &lt;code&gt;ssh pi@raspberrypi.local&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;update your catalog &lt;code&gt;sudo apt update&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;(optional ~15min) update your installed packages &lt;code&gt;sudo apt upgrade&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  3. Install smokeping, apache2 &amp;amp; fastCGI
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;install apache, smokeping &amp;amp; fast-cgi (to improve loading times) \ &lt;code&gt;$ sudo apt install apache2 fping curl smokeping libapache2-mod-fcgid&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;enable smokeping &lt;code&gt;$ sudo a2enconf smokeping&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;restart and test that smokeping default site is working by visiting &lt;code&gt;http://raspberrypi.local/&lt;/code&gt; in your browser&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this point you will see the default smokeping installation with minimal example probes&lt;/p&gt;

&lt;h2&gt;
  
  
  4 Enable smokeping configuration
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;activate fastcgi and set smokeping to default by adding this block to&lt;code&gt;/etc/apache2/conf-available/smokeping.conf&lt;/code&gt; (after Line 3)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# redirect / to /smokeping 
RedirectMatch ^/$ /smokeping/
# activate fastcgi to improve performance
&amp;lt;Location /smokeping/smokeping.cgi&amp;gt;
    SetHandler fcgid-script
&amp;lt;/Location&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5 Edit Targets and Test
&lt;/h2&gt;

&lt;p&gt;Here is the example head of the Targets config to probe your home router&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ head -n 19 /etc/smokeping/config.d/Targets 
***Targets***

probe = FPing

menu = Top
title = Network Latency Grapher
remark = Welcome to the SmokePing website of WORKS Company. \
         Here you will learn all about the latency of our network.

+ Home

menu = Home
title = Home

++ Gateway
menu = Gateway
title = Gateway
host = 192.168.1.1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6 Follow Up &amp;amp; Next Steps
&lt;/h2&gt;

&lt;p&gt;At this point your probes should be running regularly and collecting historical measurements.&lt;/p&gt;

&lt;p&gt;I recommend adding the following probes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your ISP's first and second HOPs (use &lt;code&gt;traceroute&lt;/code&gt; to identify the IP addresses)&lt;/li&gt;
&lt;li&gt;any streaming services e.g. Netflix, Youtube&lt;/li&gt;
&lt;li&gt;Assign fixed IPs to your devices like PS4, laptop, phone and probe them in your home to catch performance issues.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>raspberrypi</category>
      <category>linux</category>
      <category>cli</category>
      <category>networking</category>
    </item>
  </channel>
</rss>
