<?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>Forem: David R. Myers</title>
    <description>The latest articles on Forem by David R. Myers (@voracious).</description>
    <link>https://forem.com/voracious</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%2F440522%2F09f04292-7a9c-4d2a-a427-95beb60e283f.jpeg</url>
      <title>Forem: David R. Myers</title>
      <link>https://forem.com/voracious</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/voracious"/>
    <language>en</language>
    <item>
      <title>Install and use multiple Bundler versions</title>
      <dc:creator>David R. Myers</dc:creator>
      <pubDate>Sun, 12 Jun 2022 01:33:52 +0000</pubDate>
      <link>https://forem.com/voracious/install-and-use-multiple-bundler-versions-3m2a</link>
      <guid>https://forem.com/voracious/install-and-use-multiple-bundler-versions-3m2a</guid>
      <description>&lt;p&gt;As of Bundler v2.3 (when using RubyGems v3.3+), Bundler will automatically use the &lt;code&gt;BUNDLED WITH&lt;/code&gt; version specified in &lt;code&gt;Gemfile.lock&lt;/code&gt; when running the &lt;code&gt;bundle install&lt;/code&gt; command. If the specified version of Bundler is not available, &lt;a href="https://bundler.io/blog/2022/01/23/bundler-v2-3.html"&gt;it will be downloaded and installed&lt;/a&gt;.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bundler &lt;span class="nt"&gt;-v&lt;/span&gt;
Bundler version 2.3.15

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-2&lt;/span&gt; ./example/Gemfile.lock
BUNDLED WITH
   2.1.4

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ./example &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bundler &lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
Bundler version 2.1.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you can't upgrade to v2.3, there is a workaround. You will have to install the correct version of Bundler manually, but then you can use the &lt;code&gt;_version_&lt;/code&gt; syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bundler _2.1.4_ &lt;span class="nt"&gt;-v&lt;/span&gt;
Bundler version 2.1.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ruby</category>
      <category>bundler</category>
      <category>webdev</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>A Practical Cheat Sheet for CSS Flexbox (Containers)</title>
      <dc:creator>David R. Myers</dc:creator>
      <pubDate>Tue, 27 Jul 2021 17:58:31 +0000</pubDate>
      <link>https://forem.com/voracious/a-practical-cheat-sheet-for-css-flexbox-401p</link>
      <guid>https://forem.com/voracious/a-practical-cheat-sheet-for-css-flexbox-401p</guid>
      <description>&lt;p&gt;I originally posted this Flexbox cheat sheet &lt;a href="https://twitter.com/voraciousdev/status/1419769440938364928" rel="noopener noreferrer"&gt;on Twitter&lt;/a&gt;, but the response was so positive that I decided to write it up here too! We will cover the (in my opinion) most common scenarios for Flexbox.&lt;/p&gt;

&lt;p&gt;If you just want the cheat sheet (pictured above), &lt;a href="https://imgur.com/a/zhG7Yoj" rel="noopener noreferrer"&gt;you can download it here&lt;/a&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
Horizontal Alignment

&lt;ul&gt;
&lt;li&gt;Anchor group to the center (horizontally)&lt;/li&gt;
&lt;li&gt;Anchor group to the right side&lt;/li&gt;
&lt;li&gt;Add space around all items&lt;/li&gt;
&lt;li&gt;Add space between all items&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Vertical Alignment

&lt;ul&gt;
&lt;li&gt;Anchor group to the center (vertically)&lt;/li&gt;
&lt;li&gt;Anchor group to the top&lt;/li&gt;
&lt;li&gt;Anchor group to the bottom&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Perfect (Vertical and Horizontal) Center Alignment&lt;/li&gt;
&lt;li&gt;
Content Direction

&lt;ul&gt;
&lt;li&gt;Reverse the flow of content (horizontally)&lt;/li&gt;
&lt;li&gt;Flow content vertically instead of horizontally&lt;/li&gt;
&lt;li&gt;Reverse the flow of content (vertically)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Content Wrapping

&lt;ul&gt;
&lt;li&gt;Wrap content to next lines (flow down)&lt;/li&gt;
&lt;li&gt;Wrap content to previous lines (flow up)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Default Behavior&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Horizontal Alignment
&lt;/h2&gt;

&lt;p&gt;You can align items horizontally as a group or individually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anchor group to the center (horizontally)
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FDXQx513.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%2Fi.imgur.com%2FDXQx513.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Anchor group to the right side
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FjsBsnlq.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%2Fi.imgur.com%2FjsBsnlq.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add space around all items
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-around&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FYkwhcTE.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%2Fi.imgur.com%2FYkwhcTE.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add space between all items
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-between&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FFuFXnmh.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%2Fi.imgur.com%2FFuFXnmh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical Alignment
&lt;/h2&gt;

&lt;p&gt;You can align items vertically as a group.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anchor group to the center (vertically)
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FAr3SGwr.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%2Fi.imgur.com%2FAr3SGwr.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Anchor group to the top
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-start&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FFPE2iwN.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%2Fi.imgur.com%2FFPE2iwN.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Anchor group to the bottom
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FXvJuZBl.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%2Fi.imgur.com%2FXvJuZBl.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Perfect (Vertical and Horizontal) Center Alignment
&lt;/h2&gt;

