<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Liz Lam</title>
    <description>The latest articles on DEV Community by Liz Lam (@grepliz).</description>
    <link>https://dev.to/grepliz</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%2F126543%2F64be7775-1642-4f33-b661-21e0edd4e3b4.jpeg</url>
      <title>DEV Community: Liz Lam</title>
      <link>https://dev.to/grepliz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grepliz"/>
    <language>en</language>
    <item>
      <title>The ABC's of grep - A</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Wed, 25 Oct 2023 02:22:24 +0000</pubDate>
      <link>https://dev.to/grepliz/the-abcs-of-grep-a-4no6</link>
      <guid>https://dev.to/grepliz/the-abcs-of-grep-a-4no6</guid>
      <description>&lt;p&gt;Welcome to The ABC's of grep!  &lt;/p&gt;

&lt;p&gt;Here we will explore the different flags for our beloved command and give it the accolades it deserves.  &lt;/p&gt;

&lt;p&gt;Let's start! &lt;/p&gt;

&lt;h2&gt;
  
  
  A
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;-A&lt;/code&gt; flag to show the lines &lt;em&gt;after&lt;/em&gt; the matching search term is found.&lt;/p&gt;

&lt;p&gt;Suppose you have a file named &lt;code&gt;test.txt&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sad
happy
awake
coffee
work
school
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You would search for the word "happy" like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep "happy" test.txt
happy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see the first 2 lines after happy, execute the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep -A 2 "happy" test.txt
happy
awake
coffee
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>grep</category>
    </item>
    <item>
      <title>Use jq to format p4 changes output to SQLite</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Wed, 26 Jul 2023 18:33:39 +0000</pubDate>
      <link>https://dev.to/grepliz/use-jq-to-format-p4-changes-output-to-sqlite-369l</link>
      <guid>https://dev.to/grepliz/use-jq-to-format-p4-changes-output-to-sqlite-369l</guid>
      <description>&lt;p&gt;There are so many possibilities once data is structured. In my &lt;a href="https://grepliz.netlify.app/posts/jq-p4-changes"&gt;last post&lt;/a&gt; about formating &lt;code&gt;p4 changes&lt;/code&gt; out to JSON, it occurred to me it would be fairly trivial to put this same data into a &lt;a href="https://www.sqlite.org/index.html"&gt;SQLite&lt;/a&gt; databasse.&lt;/p&gt;

&lt;p&gt;As show in the &lt;a href="https://grepliz.netlify.app/posts/jq-p4-changes"&gt;previous post&lt;/a&gt;, &lt;code&gt;p4 changes&lt;/code&gt; output can be converted to JSON data like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p4 changes | jq -R -s '[split("\n")[:-1] | map(split("\u0020")) | .[] | { "change": .[1], "author": .[5], "date": .[3], "message": .[6:length] | join(" ") }]'

[
  {
    "change": "3",
    "author": "grepliz@test-local-01",
    "date": "2023/07/20",
    "message": "'Add day1.pdf'"
  },
  {
    "change": "2",
    "author": "grepliz@test-local-01",
    "date": "2023/07/20",
    "message": "'Add crazy.psd.'"
  },
  {
    "change": "1",
    "author": "grepliz@test-local-01",
    "date": "2023/07/20",
    "message": "'Populated server with files '"
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For brevity's sake, I'm going to redirect that output to a file called &lt;code&gt;json.txt&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt; it for the rest of the examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p4 changes | jq -R -s '[split("\n")[:-1] | map(split("\u0020")) | .[] | { "change": .[1], "author": .[5], "date": .[3], "message": .[6:length] | join(" ") }]' &amp;gt; json.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CREATING THE INSERT STATEMENTS
&lt;/h2&gt;

&lt;p&gt;We can now pipe the JSON data back into another &lt;code&gt;jq&lt;/code&gt; filter to produce the &lt;code&gt;insert&lt;/code&gt; statements needed for a SQLite database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat json.txt | jq -r '.[] | "insert into changes values (\(.change), \"\(.author)\", \"\(.date)\", \(.message));"'             

insert into changes values (3, "grepliz@test-local-01", "2023/07/20", 'Add day1.pdf');
insert into changes values (2, "grepliz@test-local-01", "2023/07/20", 'Add crazy.psd.');
insert into changes values (1, "grepliz@test-local-01", "2023/07/20", 'Populated server with files ');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key to this &lt;code&gt;jq&lt;/code&gt; filter is using string interpolation via &lt;code&gt;\(exp)&lt;/code&gt; which is documented here:&lt;br&gt;
&lt;a href="https://jqlang.github.io/jq/manual/#Stringinterpolation:%5C(exp)"&gt;https://jqlang.github.io/jq/manual/#Stringinterpolation:\(exp)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because the &lt;code&gt;insert&lt;/code&gt; statement contains characters that can make the filter a bit of a bear to look at (parenthesis and quotations), let's look at a simpler example.&lt;/p&gt;

&lt;p&gt;Suppose we just wanted to create a sentence with this format:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Changelist number X was writte by Y on Z.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What would that look like?  &lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;\(exp)&lt;/code&gt; syntax, we can do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat json.txt | jq -r '.[] | "Changelist number \(.change) was written by \(.author) on \(.date)"'                 

Changelist number 3 was written by grepliz@test-local-01 on 2023/07/20
Changelist number 2 was written by grepliz@test-local-01 on 2023/07/20
Changelist number 1 was written by grepliz@test-local-01 on 2023/07/20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose we wanted to quote the author in our sentence, we would need to add quotation marks and escape them like this: &lt;code&gt;\"(.author)\"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat json.txt | jq -r '.[] | "Changelist number \(.change) was written by \"\(.author)\" on \(.date)."'

Changelist number 3 was written by "grepliz@test-local-01" on 2023/07/20.
Changelist number 2 was written by "grepliz@test-local-01" on 2023/07/20.
Changelist number 1 was written by "grepliz@test-local-01" on 2023/07/20.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting it all together, we arrive at this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat json.txt | jq -r '.[] | "insert into changes values (\(.change), \"\(.author)\", \"\(.date)\", \(.message));"'

insert into changes values (3, "grepliz@test-local-01", "2023/07/20", 'Add day1.pdf');
insert into changes values (2, "grepliz@test-local-01", "2023/07/20", 'Add crazy.psd.');
insert into changes values (1, "grepliz@test-local-01", "2023/07/20", 'Populated server with files ');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we just need to redirect this to a file called &lt;code&gt;insert.sql&lt;/code&gt; and we will import the data into a SQLite database (i.e. append &lt;code&gt;&amp;gt; insert.sql&lt;/code&gt; to the above statement).&lt;/p&gt;

&lt;h2&gt;
  
  
  SETTING UP THE SQLITE DATABASE
&lt;/h2&gt;

&lt;p&gt;Create a SQLite database like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlite3 changelists.db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a file called &lt;code&gt;changelists.db&lt;/code&gt; in your current directory and take you the a SQLite interactive prompt.&lt;/p&gt;

&lt;p&gt;Create a table with a schema that matches the values in the &lt;code&gt;insert.sql&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlite&amp;gt; CREATE TABLE changes (
   ...&amp;gt;     change INTEGER PRIMARY KEY, 
   ...&amp;gt;     author TEXT NOT NULL, 
   ...&amp;gt;     date TEXT NOT NULL, 
   ...&amp;gt;     Message TEXT NOT NULL
   ...&amp;gt; );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have an empty table called &lt;code&gt;changes&lt;/code&gt;.  If we try to &lt;code&gt;select&lt;/code&gt; from this table, we see that it is empty as indicated by the fact that nothing is returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlite&amp;gt; select * from changes;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's toggle some options to make the SQL output look a little nicer when we do populate the table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlite&amp;gt; .headers on
sqlite&amp;gt; .mode columns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now add a dummy row to see what it will look like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlite&amp;gt; insert into changes values (0, "liz", "today", "this is a changelist description.");
sqlite&amp;gt; select * from changes;
change  author  date   Message                          
------  ------  -----  ---------------------------------
0       liz     today  this is a changelist description.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, that looks pretty good.  Now let's import the &lt;code&gt;insert.sql&lt;/code&gt; file we just created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlite&amp;gt; .read insert.sql
sqlite&amp;gt; select * from changes;
change  author                 date        Message                          
------  ---------------------  ----------  ---------------------------------
0       liz                    today       this is a changelist description.
1       grepliz@test-local-01  2023/07/20  Populated server with files      
2       grepliz@test-local-01  2023/07/20  Add crazy.psd.                   
3       grepliz@test-local-01  2023/07/20  Add day1.pdf                     
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let's delete our dummy row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlite&amp;gt; delete from changes where change = 0;
sqlite&amp;gt; select * from changes;
change  author                 date        Message                     
------  ---------------------  ----------  ----------------------------
1       grepliz@test-local-01  2023/07/20  Populated server with files 
2       grepliz@test-local-01  2023/07/20  Add crazy.psd.              
3       grepliz@test-local-01  2023/07/20  Add day1.pdf                
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voila! Now we have a SQLite database with a populated &lt;code&gt;changes&lt;/code&gt; table.&lt;/p&gt;

</description>
      <category>p4</category>
    </item>
    <item>
      <title>Use jq to format p4 changes output to JSON.</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Sat, 22 Jul 2023 20:22:46 +0000</pubDate>
      <link>https://dev.to/grepliz/use-jq-to-format-p4-changes-output-to-json-4ib7</link>
      <guid>https://dev.to/grepliz/use-jq-to-format-p4-changes-output-to-json-4ib7</guid>
      <description>&lt;p&gt;&lt;em&gt;UPDATE: Just a few days after hitting publish on this blog, a few folks from the Perforce community shared a better way to output JSON data from p4 commands using the &lt;code&gt;-ztag&lt;/code&gt; and &lt;code&gt;-Mj&lt;/code&gt; flags: &lt;code&gt;p4 -ztag -Mj changes -m3 | jq -s '.'&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I recently ran across &lt;a href="https://til.simonwillison.net/jq/git-log-json"&gt;this blog&lt;/a&gt; showing how to use &lt;code&gt;jq&lt;/code&gt; to format &lt;code&gt;git log&lt;/code&gt; output to JSON.  Curious about &lt;code&gt;jq&lt;/code&gt; and wanting to try a similar thing with Perforce, I was able to modify the example pretty easily.&lt;/p&gt;

&lt;p&gt;This is what &lt;code&gt;p4 changes&lt;/code&gt; output looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ p4 changes

Change 3 on 2023/07/20 by grepliz@test-local-01 'Add day1.pdf'
Change 2 on 2023/07/20 by grepliz@test-local-01 'Add crazy.psd.'
Change 1 on 2023/07/20 by grepliz@test-local-01 'Populated server with files '
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is how you can format to JSON using &lt;code&gt;jq&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ p4 changes | jq -R -s '[split("\n")[:-1] | map(split("\u0020")) | .[] | { "change": .[1], "author": .[5], "date": .[3], "message": .[6:length] | join(" ") }]'

[
  {
    "change": "3",
    "author": "grepliz@test-local-01"
    "date": "2023/07/20",
    "message": "'Add day1.pdf'"
  },
  {
    "change": "2",
    "author": "grepliz@test-local-01",
    "date": "2023/07/20",
    "message": "'Add crazy.psd.'"
  },
  {
    "change": "1",
    "author": "grepliz@test-local-01",
    "date": "2023/07/20",
    "message": "'Populated server with files '"
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think the original blog I referred to gives a pretty good explanation of what is going on, but I find it helpful to write out what is going on for future reference (and for my future self!).&lt;/p&gt;

&lt;h1&gt;
  
  
  The input: &lt;code&gt;p4 changes&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;I know the output of &lt;code&gt;p4 changes&lt;/code&gt; is being piped into the &lt;code&gt;jq&lt;/code&gt; program and it is helpful that the output is delimited by a space character and is one line per changelist.  This output produces the columns needed for programs like &lt;code&gt;jq&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  The flags: &lt;code&gt;jq -R -s&lt;/code&gt; 
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;jq&lt;/code&gt; flags being used are nicely &lt;a href="https://jqlang.github.io/jq/manual/"&gt;documented here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;--slurp/-s:&lt;br&gt;
Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once.&lt;/p&gt;

&lt;p&gt;--raw-input/-R:&lt;br&gt;
Don't parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with --slurp, then the entire input is passed to the filter as a single long string.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The &lt;code&gt;jq&lt;/code&gt; filter
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;'[split("\n")[:-1] | map(split("\u0020")) | .[] | { "change": .[1], "author": .[5], "date": .[3], "message": .[6:length] | join(" ") }]'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is where all the magic happens. There are basically 4 sections to this filter.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;split("\n")[:-1]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This says to split on newlines. If we were to stop here, we would get an array of the changelists.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p4 changes | jq -R -s 'split("\n")[:-1]'
[
  "Change 3 on 2023/07/20 by grepliz@test-local-01 'Add day1.pdf'",
  "Change 2 on 2023/07/20 by grepliz@test-local-01 'Add crazy.psd.'",
  "Change 1 on 2023/07/20 by grepliz@test-local-01 'Populated server with files '"
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;code&gt;map(split("\u0020"))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tells the filter to map and split on the space character.&lt;br&gt;
When combined with #1 above it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p4 changes | jq -R -s 'split("\n")[:-1] | map(split("\u0020"))'

[
  [
    "Change",
    "3",
    "on",
    "2023/07/20",
    "by",
    "grepliz@test-local-01",
    "'Add",
    "day1.pdf'"
  ],
  [
    "Change",
    "2",
    "on",
    "2023/07/20",
    "by",
    "grepliz@test-local-01",
    "'Add",
    "crazy.psd.'"
  ],
  [
    "Change",
    "1",
    "on",
    "2023/07/20",
    "by",
    "grepliz@test-local-01",
    "'Populated",
    "server",
    "with",
    "files",
    "'"
  ]
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.[]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates arrays of the values such that we can iterate over it.  The following is from the documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Array/Object Value Iterator: .[]&lt;br&gt;
If you use the .[index] syntax, but omit the index entirely, it will return all of the elements of an array. Running .[] with the input [1,2,3] will produce the numbers as three separate results, rather than as a single array.&lt;/p&gt;

&lt;p&gt;You can also use this on an object, and it will return all the values of the object.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p4 changes | jq -R -s 'split("\n")[:-1] | map(split("\u0020")) | .[]'

[
  "Change",
  "3",
  "on",
  "2023/07/20",
  "by",
  "grepliz@test-local-01",
  "'Add",
  "day1.pdf'"
]
[
  "Change",
  "2",
  "on",
  "2023/07/20",
  "by",
  "grepliz@test-local-01",
  "'Add",
  "crazy.psd.'"
]
[
  "Change",
  "1",
  "on",
  "2023/07/20",
  "by",
  "grepliz@test-local-01",
  "'Populated",
  "server",
  "with",
  "files",
  "'"
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{ "change": .[1], "author": .[5], "date": .[3], "message": .[6:length] | join(" ") }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, this section gives us the desired JSON shape of each changelist and by wrapping the whole thing (the whole jq filter) with &lt;code&gt;[]&lt;/code&gt;, we get the final array.  &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Some Quick Thoughts on Seven Languages in Seven Weeks - Part 4</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Mon, 08 May 2023 04:58:33 +0000</pubDate>
      <link>https://dev.to/grepliz/some-quick-thoughts-on-seven-languages-in-seven-weeks-part-4-5fjb</link>
      <guid>https://dev.to/grepliz/some-quick-thoughts-on-seven-languages-in-seven-weeks-part-4-5fjb</guid>
      <description>&lt;p&gt;This is a continuation of my thoughts on Seven Languages in Seven Weeks by Bruce Tate.&lt;/p&gt;

&lt;p&gt;After over a year, I finally finished Seven Langugages in Seven Weeks by Bruce Tate. The last language explored is Haskell. A few quick thoughts about Haskell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Haskell is a purely functional language but feels a little too academic for me.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Language has been around since the 1980’s.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Concatenate with &lt;code&gt;++&lt;/code&gt; &lt;br&gt;
Example: &lt;code&gt;"hello" ++ "world"&lt;/code&gt; -&amp;gt; “hello world”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strings are just a list/array of characters. Example: &lt;code&gt;['a', 'b']&lt;/code&gt; -&amp;gt; ‘ab’&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Booleans are what you expect with slightly different syntax. &lt;br&gt;
Example: &lt;br&gt;
&lt;code&gt;(4+9) == 9&lt;/code&gt; -&amp;gt; True &lt;br&gt;
&lt;code&gt;(5+5) /= 10&lt;/code&gt; -&amp;gt; False&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;if&lt;/code&gt; is a function not a control structure that returns a value like any other function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Haskell is strongly typed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Functions have two parts to them, type declaration and then function declaration. &lt;br&gt;
Example:&lt;br&gt;
&lt;code&gt;double :: Integer -&amp;gt; Integer&lt;/code&gt;&lt;br&gt;
&lt;code&gt;double x = x + x&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Classes are not OOP classes. In Haskell, classes allow for polymorphism and overloading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Instances of a class are types, not date objects.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although it took more much longer than 7 weeks to get through, this has been a horizon expanding book. I think I actually understand monads now! The book also offers an interesting insight about the past and the way trends and languages evolve. Written in 2010 when Java was still very much dominating and Ruby on Rails was becoming the hot tech stack for startups, it’s interesting to see a book about just exploring different languages. Learning for learning’s sake. These days, there is also no shortage of resources to learn just about any language out there no matter how obscure. In fact there is probably a podcast, video series and Discord community for it. I may have finally finished the book, but I plan to keep the language exploration going. Not just because it’s another line item on my resume but because it’s fun!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Some Quick Thoughts on Seven Languages in Seven Weeks - Part 3</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Mon, 08 May 2023 04:53:40 +0000</pubDate>
      <link>https://dev.to/grepliz/some-quick-thoughts-on-seven-languages-in-seven-weeks-part-3-1fl9</link>
      <guid>https://dev.to/grepliz/some-quick-thoughts-on-seven-languages-in-seven-weeks-part-3-1fl9</guid>
      <description>&lt;p&gt;This is a continuation of my thoughts on Seven Languages in Seven Weeks by Bruce Tate.&lt;/p&gt;

&lt;p&gt;“Clojure and Java desperately need each other. Lisp needs the market place that the Java Virtual Machine can offer, and the Java community needs a serious update and an injection of fun.”&lt;/p&gt;

&lt;p&gt;It’s been a little while and was able to pick up this book again. I was excited to learn a bit about Clojure since I know Uncle Bob (aka Robert Martin) is a big fan. It’s interesting to read the above quote since at the time of reading this chapter in 2022 (the book was writtenin 2010), the bit about the Java community needing an update and injection of fun still feels true.&lt;/p&gt;

&lt;p&gt;Time has been at a premium for me but I wanted to jot down some quick notes on this chapter.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function args are separated by spaces.
Example: &lt;code&gt;(+ 1 1)&lt;/code&gt; evaluates to 2.&lt;/li&gt;
&lt;li&gt;Clojure uses prefix notation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;code&gt;(+ 2 2 2 2)&lt;/code&gt; evaluates to 8.&lt;br&gt;
&lt;code&gt;(- 8 1 2 )&lt;/code&gt; evaluates to 5.&lt;br&gt;
&lt;code&gt;(&amp;lt; 1 2 3 4)&lt;/code&gt; evaluates to true.&lt;br&gt;
&lt;code&gt;(&amp;lt; 1 3 2 4)&lt;/code&gt; evalutes to false.&lt;/p&gt;

&lt;p&gt;Clojure coerces types.&lt;br&gt;
Example: &lt;code&gt;(+ 3.0 5)&lt;/code&gt; evaluates to 8.0.&lt;/p&gt;

&lt;p&gt;Use ‘str’ to concatenate strings.&lt;/p&gt;

&lt;p&gt;Example: &lt;code&gt;(str "name, " "date, " "age.")&lt;/code&gt; evaluates to “name, date, age.”&lt;/p&gt;

&lt;p&gt;This is how you do an &lt;code&gt;if&lt;/code&gt;:&lt;br&gt;
&lt;code&gt;(if true (println "it's true!"))&lt;/code&gt; prints “it’s true!“.&lt;/p&gt;

&lt;p&gt;If you want an &lt;code&gt;else&lt;/code&gt; add a third argument:&lt;br&gt;
&lt;code&gt;(if true (println "it's true!") (println "false))&lt;/code&gt; still prints “it’s true!“.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0 and "" are true, nil is not true. This is weird!&lt;/li&gt;
&lt;li&gt;Use keyword &lt;code&gt;def&lt;/code&gt; to define variables.&lt;/li&gt;
&lt;li&gt;Use keyword &lt;code&gt;defn&lt;/code&gt; to define functions.&lt;/li&gt;
&lt;li&gt;The simplest form of a function is: &lt;code&gt;(defn [params] body)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an example of a “Hello World” program in Clojure using functions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(defn hello [name] (str "Hello, " name))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Invoke this with: &lt;code&gt;(hello "liz")&lt;/code&gt; and the output will be “Hello, liz”.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Some Quick Thoughts on Seven Languages in Seven Weeks - Part 2</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Sun, 19 Dec 2021 21:40:11 +0000</pubDate>
      <link>https://dev.to/grepliz/some-quick-thoughts-on-seven-languages-in-seven-weeks-part-2-3an4</link>
      <guid>https://dev.to/grepliz/some-quick-thoughts-on-seven-languages-in-seven-weeks-part-2-3an4</guid>
      <description>&lt;p&gt;This is a continuation of my thoughts on Seven Languages in Seven Weeks by Bruce Tate.&lt;/p&gt;

&lt;p&gt;The Scala chapter of the book so far seems the most familiar to me. I have a pretty good understanding of Java, so I naturally leaned into this language quite a bit more than the others. This is the first time I saw traits outside of a Rust context (another language I’ve been trying to learn on the side). Traits are basically interfaces with implementation.&lt;/p&gt;

&lt;p&gt;There are distinct and explicit ways to declare mutable and immutable variables i.e. use val for immutable values and var for mutable variables.&lt;/p&gt;

&lt;p&gt;A similar approach is used for static classes. Instead of adding the static keyword in front of the class declaration (like in Java), Scala uses the keyword object.&lt;/p&gt;

&lt;p&gt;One interesting bit in Scala is that XML is valid syntax. This reminded me a lot of React and JSX.&lt;/p&gt;

&lt;p&gt;The pattern matching with conditions look like a really powerful tool over your basic switch/case statements.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def factorial(n: Int): Int = n match {
    case 0 =&amp;gt; 1
    case x if x &amp;gt; 0 =&amp;gt; factorial(n - 1) * n
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The author’s conclusion for Scala is mixed, but I like how you are able to start with object oriented programs and ease your way into functional paradigms. Perhaps this allows too much of an escape hatch for a functional programmer’s taste?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The next chapter is on Erlang.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few of my notes:&lt;/p&gt;

&lt;p&gt;Statements end in period.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no type coercion. Example: 1 + "2" does not work.&lt;/li&gt;
&lt;li&gt;Variables begin with capital letter and immutable.&lt;/li&gt;
&lt;li&gt;Functions use fun keyword.&lt;/li&gt;
&lt;li&gt;There is a prolog-based syntax.&lt;/li&gt;
&lt;li&gt;Use the keyword spawn to spawn a process.&lt;/li&gt;
&lt;li&gt;Send messages to threads with Pid ! "message".&lt;/li&gt;
&lt;li&gt;Interprocess communication is REALLY easy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I enjoyed reading about Erlang and doing some of the exercises but I found the syntax to be a little awkward. My first impression is it is not something I would want to work in on a daily basis. The author seemed to really like Erlang which makes me want to give it another try.&lt;/p&gt;

&lt;p&gt;So far, Scala seems the most promising in terms of professional development. I’ve seen a few companies that use Scala though it is not widespread in the industry. I am looking forward to finishing up the book with the next 2 chapters and see where it takes me.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Some Quick Thoughts on Seven Languages in Seven Weeks - Part 1</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Sun, 19 Dec 2021 21:34:04 +0000</pubDate>
      <link>https://dev.to/grepliz/some-quick-thoughts-on-seven-languages-in-seven-weeks-part-1-3p02</link>
      <guid>https://dev.to/grepliz/some-quick-thoughts-on-seven-languages-in-seven-weeks-part-1-3p02</guid>
      <description>&lt;p&gt;I recently discovered the &lt;a href="https://corecursive.com/"&gt;Corecursive&lt;/a&gt; Podcast and love it! In particular, I really enjoyed &lt;a href="https://corecursive.com/051-bruce-tate-language-learning/"&gt;this interview&lt;/a&gt; with Bruce Tate, the author of Seven Languages in Seven Weeks. The book surveys 7 different languages: Ruby, Io, Prolog, Scala, Erlang, Clojure and Haskell. I only had familiarity with Ruby, so I decided to pick it up. I have completed 3 of the 7 languages and I thought I would take some time to jot down my thoughts about the book so far.&lt;/p&gt;

&lt;p&gt;Although the book is slightly dated (2011), it reads really well and is very digestible. I’ve done a couple of projects in Ruby in the past, but found that the chapter opened my eyes to why Ruby was designed the way it was. For example, it really was designed with the developer’s experience in mind as oppose to performance. All the code samples work (though some of the output might be slightly different) and it’s a great introduction to this language.&lt;/p&gt;

&lt;p&gt;I found this to be less true with the Io chapter. Most of the trivial code samples worked, but unfortunately, none of the ones that involved http request did. This was a bit disappointing. I use JavaScript in my day to day work. Io is a prototypal language and I was hoping it would help me understand JavaScript (also a prototypal language) more. I believe it did accomplish this.&lt;/p&gt;

&lt;p&gt;The Prolog chapter was very interesting. The code almost seemed like axioms from which you derived your proofs. The language is rule based and is very different from how I think of programming. This chapter probably stretched my brain the most, but is so far the most disappointing in terms of getting the code samples to work.&lt;/p&gt;

&lt;p&gt;Overall, I still enjoyed going through these first 3 languages and look forward to the remaining 4.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Setting up Fathom Lite in a Docker Container</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Mon, 16 Nov 2020 07:21:58 +0000</pubDate>
      <link>https://dev.to/grepliz/setting-up-fathom-lite-in-a-docker-container-3ifg</link>
      <guid>https://dev.to/grepliz/setting-up-fathom-lite-in-a-docker-container-3ifg</guid>
      <description>&lt;p&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@markuswinkler?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Markus Winkler&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/charts?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;I have recently been playing around with &lt;a href="https://usefathom.com/"&gt;Fathom&lt;/a&gt; to gather visitor stats on my websites.  I really like its promise of being a "simple, light-weight privacy-first alternative to Google Analytic".&lt;/p&gt;

&lt;p&gt;It was also appealing that they offer a &lt;a href="https://github.com/usefathom/fathom"&gt;lite version&lt;/a&gt; for those who wish to self host.  Seeing they provided a pre-built Docker image made it a no-brainer to want to give it a spin. It took a bit of configuration to get everything working and I've documented the steps here in case it's helpful for anyone else (AKA me in 6 months).&lt;/p&gt;

&lt;p&gt;So before diving into the details, this is the overall picture of the setup:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YJElcyyp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a3i5ybpwhsj57hxc0oyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YJElcyyp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a3i5ybpwhsj57hxc0oyg.png" alt="diagram" width="400" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Fathom server is running on port 7070.
&lt;/li&gt;
&lt;li&gt;The nginx server is running on port 8080.&lt;/li&gt;
&lt;li&gt;The container's port 8080 is bound to the host's port 9090.

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On my host machine as root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /opt/fathom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;fathom.conf&lt;/code&gt; file in &lt;code&gt;/opt/fathom&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    server_name your.domain.name;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:7070; 
    }  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will be mapping above &lt;code&gt;fathom.conf&lt;/code&gt; file to a directory in the container to be used by nginx.&lt;/p&gt;

&lt;p&gt;Create an &lt;code&gt;.env&lt;/code&gt; file (also in /opt/fathom):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FATHOM_SERVER_ADDR=":7070"
FATHOM_DATABASE_NAME="/app/config/fathom.db"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;.env&lt;/code&gt; file will start the fathom server on port 7070 and place the sqlite db file in &lt;code&gt;/app/config&lt;/code&gt; in the Docker container.&lt;/p&gt;

&lt;p&gt;Ok, let's start our Docker container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker run -d -v /opt/fathom:/app/config -p 9090:8080 -p 80:80 --name fathom usefathom/fathom:latest ./fathom --config /app/config/.env server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Woah!! Woah!! Woah!! I know what you're thinking.  What the heck is going on here??!!!&lt;/p&gt;

&lt;p&gt;Let's break down in this docker command:    &lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo docker run -d&lt;/code&gt; - This runs the Docker container.    &lt;/p&gt;

&lt;p&gt;&lt;code&gt;-v /opt/fathom:/app/config&lt;/code&gt; - This maps a volume from our host machine (&lt;code&gt;/opt/fathom&lt;/code&gt;) to a directory in our Docker container (&lt;code&gt;/app/config&lt;/code&gt;).    &lt;/p&gt;

&lt;p&gt;&lt;code&gt;-p 9090:8080 -p 80:80&lt;/code&gt; - This exposes the container's port 8080 as the host's port 9090.  The second argument exposes port 80 as itself.  This will be needed for generating a Let's Encrypt SSL certificate.    &lt;/p&gt;

&lt;p&gt;&lt;code&gt;--name fathom&lt;/code&gt; - This names the container so we can easily reference it.    &lt;/p&gt;

&lt;p&gt;&lt;code&gt;usefathom/fathom:latest&lt;/code&gt; - This pulls down the pre-built Docker container provided by Fathom.    &lt;/p&gt;

&lt;p&gt;&lt;code&gt;./fathom --config /app/config/.env server&lt;/code&gt; - This starts the fathom server using the &lt;code&gt;.env&lt;/code&gt; file we just created and mapped into the container.    &lt;/p&gt;

&lt;p&gt;Now that we have created a running Docker container, we can access it with an interactive bash shell with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker exec -it fathom /bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: I didn't give docker the permissions needed to run it without &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once in the container, you should be in the &lt;code&gt;/app&lt;/code&gt; directory.    &lt;/p&gt;

&lt;p&gt;Let's create a fathom user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fathom --config /app/config/.env user add --email="your@email.com" --password="strong-password"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install nginx, certbot and the certbot/nginx plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apk add certbot certbot-nginx nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: The pre-built Docker container is based on the &lt;a href="https://alpinelinux.org/"&gt;Alpine Linux&lt;/a&gt; distribution. Coincidentally, the host machine I'm using is a &lt;a href="https://www.linode.com"&gt;Linode&lt;/a&gt; that is also Alpine Linux.&lt;/p&gt;

&lt;p&gt;Symlink the previously created &lt;code&gt;fathom.conf&lt;/code&gt; so nginx can use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ln -s /app/config/fathom.conf /etc/nginx/conf.d/fathom.conf    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create certs from Let's Encrypt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /run/nginx
certbot --nginx -d your-site.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There will be a series of questions you will need to answer and once done there be updates to your conf file.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;/etc/nginx/conf.d/fathom.conf&lt;/code&gt; and find the updated section.  It should looks something like this (excerpt):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    listen 80; # managed by Certbot

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/yoursite.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/yoursite.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


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

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;443&lt;/code&gt; to &lt;code&gt;8080&lt;/code&gt;, the final content should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    server_name your.domain.name;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:7070; 
    }  

    listen 80; # managed by Certbot

    listen 8080 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/yoursite.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/yoursite.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nginx -t
nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whew! That was a lot! Now go to &lt;code&gt;https://yourdomain.com:9090&lt;/code&gt; to see your freshly installed Fathom Lite dashboard!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>fathom</category>
      <category>setup</category>
      <category>linux</category>
    </item>
    <item>
      <title>A Gentle Introduction to the Git Command Line</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Wed, 07 Oct 2020 19:47:42 +0000</pubDate>
      <link>https://dev.to/grepliz/a-gentle-introduction-to-the-git-command-line-2f1d</link>
      <guid>https://dev.to/grepliz/a-gentle-introduction-to-the-git-command-line-2f1d</guid>
      <description>&lt;p&gt;Git is a version control system written by Linus Torvalds in 2005. It was created specifically to manage the Linux Kernel Project. One could say it was written by Linux Kernel Developers for Linux Kernel Developers. As a result, the initial environment for working with git is the command line. &lt;/p&gt;

&lt;p&gt;Now, if you're not familiar with the command line (like a Linux Kernel Developer), this can feel scary.  With so many GUI tools out there, you may feel it's not even necessary to learn.  I want to suggest that knowing how the git GUIs work under the hood is super helpful as a developer.  With some diligence and working through this tutorial, you'll be a git command line power user in no time...well with some time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: I leave out some of the git output for clarity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a new git repository
&lt;/h2&gt;

&lt;p&gt;Open a terminal and run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ mkdir project 
    $ cd project
    $ git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What did we just do? &lt;br&gt;
We just created an empty git repository.&lt;/p&gt;

&lt;p&gt;Let take a look at the state of the git workspace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git status
    On branch master

    No commits yet

    nothing to commit (create/copy files and use "git add" to track)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add a file to our working directory
&lt;/h2&gt;

&lt;p&gt;Type the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ echo ‘hello world’ &amp;gt; hello.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take a look at the status again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git status
    On branch master

    No commits yet

    Untracked files:
    (use "git add &amp;lt;file&amp;gt;..." to include in what will be committed)

      hello.txt

    nothing added to commit but untracked files present (use "git add" to track)

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

&lt;/div&gt;



&lt;p&gt;The status gives us a clue on what we need to do next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git add .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git knows we have a new file with the &lt;em&gt;intention&lt;/em&gt; to add it to the repository but we have not committed it yet. This is often a point of confusion for new users.  I think of &lt;code&gt;git add&lt;/code&gt; like an engagement ring.  It's a promise to commit, but we're not there yet.&lt;/p&gt;

&lt;p&gt;Let's take a look at the status again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git status
    On branch master

    No commits yet

    Changes to be committed:
      (use "git rm --cached &amp;lt;file&amp;gt;..." to unstage)

        new file:   hello.txt

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time to commit
&lt;/h2&gt;

&lt;p&gt;Type the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git commit -m “Commit first file to the repo”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! We have made our first commit to the master branch!&lt;br&gt;
How do we know what branch we are currently on?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     $ git branch
     * master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a new branch
&lt;/h2&gt;

&lt;p&gt;Type the following in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git checkout -b dev_llam
      Switched to a new branch 'dev_llam'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new branch and switch to that branch.&lt;br&gt;&lt;br&gt;
We should be able to see both branches now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git branch
    * dev_llam
      master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may be thinking, "Wait??!! I didn't &lt;code&gt;cd&lt;/code&gt; into a new directory. How did I switch to a new branch?".&lt;br&gt;&lt;br&gt;
This can bit a little bit confusing for those coming from other version control systems.  &lt;/p&gt;

&lt;p&gt;I think of it like someone pulled the rug out from under me and replaced it with a new one without me ever having to get up. You are physically sitting in the same directory in the filesystem, but the branch has been changed from underneath you.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let’s make a change on our new branch.
&lt;/h2&gt;

&lt;p&gt;Edit hello.txt by adding a 2nd line saying who you are.  (Example: “I am Liz.”)&lt;br&gt;
If you check the status, you will see git knows we made changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ echo 'I am Liz.' &amp;gt;&amp;gt; hello.txt
    $ cat hello.txt
      hello world
      I am Liz.
    $ git status
    On branch dev_llam
    Changes not staged for commit:
      (use "git add &amp;lt;file&amp;gt;..." to update what will be committed)
      (use "git checkout -- &amp;lt;file&amp;gt;..." to discard changes in working directory)

        modified:   hello.txt

    no changes added to commit (use "git add" and/or "git commit -a")

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

&lt;/div&gt;



&lt;p&gt;We want to add our changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git add .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we want to commit them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git commit -m “Saying who I am”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let's take a look at our history so far.
&lt;/h2&gt;

&lt;p&gt;Type in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git log --oneline
      187c6fa (HEAD -&amp;gt; dev_llam) Saying who I am
      deccda5 (master) Commit first file to the repo.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have two commits in our history in our dev branch.&lt;/p&gt;

&lt;p&gt;NOTE: The seemingly random characters in front of our commit message is called a commit SHA. This commit SHA includes information about the author and date and will be unique to you. If you are following along on your terminal, don't worry if the output looks a little different.&lt;/p&gt;

&lt;p&gt;Let’s check on master:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git checkout master
    $ git log --oneline
      deccda5 (HEAD -&amp;gt; master) Commit first file to the repo.
    $ cat hello.txt
      hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time to merge!
&lt;/h2&gt;

&lt;p&gt;We want to merge our changes from dev to master.&lt;br&gt;
Remember, the target branch is always the branch you are on.  Use &lt;code&gt;git branch&lt;/code&gt; if you are not sure where you are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git merge dev_llam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we should see that master has the same changes as our dev branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git log --oneline
      187c6fa (HEAD -&amp;gt; master, dev_llam) Saying who I am
      deccda5 Commit first file to the repo.
    $ cat hello.txt
      hello world
      I am Liz.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What about cloning?
&lt;/h2&gt;

&lt;p&gt;Open another terminal window and clone the repo we just created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git clone /path/to/git/project project2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an exact copy of what we had in the original project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ cd project2
    $ git log --oneline 
      187c6fa (HEAD -&amp;gt; master, dev_llam) Saying who I am
      deccda5 Commit first file to the repo.
    $ cat hello.txt 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What about pulling?
&lt;/h2&gt;

&lt;p&gt;To keep our repo updated, we need to pull from the original/remote.&lt;/p&gt;

&lt;p&gt;Go to the &lt;em&gt;first&lt;/em&gt; terminal window with the original project open and make a change and commit it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   $ echo 'I love coffee!' &amp;gt;&amp;gt; hello.txt
   $ git add .
   $ git commit -m "Add line about my love of caffeine."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go back to the &lt;em&gt;second&lt;/em&gt; terminal window with project2 open and check its status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git status
    On branch master
    Your branch is up to date with 'origin/master'.

    nothing to commit, working tree clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's interesting.  Didn't we just make a change in the original project?!? Our cloned project (project2) does not know it is out of date with the original.&lt;br&gt;
That is because we need to &lt;em&gt;fetch&lt;/em&gt; the changes (note: fetching is different from pulling).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git fetch origin master
    $ git status
      On branch master
      Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
        (use "git pull" to update your local branch)

      nothing to commit, working tree clean

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

&lt;/div&gt;



&lt;p&gt;Great! Now our repo is updated...but our working directory is not.&lt;br&gt;
This is because fetching only updates our local repo, while pulling will fetch and merge it into our local workspace.&lt;br&gt;
As the git output suggest, let's pull!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ git pull
    $ git log --oneline
      fb58b27 (HEAD -&amp;gt; master, origin/master, origin/HEAD) Add line about my love of caffeine.
      187c6fa (origin/dev_llam) Saying who I am
      deccda5 Commit first file to the repo.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yay! We’re done! We have successfully pulled the coffee change from a remote repo.&lt;/p&gt;

&lt;p&gt;If you've made it this far, you are a trooper! Congratulations!&lt;/p&gt;

&lt;p&gt;You now know how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new git repository&lt;/li&gt;
&lt;li&gt;Add and commit files to a repo&lt;/li&gt;
&lt;li&gt;Create and merge branches&lt;/li&gt;
&lt;li&gt;Clone a repository&lt;/li&gt;
&lt;li&gt;Fetch and pull changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully this was an insightful glimpse of the things possible with &lt;code&gt;git&lt;/code&gt; and the command line at your finger tips.&lt;/p&gt;

</description>
      <category>git</category>
      <category>commandline</category>
      <category>versioncontrol</category>
    </item>
    <item>
      <title>How to use the fetch API with and without async/await</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Fri, 21 Aug 2020 16:12:05 +0000</pubDate>
      <link>https://dev.to/grepliz/how-to-use-the-fetch-api-with-and-without-async-await-494e</link>
      <guid>https://dev.to/grepliz/how-to-use-the-fetch-api-with-and-without-async-await-494e</guid>
      <description>&lt;p&gt;Sometimes the best way to explain something to someone is to just show them an example.  This was the case when a couple of coworkers had some confusion around using &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;After verbally explaining, I opened up my web console and gave them a quick example.  This seemed to clarify their understanding.  &lt;/p&gt;

&lt;p&gt;I will share the example here in case it's helpful to anyone else. &lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;SIDE NOTE: This also made me think about how just playing around in the web console is a great way to learn of JavaScript.  It's also an easy way to share knowledge because anyone can just copy what you have into their own web console.&lt;/em&gt; &lt;/p&gt;

</description>
      <category>fetch</category>
      <category>async</category>
      <category>await</category>
    </item>
    <item>
      <title>Learning With Video Games</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Mon, 03 Aug 2020 17:31:15 +0000</pubDate>
      <link>https://dev.to/grepliz/learning-with-video-games-4ip3</link>
      <guid>https://dev.to/grepliz/learning-with-video-games-4ip3</guid>
      <description>&lt;p&gt;I just recently finished &lt;a href="https://serviceworkies.com/"&gt;Service Workies&lt;/a&gt; by &lt;a href="https://twitter.com/geddski"&gt;Dave Geddes&lt;/a&gt;.  It is a video game style tutorial that teaches the player how to use Service Workers.  It's not simply the gamification of learning, but an actual game with engaging graphics, music and story.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--83rosF38--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ykkblygwuprgv4di7rk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--83rosF38--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ykkblygwuprgv4di7rk7.png" alt="Service Workies Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The concept is based on the idea that expertise is attained when you repeatedly do something.  Video games are a good example of this and he uses those techniques to solidify concepts and drill in practice.  Although I'm not really a gamer, I find this style of tutorials to be really creative and fun!&lt;/p&gt;

&lt;p&gt;Dave Geddes also have "courses" on &lt;a href="https://flexboxzombies.com/p/flexbox-zombies"&gt;Flexbox&lt;/a&gt; and &lt;a href="https://gridcritters.com/"&gt;CSS Grid&lt;/a&gt;.  Both Flexbox Zombies and Service Workies are free to play where Grid Critters cost about $99 at the time of writing this.&lt;/p&gt;

&lt;p&gt;After a quick look around, I've found a few other games in the same vein:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://flexboxfroggy.com/"&gt;Flexbox Froggie&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cssgridgarden.com/"&gt;Grid Garden&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flukeout.github.io/"&gt;CSS Diner&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vim-adventures.com/"&gt;VIM Adventures&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's your experience with these type of games?  Do you think they are an effective way of learning? &lt;/p&gt;

</description>
      <category>games</category>
      <category>learning</category>
      <category>tutorials</category>
    </item>
    <item>
      <title>Create Your Own Quote API with Netlify Functions - Part 3</title>
      <dc:creator>Liz Lam</dc:creator>
      <pubDate>Tue, 07 Jul 2020 22:23:06 +0000</pubDate>
      <link>https://dev.to/grepliz/create-your-own-quote-api-with-netlify-functions-part-3-36be</link>
      <guid>https://dev.to/grepliz/create-your-own-quote-api-with-netlify-functions-part-3-36be</guid>
      <description>&lt;p&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@jontyson?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Jon Tyson&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/quotes?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This is a 3 part exercise on how to create and use your own quote API with Netlify functions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Create Your Own Quote API with Netlify Functions (3 Part Series)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/grepliz/create-your-own-quote-api-with-netlify-functions-part-1-3f4o"&gt;Part 1: Get a Netlify function up and running locally.&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/grepliz/create-your-own-quote-api-with-netlify-functions-part-2-5fpm"&gt;Part 2: Deploy the function to the Netlify platform.&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/grepliz/create-your-own-quote-api-with-netlify-functions-part-3-36be"&gt;Part 3: Tie it all together by using the deployed API to display quotes in a React app.&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you've been following along, you should now have a working public API that returns a random quote.  In this last part of the series, we will use that API and display the quote in our React app.    &lt;/p&gt;

&lt;p&gt;Go into the &lt;code&gt;src&lt;/code&gt; directory and replace &lt;code&gt;App.js&lt;/code&gt; with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import './App.css';

function App() {
  const url = '/.netlify/functions/quotes';
  const [quote, setQuote] = useState();

  useEffect(() =&amp;gt; {
    const getQuote = async () =&amp;gt; {
      const response = await fetch(url);
      const data = await response.json();
      setQuote(data.quote);
      return data;
    }
    getQuote();
  }, []);

  return (
    &amp;lt;div className="App"&amp;gt;
      &amp;lt;header className="App-header"&amp;gt;
        &amp;lt;p&amp;gt;
          {quote}
        &amp;lt;/p&amp;gt;
      &amp;lt;/header&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are a React developer, this should feel pretty familiar to you.  If not, this is essentially a &lt;a href="https://reactjs.org/docs/components-and-props.html"&gt;functional component&lt;/a&gt; that uses &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;fetch&lt;/a&gt; to call our quotes api. &lt;br&gt;
 The component returns the &lt;a href="https://reactjs.org/docs/introducing-jsx.html"&gt;JSX&lt;/a&gt; portion which displays the quote. &lt;/p&gt;

&lt;p&gt;Start your dev environment if you haven't already with &lt;code&gt;netlify dev&lt;/code&gt;.  Open up a browser and go to &lt;code&gt;http://localhost:8888&lt;/code&gt;.  You should see a screen something like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hU564Piz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yde9uioup8xbh585d75z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hU564Piz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yde9uioup8xbh585d75z.png" alt="Quote being displayed" width="486" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Commit and push these new changes to GitHub.  This should trigger a redeploy on Netlify.  Once the redeploy is complete, you should be able to navigate to your public url and see the same thing. &lt;/p&gt;

&lt;p&gt;Congratulations! You did it! You've created a quotes API, deployed it to Netlify and used it in a React app. Hopefully this example serves as a simple foundation on how to build API's with the power of serverless technologies.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