&lt;p&gt;You can combine selectors to get your desired layout. Perfect centering is a breeze with Flexbox.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FszacZbz.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%2Fi.imgur.com%2FszacZbz.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Content Direction
&lt;/h2&gt;

&lt;p&gt;You can change the overall content flow (column or row), and you can even change the arrangement of content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reverse the flow of content (horizontally)
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row-reverse&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4WZXnbY.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%2Fi.imgur.com%2F4WZXnbY.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Flow content vertically instead of horizontally
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4C0f7kF.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%2Fi.imgur.com%2F4C0f7kF.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reverse the flow of content (vertically)
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column-reverse&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FuqVFhKd.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%2Fi.imgur.com%2FuqVFhKd.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Content Wrapping
&lt;/h2&gt;

&lt;p&gt;By default, all items are put on a single line.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FutYDsX5.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%2Fi.imgur.com%2FutYDsX5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap content to next lines (flow down)
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FtNyEkEi.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%2Fi.imgur.com%2FtNyEkEi.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap content to previous lines (flow up)
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap-reverse&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FBj5Xmz2.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%2Fi.imgur.com%2FBj5Xmz2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Behavior
&lt;/h2&gt;

&lt;p&gt;The default behavior of Flexbox will...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat the container as block (full width)&lt;/li&gt;
&lt;li&gt;Left align all items&lt;/li&gt;
&lt;li&gt;Stretch each item's height to fit the container&lt;/li&gt;
&lt;li&gt;Fit all items on a single line&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&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;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FWrZXttr.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%2Fi.imgur.com%2FWrZXttr.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for taking the time to check this out! If you think something is missing or you just want to say hello, please leave a comment below! ✌️&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>flexbox</category>
      <category>frontend</category>
    </item>
    <item>
      <title>A Guide to Customizing the Zsh Shell Prompt</title>
      <dc:creator>David R. Myers</dc:creator>
      <pubDate>Thu, 11 Mar 2021 21:13:23 +0000</pubDate>
      <link>https://forem.com/voracious/a-guide-to-customizing-the-zsh-shell-prompt-2an6</link>
      <guid>https://forem.com/voracious/a-guide-to-customizing-the-zsh-shell-prompt-2an6</guid>
      <description>&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%2Fi.imgur.com%2Fs8RVMid.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%2Fi.imgur.com%2Fs8RVMid.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal of this article is to teach you just enough about the shell prompt to make some helpful customizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the shell prompt?
&lt;/h2&gt;

&lt;p&gt;The prompt is the bit of text that shows up in our shells to indicate that we can interact with them. The prompt usually gives us some details about the current shell session such as username, machine name, current directory, and some kind of prompt termination token. An example might look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;david@macbook /tmp &lt;span class="nv"&gt;$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of this information can be customized through the shell's prompt strings. Each shell has specific escape sequences that must be used. This just means that we have to use different tokens to represent things such as username, color formatting, etc. For the purposes of this article, we will be using &lt;a href="https://www.zsh.org/" rel="noopener noreferrer"&gt;Zsh&lt;/a&gt;, and we can confirm that is our current shell by running this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="c"&gt;# /bin/zsh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Introducing PS1
&lt;/h3&gt;

&lt;p&gt;The primary prompt string is stored in a variable called &lt;code&gt;PS1&lt;/code&gt;. There are five prompt strings in total, so the trailing number denotes its responsibility. The primary prompt string is the one that is printed to &lt;code&gt;stdout&lt;/code&gt; when the shell is waiting for a new command, and it is therefore the one we probably see most frequently. Unlike a typical variable, these prompt strings undergo expansion &lt;em&gt;every time the prompt is displayed&lt;/em&gt;. This is what allows us to update the displayed path after changing directories, for example. A &lt;code&gt;PS1&lt;/code&gt; string might look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'%n@%m %/ $ '&lt;/span&gt; &lt;span class="c"&gt;# david@macbook /tmp $ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will dive into this more below.&lt;/p&gt;

&lt;h4&gt;
  
  
  Breaking it down
&lt;/h4&gt;

&lt;p&gt;The first thing to note is the use of single quotes &lt;code&gt;''&lt;/code&gt;. We can use double quotes, but we have to remember to escape all of the expressions that we want to re-evaluate each time the prompt is displayed. Double quoted strings undergo normal expansion and substitution &lt;em&gt;before&lt;/em&gt; being stored in a variable, so evaluation would only happen once per shell session rather than once per prompt. It doesn't make a difference for our simple example above, but it starts to matter when we introduce things like variables and shell expressions. More on that later.&lt;/p&gt;

&lt;p&gt;Next, let's take a look at each of the escape sequences in our prompt string. The first one is &lt;code&gt;%n&lt;/code&gt;, and it represents our username. The next escape sequence is &lt;code&gt;%/&lt;/code&gt;, and it represents the current directory. For these examples, we will assume the username is &lt;code&gt;david&lt;/code&gt; and the current directory is &lt;code&gt;/tmp&lt;/code&gt;. For more on Zsh prompt expansion, &lt;a href="http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html" rel="noopener noreferrer"&gt;check out the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we customize it?
&lt;/h2&gt;

&lt;p&gt;We are going to build our prompt from scratch, so let's start with some basic information. We talked about the &lt;code&gt;PS1&lt;/code&gt; variable above, but we didn't talk about where it needs to be defined. For Zsh, we will use &lt;code&gt;~/.zshrc&lt;/code&gt; to set the &lt;code&gt;PS1&lt;/code&gt; variable. This file is loaded at the beginning of every shell session, so it will ensure our configuration is respected for all sessions and not just the current one. Every shell has a default prompt string, and we can view the raw source by echoing the &lt;code&gt;PS1&lt;/code&gt; variable (e.g. &lt;code&gt;echo $PS1&lt;/code&gt;). While we can build on top of the existing one, for the purposes of learning, we are going to build ours from scratch. Add the following to your Zsh config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.zshrc&lt;/span&gt;
&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'$ '&lt;/span&gt; &lt;span class="c"&gt;# $ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prompt does its primary job of telling us the shell is ready for input, but we can make it much more useful. Let's start by adding our username &lt;code&gt;%n&lt;/code&gt;, our machine name &lt;code&gt;%m&lt;/code&gt;, and our current directory &lt;code&gt;%/&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.zshrc&lt;/span&gt;
&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'%n@%m %/ $ '&lt;/span&gt; &lt;span class="c"&gt;# david@macbook /tmp $ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's looking a lot more like what we might expect from a typical shell prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding some color
&lt;/h3&gt;

&lt;p&gt;Now that we have a basic prompt, we can spice it up with some color. To change the color of our prompt, we need to use a new type of sequence. Many modern terminals support 256 colors, and while some of these can be referenced by name, most will need to be referenced by their color code - ranging from 0 to 255. Colors are applied via start and stop sequences indicated by &lt;code&gt;%F{}&lt;/code&gt; and &lt;code&gt;%f&lt;/code&gt;, respectively. Let's put this into practice by coloring our current directory red.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.zshrc&lt;/span&gt;
&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'%n@%m %F{red}%/%f $ '&lt;/span&gt; &lt;span class="c"&gt;# david@macbook /tmp $ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding the current Git branch
&lt;/h3&gt;

&lt;p&gt;Another useful piece of information which is not typically displayed by default is version control. Not all directories are version controlled, so this info will only show up when it is relevant. For this guide, we will use Git, but Zsh actually does &lt;a href="http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#vcs_005finfo-Examples" rel="noopener noreferrer"&gt;support a few others&lt;/a&gt;. We are going to add the branch name of the current repo to our prompt, and in order to do this, we need to cover a few details about &lt;code&gt;vcs_info&lt;/code&gt; . It is a framework that ships with Zsh to gather information from various version control systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.zshrc&lt;/span&gt;
autoload &lt;span class="nt"&gt;-Uz&lt;/span&gt; vcs_info &lt;span class="c"&gt;# enable vcs_info&lt;/span&gt;
precmd &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; vcs_info &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="c"&gt;# always load before displaying the prompt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This block is what actually enables and autoloads &lt;code&gt;vcs_info&lt;/code&gt; before each rendering of the shell prompt. It stores the data in a new variable called &lt;code&gt;vcs_info_msg_0_&lt;/code&gt;. If we use this variable in our prompt string, it will display some basic info such as our version control system and the current branch (e.g. &lt;code&gt;(git)-[main]-&lt;/code&gt;). To format this info, we can use &lt;code&gt;zstyle&lt;/code&gt; like so.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.zshrc&lt;/span&gt;
zstyle &lt;span class="s1"&gt;':vcs_info:*'&lt;/span&gt; formats &lt;span class="s1"&gt;' %s(%b)'&lt;/span&gt; &lt;span class="c"&gt;# git(main)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;zstyle&lt;/code&gt; format string has its own tokens that are expanded in the prompt string. The first token &lt;code&gt;%s&lt;/code&gt; represents the current version control system. The next token &lt;code&gt;%b&lt;/code&gt; represents the current branch name. For more information on available tokens, &lt;a href="http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#vcs_005finfo-Configuration" rel="noopener noreferrer"&gt;check out the docs&lt;/a&gt;. Finally, we can combine everything we've learned and add a bit of color to the branch name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.zshrc&lt;/span&gt;
autoload &lt;span class="nt"&gt;-Uz&lt;/span&gt; vcs_info &lt;span class="c"&gt;# enable vcs_info&lt;/span&gt;
precmd &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; vcs_info &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="c"&gt;# always load before displaying the prompt&lt;/span&gt;
zstyle &lt;span class="s1"&gt;':vcs_info:*'&lt;/span&gt; formats &lt;span class="s1"&gt;' %s(%F{red}%b%f)'&lt;/span&gt; &lt;span class="c"&gt;# git(main)&lt;/span&gt;

&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'%n@%m %F{red}%/%f$vcs_info_msg_0_ $ '&lt;/span&gt; &lt;span class="c"&gt;# david@macbook /tmp/repo (main) $ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final result
&lt;/h3&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%2Fi.imgur.com%2FnCWDdyi.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%2Fi.imgur.com%2FnCWDdyi.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To summarize, we have learned how to include specific information about our system and shell session, how to display version control status information, and how to apply color to these various pieces of information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I hope this article helped shed some light on the shell prompt syntax. It was a lot of fun to write while experimenting with my own prompt (which you can see at the top of this page). As a final note, I would love to share &lt;a href="https://github.com/writewithocto/octo" rel="noopener noreferrer"&gt;octo&lt;/a&gt; - a hackable, offline-first markdown editor for notes, code snippets, and writing that runs entirely in-browser. It's free and open source, and working on it gives me a lot of ideas and inspiration for the articles I write. Thank you, and happy coding. ✌️&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>bash</category>
      <category>tutorial</category>
      <category>zsh</category>
    </item>
    <item>
      <title>A Guide to Web Development on the Windows Subsystem for Linux (WSL)</title>
      <dc:creator>David R. Myers</dc:creator>
      <pubDate>Sat, 02 Jan 2021 20:59:33 +0000</pubDate>
      <link>https://forem.com/voracious/a-guide-to-web-development-on-the-windows-subsystem-for-linux-wsl-26og</link>
      <guid>https://forem.com/voracious/a-guide-to-web-development-on-the-windows-subsystem-for-linux-wsl-26og</guid>
      <description>&lt;p&gt;This guide assumes you already have the Windows Subsystem for Linux (WSL) 2 installed. If that is not the case, I highly recommend you read through my previous article,  &lt;a href="https://dev.to/voraciousdev/a-guide-to-installing-the-windows-subsystem-for-linux-wsl-and-windows-terminal-4dd4"&gt;A Guide to Installing the Windows Subsystem for Linux (WSL) and Windows Terminal&lt;/a&gt;, first. We are going to cover some of the most common web development tools that we need to get up and running, but there might be something missing. If that is the case, please leave a comment below! While I am using my own experience as a foundation, I am happy to amend this article as needed to make sure we cover the most common tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Linux package repositories
&lt;/h2&gt;

&lt;p&gt;Make sure the Linux packages are up-to-date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Git
&lt;/h2&gt;

&lt;p&gt;Make sure Git is installed and up-to-date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sign your commits with GPG
&lt;/h3&gt;

&lt;p&gt;Make sure GPG is installed and up-to-date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; gnupg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Generate a GPG key
&lt;/h4&gt;

&lt;p&gt;To use GPG signing with Git, you will need a GPG keypair. If you already have one, you can skip to the next step. This command will prompt you for the settings of your new key. If you do not know what to choose for the key settings, just go with the defaults. The two things you will need to provide are your name and your email.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# generate a new gpg key&lt;/span&gt;
gpg &lt;span class="nt"&gt;--full-generate-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure Git to sign commits
&lt;/h4&gt;

&lt;p&gt;This information is based on &lt;a href="https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/telling-git-about-your-signing-key" rel="noopener noreferrer"&gt;GitHub's guide&lt;/a&gt;. To list and highlight your available signing keys, run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--list-secret-keys&lt;/span&gt; &lt;span class="nt"&gt;--keyid-format&lt;/span&gt; long | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 2 ^sec | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 2 &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="s2"&gt;"(?&amp;lt;=/)&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="s2"&gt;+"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the highlighted part of your desired key (on the &lt;code&gt;sec&lt;/code&gt; line after the &lt;code&gt;/&lt;/code&gt;) for the next step. The terminal output should look something like this.&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%2Fi.imgur.com%2FxROdSK9.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%2Fi.imgur.com%2FxROdSK9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you need to tell Git about your signing key and enable commit signing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# replace `&amp;lt;key&amp;gt;` with the key copied above&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.signingkey &amp;lt;key&amp;gt;

&lt;span class="c"&gt;# enable commit signing&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; commit.gpgsign &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;

&lt;p&gt;GitHub is the most common platform for code hosting, and it is the one I use. That said, this information should be applicable to other platforms as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSH
&lt;/h3&gt;

&lt;p&gt;If you prefer to use SSH for GitHub (like me), you can generate a new SSH keypair and copy the public key to your clipboard using a Windows utility called &lt;code&gt;clip.exe&lt;/code&gt;. Run the following commands to generate a new SSH keypair and copy the public key to your clipboard. Make sure you update the fake email below to match your actual email. If you decide to change the name of your generated SSH key, make sure to update the second command with the appropriate file name (&lt;code&gt;id_ed25519&lt;/code&gt; is the default).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# generate the ssh keypair&lt;/span&gt;
ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; youremail@provider.example

&lt;span class="c"&gt;# copy the public key&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ed25519.pub | clip.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then upload your public key to GitHub via your &lt;a href="https://github.com/settings/keys" rel="noopener noreferrer"&gt;settings page&lt;/a&gt; under the SSH keys section.&lt;/p&gt;

&lt;h3&gt;
  
  
  GPG
&lt;/h3&gt;

&lt;p&gt;If you generated a GPG keypair in the Git section above, you can export the public key for use in GitHub or any other provider where you want your commits to show up as verified. Run the following command to copy the public key to your clipboard. Make sure you update the fake email below to match your actual email.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# copy the public key&lt;/span&gt;
gpg &lt;span class="nt"&gt;--export&lt;/span&gt; &lt;span class="nt"&gt;--armor&lt;/span&gt; youremail@provider.example | clip.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can upload your public key to GitHub via your &lt;a href="https://github.com/settings/keys" rel="noopener noreferrer"&gt;settings page&lt;/a&gt; under the GPG keys section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node / NPM
&lt;/h2&gt;

&lt;p&gt;We have a couple of options available for installing Node and NPM. If you need to switch between multiple versions, I highly recommend using NVM. If you just want the latest version available for the Ubuntu distribution of Linux (without an easy method of switching), skip down to the Apt section below.&lt;/p&gt;

&lt;h3&gt;
  
  
  NVM
&lt;/h3&gt;

&lt;p&gt;These instructions were pulled from the &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;NVM README&lt;/a&gt;. Feel free to check out the instructions there if you want more details. Otherwise, run the following commands to get set up with the latest version of Node and NPM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install nvm (latest version at time of writing)&lt;/span&gt;
curl &lt;span class="nt"&gt;-o-&lt;/span&gt; https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash

&lt;span class="c"&gt;# reload the .bashrc file&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc

&lt;span class="c"&gt;# install the latest version of node&lt;/span&gt;
nvm &lt;span class="nb"&gt;install &lt;/span&gt;node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Apt
&lt;/h3&gt;

&lt;p&gt;This installs Node from the Ubuntu package repositories. The latest version available through Ubuntu might not be the latest version available through other means.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker
&lt;/h2&gt;

&lt;p&gt;Download and install &lt;a href="https://hub.docker.com/editions/community/docker-ce-desktop-windows" rel="noopener noreferrer"&gt;Docker Desktop for Windows&lt;/a&gt;. To enable Docker for WSL 2, make sure the &lt;strong&gt;Install required Windows components for WSL 2&lt;/strong&gt; option is checked. Log out and log back in to finish the installation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text Editor
&lt;/h2&gt;

&lt;p&gt;Using a traditional text editor with the WSL will require some extra configuration depending on the one you choose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atom
&lt;/h3&gt;

&lt;p&gt;Launching Atom from within WSL is not as simple as you might think. The &lt;code&gt;atom&lt;/code&gt; binary needs to be executed in a Windows &lt;code&gt;cmd&lt;/code&gt; context, and it needs the &lt;em&gt;Windows&lt;/em&gt; path of the specified directory instead of the Linux path. I created a &lt;a href="https://gist.github.com/voraciousdev/1a1473ea36906c8f6830a17701e7fd21" rel="noopener noreferrer"&gt;little helper script&lt;/a&gt; to do exactly that. Download it to the &lt;code&gt;/usr/local/bin&lt;/code&gt; directory and make it executable by running the following commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# download the atom script&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; /usr/local/bin/atom https://gist.githubusercontent.com/voraciousdev/1a1473ea36906c8f6830a17701e7fd21/raw/b8c697ca810022f2fc4be9eef3f72a54c6073b7e/atom.sh

&lt;span class="c"&gt;# make it executable&lt;/span&gt;
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; +x /usr/local/bin/atom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the &lt;code&gt;atom&lt;/code&gt; command can be run from within WSL to open the app on Windows. It is worth mentioning that this does not implement full &lt;code&gt;atom&lt;/code&gt; argument support at the moment. This script only accepts a single, optional path argument for the time being. Here are a few examples of how to use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# open the current directory&lt;/span&gt;
atom &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# open another directory&lt;/span&gt;
atom ~/workspace/project

&lt;span class="c"&gt;# open atom without specifying a project&lt;/span&gt;
atom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  VS Code
&lt;/h3&gt;

&lt;p&gt;Download and install &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt;. When you open VS Code for the first time, it will prompt you to install recommended extensions. One of the recommended extensions will be &lt;a href="https://aka.ms/vscode-remote/download/extension" rel="noopener noreferrer"&gt;Remote Development&lt;/a&gt;. Here are a few examples of how to use the new &lt;code&gt;code&lt;/code&gt; command from the WSL terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# open the current directory&lt;/span&gt;
code &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# open another directory&lt;/span&gt;
code ~/workspace/project

&lt;span class="c"&gt;# open vscode without specifying a project&lt;/span&gt;
code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;If you think something is missing from this article, please let me know. I am happy to update it with other common web dev tools. As always, thank you for reading!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>linux</category>
      <category>bash</category>
    </item>
    <item>
      <title>A Guide to Installing the Windows Subsystem for Linux (WSL) and Windows Terminal</title>
      <dc:creator>David R. Myers</dc:creator>
      <pubDate>Tue, 29 Dec 2020 05:00:20 +0000</pubDate>
      <link>https://forem.com/voracious/a-guide-to-installing-the-windows-subsystem-for-linux-wsl-and-windows-terminal-4dd4</link>
      <guid>https://forem.com/voracious/a-guide-to-installing-the-windows-subsystem-for-linux-wsl-and-windows-terminal-4dd4</guid>
      <description>&lt;p&gt;As a developer that typically works on Mac or Linux, you will be disappointed with the out-of-the-box terminal in Windows. Lucky for us, Windows supports a fairly smooth Linux integration called the Windows Subsystem for Linux (or WSL for short). If you are unfamiliar with it, Microsoft has a pretty concise explanation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Windows Subsystem for Linux lets developers run a GNU/Linux environment -- including most command-line tools, utilities, and applications -- directly on Windows, unmodified, without the overhead of a traditional virtual machine or dual-boot setup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This guide is meant to serve as a quick reference for setting it up yourself (as I recently had to do).&lt;/p&gt;

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

&lt;p&gt;This guide is not a comprehensive resource for all available options. Instead, I have made some assumptions to help you get it set up quickly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You &lt;strong&gt;do not&lt;/strong&gt; want to join the &lt;a href="https://insider.windows.com/getting-started"&gt;Windows Insider Program&lt;/a&gt; and install a preview build of Windows.&lt;/li&gt;
&lt;li&gt;You &lt;strong&gt;do&lt;/strong&gt; want to upgrade to WSL 2.&lt;/li&gt;
&lt;li&gt;You &lt;strong&gt;do&lt;/strong&gt; want to use Ubuntu 20.04 LTS as your Linux distribution.&lt;/li&gt;
&lt;li&gt;You &lt;strong&gt;do&lt;/strong&gt; want to use the Windows Terminal app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A note about WSL 2 performance
&lt;/h3&gt;

&lt;p&gt;While WSL 2 is more performant than WSL 1 in most cases, there is a specific scenario where it can actually perform worse than WSL 1. This occurs when you are working on files across file systems. Specifically, you will want to make sure you store your project files on the Linux file system instead of the Windows file system (assuming you are using Linux utilities). Microsoft explains this in further detail on &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/compare-versions"&gt;Microsoft Docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable WSL 1
&lt;/h3&gt;

&lt;p&gt;We have to first enable WSL 1 before we can upgrade to WSL 2. In PowerShell (as an administrator), run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dism.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/online&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/enable-feature&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/featurename:Microsoft-Windows-Subsystem-Linux&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/norestart&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enable the Virtual Machine Platform feature
&lt;/h3&gt;

&lt;p&gt;To enable the Virtual Machine Platform feature (required for WSL 2), run the following command in PowerShell (as an administrator).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dism.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/online&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/enable-feature&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/featurename:VirtualMachinePlatform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/norestart&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Restart your machine
&lt;/h3&gt;

&lt;p&gt;In order to continue the installation of WSL 1 and 2, you will need to restart your machine. This can be done by running the following in PowerShell (as an administrator).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Restart-Computer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update the Linux kernel
&lt;/h3&gt;

&lt;p&gt;The Linux kernel update package is required to upgrade to WSL 2. To download and run the update, I recommend moving into a different directory since the administrator PowerShell dumps you into the &lt;code&gt;system32&lt;/code&gt; directory. You can accomplish this with the following command in PowerShell (as an administrator).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-outfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;update.msi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\update.msi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be prompted to finish the WSL update.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set WSL 2 as the default
&lt;/h3&gt;

&lt;p&gt;In PowerShell (as an administrator), run the following command to set WSL 2 as the default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--set-default-version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Ubuntu 20.04 LTS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.microsoft.com/en-us/p/ubuntu-2004-lts/9n6svws3rx71"&gt;Get Ubuntu 20.04 LTS&lt;/a&gt; from Microsoft. You will need to click the "Get" link to open the Microsoft Store. From there, you can click "Install" to download and install the Ubuntu distribution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Launch Ubuntu
&lt;/h3&gt;

&lt;p&gt;The Ubuntu 20.04 LTS app should now be easily searchable in your list of Windows apps. Launch the app to finish setup. You will need to provide a username and password.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: If you encounter an error related to virtualization when launching the app, you may need to enable virtualization at the BIOS level.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Windows Terminal
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://aka.ms/terminal"&gt;Get Windows Terminal&lt;/a&gt; from Microsoft. You will need to click the "Get" link to open the Microsoft Store. From there, you can click "Install" to download and install the app. For more information on Windows Terminal, head over to &lt;a href="https://docs.microsoft.com/en-us/windows/terminal/"&gt;Microsoft Docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Ubuntu as the default shell
&lt;/h3&gt;

&lt;p&gt;To set Ubuntu as the default terminal in Windows Terminal, you will need to edit the &lt;code&gt;settings.json&lt;/code&gt; file. To open this, click the dropdown arrow next to the new tab button and click on "Settings" near the bottom of the menu that pops up. The file will look something like this (unnecessary info has been removed).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"defaultProfile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{a-random-uuid-for-powershell}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"profiles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"guid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{a-random-uuid-for-powershell}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Windows PowerShell"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"guid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{a-random-uuid-for-ubuntu}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ubuntu-20.04"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You just need to update the &lt;code&gt;defaultProfile&lt;/code&gt; property with the UUID for Ubuntu and save the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the Linux file system as your default
&lt;/h3&gt;

&lt;p&gt;When you launch Windows Terminal, you &lt;em&gt;will&lt;/em&gt; be presented with the Ubuntu shell, but you will be dropped into the Windows file system. As mentioned above, WSL 2 works best when you use the Linux file system. To change your default directory to your Linux user's home directory, you just need to run the following command in the Ubuntu shell (your new default for Windows Terminal).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'cd ~'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can change &lt;code&gt;~&lt;/code&gt; to something else if you would like, but the home directory is usually a safe place to land in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;While this isn't necessarily a &lt;em&gt;short&lt;/em&gt; article, I believe it is pretty concise. It aggregates information from a few sources to hopefully get you up and running with WSL 2 and Windows Terminal as quickly as possible.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>linux</category>
      <category>development</category>
      <category>bash</category>
    </item>
    <item>
      <title>An Introduction to vue-markdown-editor</title>
      <dc:creator>David R. Myers</dc:creator>
      <pubDate>Mon, 28 Dec 2020 21:50:55 +0000</pubDate>
      <link>https://forem.com/voracious/an-alternative-markdown-editor-component-for-vue-479a</link>
      <guid>https://forem.com/voracious/an-alternative-markdown-editor-component-for-vue-479a</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/voraciousdev/vue-markdown-editor"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cy_QqFoT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/voraciousdev/vue-markdown-editor/master/images/screenshot.png" alt="" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the biggest challenges I faced while building &lt;a href="https://github.com/voraciousdev/octo"&gt;Octo&lt;/a&gt; was the markdown editor. When it comes to implementing a markdown text input, there is usually one way to go about it: a &lt;strong&gt;plain text&lt;/strong&gt; input field with an optional &lt;strong&gt;preview&lt;/strong&gt; mode. This approach obviously works, but the experience can be a bit clunky when writing larger bodies of content.&lt;/p&gt;

&lt;p&gt;In this article, we will cover an alternative approach that - while being a bit heavier - offers a smoother user experience for the author. This will be accomplished with a standalone Vue component called &lt;a href="https://github.com/voraciousdev/vue-markdown-editor"&gt;vue-markdown-editor&lt;/a&gt; (MIT-licensed) which was extracted from the core of &lt;a href="https://github.com/voraciousdev/octo"&gt;Octo&lt;/a&gt;. This component acts as a plain text input, but it renders headers, syntax highlighting, and images in place. This is especially helpful for overall readability and catching syntax errors without interrupting focus by switching between edit and preview panels. Feel free to try it out at &lt;a href="https://octo.app"&gt;octo.app&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new Vue project
&lt;/h2&gt;

&lt;p&gt;To kick things off, we need to create a new Vue project. We will create a &lt;em&gt;bare&lt;/em&gt; project with the &lt;code&gt;-b&lt;/code&gt; flag and use the &lt;em&gt;default&lt;/em&gt; presets with the &lt;code&gt;-d&lt;/code&gt; flag. The default preset uses &lt;code&gt;yarn&lt;/code&gt;, but the snippets below will include the corresponding &lt;code&gt;npm&lt;/code&gt; commands as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# create and open the project&lt;/span&gt;
vue create &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; playground &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;playground
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install the editor component
&lt;/h2&gt;

&lt;p&gt;Next, we will install the Markdown editor component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# yarn (the default preset)&lt;/span&gt;
yarn add @voraciousdev/vue-markdown-editor

&lt;span class="c"&gt;# npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @voraciousdev/vue-markdown-editor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implement the editor
&lt;/h2&gt;

&lt;p&gt;We need to import, register, and then use the new component. This is no different than importing another component from a relative path. Note the use of &lt;code&gt;v-model&lt;/code&gt; on the &lt;code&gt;MarkdownEditor&lt;/code&gt; component. This is the simplest way to bind our own data to the markdown editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- src/App.vue --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Playground&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- use the registered component --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;MarkdownEditor&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"markdown"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"editor"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// import MarkdownEditor from the package&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MarkdownEditor&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@voraciousdev/vue-markdown-editor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// register the component as MarkdownEditor&lt;/span&gt;
    &lt;span class="c1"&gt;// this step is what allows us to reference &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MarkdownEditor&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;
    &lt;span class="nx"&gt;MarkdownEditor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;# Hello, World!&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s1"&gt;How are you today?&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#111&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#aaa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.app&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.editor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#050505&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the app
&lt;/h2&gt;

&lt;p&gt;All we have to do now is run the app and play around with the editor!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# yarn (the default preset)&lt;/span&gt;
yarn serve

&lt;span class="c"&gt;# npm&lt;/span&gt;
npm run serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://youtu.be/LfhkoCAK6aA"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q2utmOzN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://j.gifs.com/4Q1DNJ.gif" alt="" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This component was designed to be as simple to use as a &lt;code&gt;textarea&lt;/code&gt;. Content is kept in plain text, so we can copy from or paste into the editor whenever we want!&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;This example project is on &lt;a href="https://github.com/voraciousdev/vue-markdown-editor/tree/master/examples/playground"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All in all, this article was pretty simple, but I really wanted to show off this new Vue component. It's open source and now available for anyone to use. I will continue to work on and improve this component because it powers my open source Markdown editor &lt;a href="https://github.com/voraciousdev/octo"&gt;Octo&lt;/a&gt; (which I used to write this article). Both are MIT-licensed and available for anyone to use. I would greatly appreciate any feedback, and I hope you have a fantastic day!&lt;/p&gt;

</description>
      <category>vue</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>showdev</category>
    </item>
    <item>
      <title>A Practical Guide to the Web Cryptography API</title>
      <dc:creator>David R. Myers</dc:creator>
      <pubDate>Wed, 09 Sep 2020 23:46:06 +0000</pubDate>
      <link>https://forem.com/voracious/a-practical-guide-to-the-web-cryptography-api-4o8n</link>
      <guid>https://forem.com/voracious/a-practical-guide-to-the-web-cryptography-api-4o8n</guid>
      <description>&lt;p&gt;Client-side encryption is a feature I had wanted to implement in &lt;a href="https://github.com/voraciousdev/octo"&gt;octo&lt;/a&gt; for a while now. When it finally came time to tackle it, I was surprised at the sparse real-world examples on the topic. The documentation on &lt;a href="https://developer.mozilla.org/en-US/"&gt;MDN&lt;/a&gt; is robust, but it requires a lot of jumping around to individual method APIs. I hope this article is helpful for anyone out there looking for guidance.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The Web Cryptography API is asynchronous, so I use the async/await syntax in this article for concision.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  SubtleCrypto
&lt;/h3&gt;

&lt;p&gt;The Web Cryptography API was initially exposed through a nonstandard interface called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Crypto"&gt;Crypto&lt;/a&gt;, but it was later standardized through a new interface called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto"&gt;SubtleCrypto&lt;/a&gt;. This article will focus on the public SubtleCrypto interface exposed at &lt;code&gt;window.crypto.subtle&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encryption
&lt;/h2&gt;

&lt;p&gt;For the purposes of this article, we are going to use a symmetric algorithm. The public-key (asymmetric) strategy has a hard limit on how much data it can encrypt based on key size: &lt;code&gt;(keyBits / 8) - padding&lt;/code&gt;. Symmetric encryption uses the same key to encrypt and decrypt data, and it does not have the same constraint. There are a few &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#Supported_algorithms"&gt;supported algorithms&lt;/a&gt;, but the recommended symmetric algorithm is &lt;code&gt;AES-GCM&lt;/code&gt; for its &lt;a href="https://en.wikipedia.org/wiki/Authenticated_encryption"&gt;authenticated mode&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating a Key
&lt;/h3&gt;

&lt;p&gt;To start things off, we need to generate a symmetric key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateKey&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;encrypt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decrypt&lt;/span&gt;&lt;span class="dl"&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;h3&gt;
  
  
  Encoding Data
&lt;/h3&gt;

&lt;p&gt;Before we can encrypt data, we first have to encode it into a byte stream. We can achieve this pretty simply with the &lt;code&gt;TextEncoder&lt;/code&gt; class. This little utility will be used by our &lt;code&gt;encrypt&lt;/code&gt; function later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;h3&gt;
  
  
  Generating an Initialization Vector (IV)
&lt;/h3&gt;

&lt;p&gt;Simply put, an IV is what introduces true randomness into our encryption strategy. When using the same key to encrypt multiple sets of data, it is possible to derive relationships between the encrypted chunks of the cipher and therefore expose some or all of the original message. IVs ensure that repeating character sequences in the input data produce varying byte sequences in the resulting cipher. It is perfectly safe to store IVs in plain text alongside our encrypted message, and we will need to do this to decrypt our message later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateIv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&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;p&gt;We never want to use the same IV with a given key, so it's best to incorporate automatic IV generation into our encryption strategy as we will do later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encrypting Data
&lt;/h3&gt;

&lt;p&gt;Now that we have all of our utilities in place, we can implement our &lt;code&gt;encrypt&lt;/code&gt; function! As mentioned above, we will need it to return both the cipher &lt;em&gt;and&lt;/em&gt; the IV so that we can decrypt the cipher later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateIv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;iv&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;h2&gt;
  
  
  Transmission and Storage
&lt;/h2&gt;

&lt;p&gt;Most practical applications of encryption involve transmission or storage of said encrypted data. When data is encrypted using SubtleCrypto, the resulting cipher and IV are represented as raw binary data buffers. This is not an ideal format for transmission or storage, so we will tackle packing and unpacking next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Packing Data
&lt;/h3&gt;

&lt;p&gt;Since data is often transmitted in JSON and stored in databases, it makes sense to pack our data in a format that is portable. We are going to convert our binary data buffers into base64-encoded strings. Depending on your use case, the base64 encoding is absolutely optional, but I find it helps make the data as portable as you could possibly need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;btoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromCharCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&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;h3&gt;
  
  
  Unpacking Data
&lt;/h3&gt;

&lt;p&gt;Once our packed data has been transmitted, stored, and later retrieved, we just need to reverse the process. We will convert our base64-encoded strings back into raw binary buffers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unpack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bufferView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bufferView&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Decryption
&lt;/h2&gt;

&lt;p&gt;We're in the home stretch! The last step of the process is decrypting our data to see those sweet, sweet secrets. As with unpacking, we just need to reverse the encryption process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decoding Data
&lt;/h3&gt;

&lt;p&gt;After decrypting, we will need to decode our resulting byte stream back into its original form. We can achieve this with the &lt;code&gt;TextDecoder&lt;/code&gt; class. This utility will be used by our &lt;code&gt;decrypt&lt;/code&gt; function later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytestream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytestream&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;h3&gt;
  
  
  Decrypting Data
&lt;/h3&gt;

&lt;p&gt;Now we just need to implement the &lt;code&gt;decrypt&lt;/code&gt; function. As mentioned before, we will need to supply not just the key but also the IV that was used in the encryption step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encoded&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;h2&gt;
  
  
  Putting it into Practice
&lt;/h2&gt;

&lt;p&gt;Let's write an app! Now that all of our utilities are built, we just need to use them. We will encrypt, pack, and transmit our data to a secure endpoint. Then, we will retrieve, unpack, and decrypt the original message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// encrypt message&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateKey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// pack and transmit&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/secure-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iv&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;span class="c1"&gt;// retrieve&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/secure-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

  &lt;span class="c1"&gt;// unpack and decrypt message&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;unpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;unpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;final&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// logs 'Hello, World!'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all there is to it! We have successfully implemented client-side encryption.&lt;/p&gt;

&lt;p&gt;As a final note, I just want to share &lt;a href="https://github.com/voraciousdev/octo"&gt;octo&lt;/a&gt;, a writing app for developers, one more time. It's free, it's open source, and I would absolutely love it if you checked it out. Thanks, everyone, and happy coding. ✌️&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>cryptography</category>
    </item>
  </channel>
</rss>
