<?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: Anthony Slater</title>
    <description>The latest articles on Forem by Anthony Slater (@slaterslater).</description>
    <link>https://forem.com/slaterslater</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%2F469125%2F61a4752c-2f60-48ad-a2c4-8ca076689c59.jpg</url>
      <title>Forem: Anthony Slater</title>
      <link>https://forem.com/slaterslater</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/slaterslater"/>
    <language>en</language>
    <item>
      <title>Setting up MongoDB</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Mon, 01 Feb 2021 22:03:25 +0000</pubDate>
      <link>https://forem.com/slaterslater/setting-up-mongodb-bc4</link>
      <guid>https://forem.com/slaterslater/setting-up-mongodb-bc4</guid>
      <description>&lt;p&gt;It's been a while since I fired up MongoDB, so I opened up a terminal and typed &lt;strong&gt;mongo&lt;/strong&gt; thinking everything would be fine. Instead &lt;em&gt;macOS Catalina&lt;/em&gt; gave me some grief about the developer being unrecognized...&lt;/p&gt;

&lt;p&gt;The solution: &lt;strong&gt;Homebrew&lt;/strong&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="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; brew tap mongodb/brew
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;mongodb-community
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next I added the &lt;code&gt;/data/db&lt;/code&gt; folder in &lt;code&gt;System/Volumes/Data&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="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /System/Volumes/Data/data/db
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-un&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; /System/Volumes/Data/data/db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command creates the folders and the second changes its permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;Here are the commands to start and stop MongoDB as a background service:&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="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; brew services run mongodb-community
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; brew services stop mongodb-community
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unless you love typing things, edit your &lt;code&gt;.bash_profile&lt;/code&gt; and set some aliases for the above commands.&lt;/p&gt;

&lt;p&gt;Once MongoDB is running, you can type &lt;strong&gt;mongo&lt;/strong&gt; in the terminal to start the mongo shell or run a Node.js program.&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;var&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to the db&lt;/span&gt;
&lt;span class="p"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb://localhost:27017&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;useUnifiedTopology&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;listDatabases&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&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;



</description>
      <category>mongodb</category>
      <category>node</category>
    </item>
    <item>
      <title>Gustavo looks through a Telescope</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Mon, 16 Nov 2020 16:00:22 +0000</pubDate>
      <link>https://forem.com/slaterslater/gustavo-looks-through-a-telescope-27gc</link>
      <guid>https://forem.com/slaterslater/gustavo-looks-through-a-telescope-27gc</guid>
      <description>&lt;p&gt;I'm going to be integrating &lt;a href="https://github.com/slaterslater/gustavo"&gt;Gustavo&lt;/a&gt;, a HTTP status checker, with Telescope &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Seneca-CDOT"&gt;
        Seneca-CDOT
      &lt;/a&gt; / &lt;a href="https://github.com/Seneca-CDOT/telescope"&gt;
        telescope
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A tool for tracking blogs in orbit around Seneca's open source involvement
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 Telescope uses many technologies, so it's best to get started by reading through and following all the steps in its &lt;a href="https://github.com/Seneca-CDOT/telescope/blob/master/docs/environment-setup.md"&gt;Environment Setup Documentation&lt;/a&gt;.&lt;br&gt;
Since I already had &lt;strong&gt;npm&lt;/strong&gt; installed, I used &lt;code&gt;brew&lt;/code&gt; to install the two other necessary technologies: &lt;strong&gt;redis&lt;/strong&gt; and &lt;strong&gt;elasticsearch&lt;/strong&gt;&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; brew install npm
&amp;gt;&amp;gt;&amp;gt; brew install redis
&amp;gt;&amp;gt;&amp;gt; brew tap elastic/tap
&amp;gt;&amp;gt;&amp;gt; brew install elastic/tap/elasticsearch-full
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now you can open three terminal windows to get your local Telescope server running:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; redis-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; elasticsearch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; npm start&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If everything is working correctly, opening a browser to &lt;a href="http://localhost:3000/posts"&gt;http://localhost:3000/posts&lt;/a&gt; should display an array of 10 json objects.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[{"id":"979c6d3eb5","url":"/posts/979c6d3eb5"},
{"id":"f1f56132fd","url":"/posts/f1f56132fd"},
{"id":"6413f59523","url":"/posts/6413f59523"},
{"id":"a0d10ce9e7","url":"/posts/a0d10ce9e7"},
{"id":"476491f37d","url":"/posts/476491f37d"},
{"id":"d5eed3b8ec","url":"/posts/d5eed3b8ec"},
{"id":"b1f2991c27","url":"/posts/b1f2991c27"},
{"id":"6fc08da083","url":"/posts/6fc08da083"},
{"id":"1aca420d0f","url":"/posts/1aca420d0f"},
{"id":"6ba1ae431a","url":"/posts/6ba1ae431a"}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next I wanted to update &lt;a href="https://github.com/slaterslater/gustavo"&gt;Gustavo&lt;/a&gt; to check the HTTP status of the above urls. Gustavo works by searching through a file for any string that starts with &lt;strong&gt;HTTP://&lt;/strong&gt; or &lt;strong&gt;HTTPS://&lt;/strong&gt; and creates a list of all matches. This list is then processed. I knew the program would work, if I could produce a list of fully formed URLs from the above json.&lt;/p&gt;

&lt;p&gt;I updated &lt;code&gt;args.py&lt;/code&gt; to handle additional flags &lt;code&gt;-t&lt;/code&gt; or &lt;code&gt;--telescope&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'-f'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'--file'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'store'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'source'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'location of source file'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'-t'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'--telescope'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'store_const'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'source'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'TELESCOPE'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'check recent posts indexed by Telescope'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead of specifying a file path, using the &lt;code&gt;-t&lt;/code&gt; or &lt;code&gt;--telescope&lt;/code&gt; flags will save a string &lt;em&gt;TELESCOPE&lt;/em&gt; to the source variable. The program runs normally until the &lt;code&gt;get_list()&lt;/code&gt; function is called. At this point, if the value of the source variable equals &lt;em&gt;TELESCOPE&lt;/em&gt;, the following code executes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'http://localhost:3000/posts'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/posts/[a-zA-Z0-9]{10}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'http://localhost:3000'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;What does it do?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First a query is made to the server's REST API for posts.&lt;/li&gt;
&lt;li&gt;Next a list of URLs if created by using a regular expression to find all unique 10-digit IDs.&lt;/li&gt;
&lt;li&gt;Using a list comprehension, the domain is appended to each URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now heading back to the terminal, running the command&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; python gus.py -t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;produces the following output:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[GOOD] [200] http://localhost:3000/posts/78e5ab8438
[GOOD] [200] http://localhost:3000/posts/2da60bf766
[GOOD] [200] http://localhost:3000/posts/4a8a76df4a
[GOOD] [200] http://localhost:3000/posts/e5f703c004
[GOOD] [200] http://localhost:3000/posts/168346fd63
[GOOD] [200] http://localhost:3000/posts/db7e046128
[GOOD] [200] http://localhost:3000/posts/f87957048e
[GOOD] [200] http://localhost:3000/posts/35b33ca432
[GOOD] [200] http://localhost:3000/posts/3555e6f683
[GOOD] [200] http://localhost:3000/posts/868b94d523
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The complete summary of changes I made can be seen below: &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



</description>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>Concurrent Futures and Showing Progress </title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Fri, 13 Nov 2020 23:32:11 +0000</pubDate>
      <link>https://forem.com/slaterslater/concurrent-futures-and-showing-progress-56mc</link>
      <guid>https://forem.com/slaterslater/concurrent-futures-and-showing-progress-56mc</guid>
      <description>&lt;p&gt;I made a few updates to Gustavo: one major; one minor; and some refactoring. &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/slaterslater"&gt;
        slaterslater
      &lt;/a&gt; / &lt;a href="https://github.com/slaterslater/gustavo"&gt;
        gustavo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Print a colourized report of all HTTP urls in a file
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 The main issue I wanted to address was performance. I found that Gus took far too long to make HTTP requests compared to other similar tools. I didn't implement a time object to get precise measurements, but it felt like a list of 800 URLs could take anywhere from 5-8 minutes to process. Gus would check a list of URLs one after the other and I wanted them checked (practically) all at once.

&lt;p&gt;This project is one of my first times working with Python and I was really impressed with how easy it was to implement threading. After importing &lt;code&gt;concurrent.futures&lt;/code&gt; I found that using a list comprehension really made for an elegant solution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urlist&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 it took to exponentially improve the performance. The first line creates a ThreadPoolExecutor which creates, starts and joins threads. The second line is a list comprehension which creates a list of threads executing &lt;code&gt;get_status()&lt;/code&gt; for each url in the list.&lt;/p&gt;

&lt;p&gt;During the processing, the iterative version of Gus would update the console with a print statement ie: &lt;em&gt;"Checking URL 123 of 456."&lt;/em&gt; This didn't really make much sense in the threaded version of Gus as it would print &lt;em&gt;"Checking URL 456 of 456."&lt;/em&gt; in a fraction of a second and then waits for the &lt;code&gt;get_status()&lt;/code&gt; functions to complete. I thought a progress bar would be a nice touch. &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/verigak"&gt;
        verigak
      &lt;/a&gt; / &lt;a href="https://github.com/verigak/progress"&gt;
        progress
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Easy to use progress bars for Python
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;In the end I used a Spinner which advances the animation each time a thread completes. I noticed that once the Spinner finishes, it would leave itself on the console line and the program would continue. I read through the source code and found that the Spinner class had a &lt;code&gt;writeln()&lt;/code&gt; which takes a string. Thank you very much Stack Overflow for answering the question: &lt;a href="https://stackoverflow.com/questions/11474391/is-there-go-up-line-character-opposite-of-n"&gt;Is there go up line character?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The updated function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wanted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;processed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rtf_format&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;  &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'rtf'&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json_format&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;  &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'json'&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;std_format&lt;/span&gt;
  &lt;span class="n"&gt;spinner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Spinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Checking URLs '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urlist&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_completed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'desc'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;wanted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;processed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formatted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="n"&gt;spinner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
  &lt;span class="n"&gt;spinner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[F"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# move cursor to the beginning of previous line
&lt;/span&gt;  &lt;span class="n"&gt;spinner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;processed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remaining changes I made were to refactor &lt;strong&gt;gus.py&lt;/strong&gt; into smaller related files:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gus.py&lt;/td&gt;
&lt;td&gt;creates a Gus class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;const.py&lt;/td&gt;
&lt;td&gt;any constant values needed for processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;args.py&lt;/td&gt;
&lt;td&gt;handles all command line argument parsing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;urls.py&lt;/td&gt;
&lt;td&gt;all HTTP checking functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;out.py&lt;/td&gt;
&lt;td&gt;output formatting functions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>Using Numpy to build WAV files</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Sun, 01 Nov 2020 23:26:01 +0000</pubDate>
      <link>https://forem.com/slaterslater/using-numpy-to-build-wav-files-1ga6</link>
      <guid>https://forem.com/slaterslater/using-numpy-to-build-wav-files-1ga6</guid>
      <description>&lt;p&gt;I found a fun little tool that converts text into Morse Code with audio. &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nimit2801"&gt;
        nimit2801
      &lt;/a&gt; / &lt;a href="https://github.com/nimit2801/MorseCodeMessenger"&gt;
        MorseCodeMessenger
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This Project will currently let you convert your text into Encrypted Morse Code with audio!
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 It works by first declaring a dictionary of letters, numbers and symbols with their corresponding definitions of dots and dashes. The program asks the user for input; iterates through the provided string one character at a time; looks up the character's definition; and saves the result to a new encoded string. The program includes two wav files: a dot and a dash. The program iterates through the saved encoded string of dots and dashes and plays the appropriate wav file. So it can encode text into sound, but the issue was can it &lt;a href="https://github.com/nimit2801/MorseCodeMessenger/issues/2"&gt;decode sound into text&lt;/a&gt;?

&lt;p&gt;I have a little bit of experience making command line tools, but I have never worked with sound before. My plan to tackle this issue was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;figure out how to read a wav file&lt;/li&gt;
&lt;li&gt;create a wav file from multiple smaller ones&lt;/li&gt;
&lt;li&gt;figure out how to find patterns in a wav file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After a little bit of research I found that a straightforward way to read a wav file was to use &lt;a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.wavfile.read.html#scipy.io.wavfile.read"&gt;scipy.io.wavfile.read&lt;/a&gt;. The method takes a file location to a wav file and returns a sample rate as an integer and a numpy array. The opposite method &lt;a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.wavfile.write.html#scipy.io.wavfile.write"&gt;scipy.io.wavfile.write&lt;/a&gt; takes a file location, a sample rate and a numpy array and creates a wav file. After playing around with these functions for a while, I was able to read the dot and dash wav files and create a large numpy array by appending copies of the dot and dash arrays.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'uint8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;blank&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 0.1s
&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 0.03s
&lt;/span&gt;&lt;span class="n"&gt;samplerate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wavfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DOT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;samplerate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wavfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DASH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;dash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;wav_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tune&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;np_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tune&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'.'&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;dash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tune&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'-'&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;blank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;wav_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wav_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;np_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;f'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.wav'&lt;/span&gt;
&lt;span class="n"&gt;wavfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;samplerate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wav_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last thing I needed the tool to do was read a wav file and recognize patterns, specifically a dot, a dash, or blank silence. Perhaps there is a better method, but I decided that I would have the program read the wav file and look for specific values in the returned array at specific locations. This isn't a particularly elegant solution as it mainly involved checking an arbitrary location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;samplerate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wav&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wavfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.wav'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;
&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;]&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="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;      &lt;span class="c1"&gt;# size of blank array
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;' '&lt;/span&gt;
  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1120&lt;/span&gt;     &lt;span class="c1"&gt;# size of dot array
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;'.'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2080&lt;/span&gt;     &lt;span class="c1"&gt;# size of dash array
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;'-'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is a string of dots, dashes and spaces which could be passed to the original functions of the tool. &lt;br&gt;
The last thing I wanted to do, was give the user a way to specify which functions to call from the command line. So I turned to &lt;a href="https://docs.python.org/3/library/argparse.html"&gt;argparse&lt;/a&gt; and implemented the following flags:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Optional flags&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;-w&lt;/code&gt;&lt;br&gt;&lt;code&gt;--wav&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Create a Morse Code audio file&lt;/td&gt;
&lt;td&gt;At the prompts, enter a message &lt;em&gt;Hello World&lt;/em&gt; and a name &lt;em&gt;hi&lt;/em&gt;. An audio file will be created and saved as &lt;code&gt;hi.wav&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;-p&lt;/code&gt;&lt;br&gt;&lt;code&gt;--play&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Play a Morse Code audio file&lt;/td&gt;
&lt;td&gt;At the prompt, enter &lt;em&gt;hi&lt;/em&gt; and if &lt;code&gt;hi.wav&lt;/code&gt; exists, the audio will be played&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;-r&lt;/code&gt;&lt;br&gt;&lt;code&gt;--read&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Decipher a Morse Code audio file&lt;/td&gt;
&lt;td&gt;At the prompt, enter &lt;em&gt;hi&lt;/em&gt; and if &lt;code&gt;hi.wav&lt;/code&gt; exists, the text &lt;em&gt;Hello World&lt;/em&gt; will be displayed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This was a fun little project and I was really happy to have &lt;a href="https://github.com/nimit2801/MorseCodeMessenger/pull/3"&gt;my PR merged&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>Adding Form Validation to Eztrackr</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Sun, 01 Nov 2020 19:14:31 +0000</pubDate>
      <link>https://forem.com/slaterslater/adding-form-validation-to-eztrackr-435</link>
      <guid>https://forem.com/slaterslater/adding-form-validation-to-eztrackr-435</guid>
      <description>&lt;p&gt;I use Trello - maybe you do too. I came across &lt;a href="https://chrome.google.com/webstore/detail/eztrackr/kdpbamlhffmfbgglmaedhopenkpgkfdg"&gt;Eztrackr&lt;/a&gt;, a chrome extension to save notes to Trello. I noticed that Eztrackr had an open issue on github to&lt;br&gt;
&lt;a href="https://github.com/HarshdipD/job-tracker/issues/28"&gt;validate the input form before sending an API call&lt;/a&gt;. The first thing I did was install the extension and follow the documented steps to reproduce the bug. &lt;/p&gt;

&lt;p&gt;With all fields filled out, the tool works great and your note will appear as a new card in your Trello board. If the user doesn't select a board, the post fails, all entered data is lost and must be re-entered. What I needed to do was run a check to make sure a board was selected before making the API call. An error message should be displayed with a close button, so that all form data fields remain untouched. All the user should have to do is fix the error by selecting the desired Trello board, and resubmit.&lt;/p&gt;

&lt;p&gt;I walked through &lt;code&gt;popup.js&lt;/code&gt; and found the API call and since all data fields could potentially be empty except for the &lt;code&gt;idList&lt;/code&gt;, I just added a simple condition before its execution.&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="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idList&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Choose list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="nx"&gt;Trello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;/cards?key=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;APP_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;token=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;idList=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;idList&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;name=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data_company&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;desc=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If the condition fails, an error message should prompt the user to select a Trello board. I noticed that &lt;code&gt;popup.html&lt;/code&gt; contained two hidden divs that could be conditionally shown for (un)successful API calls and display a hard-coded message. Since I was attempting to fix a bug, I knew I needed show an error message. Instead of adding a third div, I decided I would modify the existing one.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- failed posted alert --&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;"alert alert-danger"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"post_fail"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: none;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h4&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Error&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;There was an issue posting this card to Trello. Please try again.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I thought what the most efficient solution would be a generic error that could receive text from javascript instead of hard coded HTML. I added a button and the new code looked like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- alert box --&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;"alert alert-danger"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"alert_box"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: none;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h4&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Error&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"alert_msg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-danger btn-sm"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"close_alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Close&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I went back to the &lt;code&gt;popup.js&lt;/code&gt; added a function that would display &lt;code&gt;#alert_box&lt;/code&gt; and pass text into &lt;code&gt;#alert_msg&lt;/code&gt;. I updated the existing code to call this function if the Trello board isn't selected or after a failed API call.&lt;/p&gt;

&lt;p&gt;After a few tests to confirm everything was working as intended, I made a pull request. Evidently the work checked all the necessary boxes, as it was merged the next day.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/HarshdipD/job-tracker/pull/29"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg"&gt;
      &lt;span class="issue-title"&gt;
        Fixes #28: Form validation
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#29&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/slaterslater"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cflr2dXa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars2.githubusercontent.com/u/2923048%3Fv%3D4" alt="slaterslater avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/slaterslater"&gt;slaterslater&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/HarshdipD/job-tracker/pull/29"&gt;&lt;time&gt;Oct 21, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;ul&gt;
&lt;li&gt;alert box displays if Trello list not chosen&lt;/li&gt;
&lt;li&gt;close button added to alert box&lt;/li&gt;
&lt;li&gt;choosing a Trello list will close alert box&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HarshdipD/job-tracker/pull/29"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Contributing to a RPG with CSV</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Thu, 22 Oct 2020 23:56:34 +0000</pubDate>
      <link>https://forem.com/slaterslater/contributing-to-a-rpg-with-csv-1moj</link>
      <guid>https://forem.com/slaterslater/contributing-to-a-rpg-with-csv-1moj</guid>
      <description>&lt;p&gt;Recent events &amp;lt;&amp;lt; &lt;em&gt;looks over at covid19&lt;/em&gt; &amp;gt;&amp;gt; have forced many of us to isolate indoors. My own DnD campaign has been slowly advancing through Zoom for the past six months. So this year, I figured I would start my &lt;strong&gt;Hacktoberfest&lt;/strong&gt; by making a perception check (with advantage) and looking for game-related issues. I pretty quickly came across Mimic Tools:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Mimic-Tools"&gt;
        Mimic-Tools
      &lt;/a&gt; / &lt;a href="https://github.com/Mimic-Tools/name-generation"&gt;
        name-generation
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Generation of character names
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
  The issue they wanted addressed was how to display a report of tabular data from their github repo. The script &lt;code&gt;region-checker.py&lt;/code&gt; could produce the desired report as HTML, but if you click on an HTML file in github... you see HTML. The solution was CSV. If you click on &lt;a href="https://github.com/Mimic-Tools/name-generation/blob/main/availability_report.csv"&gt;a CSV file in github&lt;/a&gt;, it's displayed as a nice, easy-to-read, zebra-striped table.

&lt;p&gt;The &lt;code&gt;region-checker.py&lt;/code&gt; already includes functions to iterate through all the important objects and builds strings of HTML where appropriate. I thought it would be easy enough to make a copy of said function and swap HTML syntax with CSV... But, as it turns out, CSV doesn't mean &lt;em&gt;a string with commas in it&lt;/em&gt;; it means &lt;em&gt;values separated by commas&lt;/em&gt;. After a little research, I found the &lt;a href="https://docs.python.org/3/library/csv.html"&gt;python csv library&lt;/a&gt; and was almost ready to go.&lt;/p&gt;

&lt;p&gt;If a table cell required a positive value, the ✓ character &lt;code&gt;u'\u2713'&lt;/code&gt; was written. An X was written for negative values. One of the things requested was a cross symbol instead of a literal X.&lt;/p&gt;

&lt;p&gt;I browsed through the &lt;a href="https://www.compart.com/en/unicode/block/U+2700"&gt;Unicode Block “Dingbats”&lt;/a&gt; and it turns out the &lt;br&gt;
✕  &lt;code&gt;u'\u2715'&lt;/code&gt; and ✓  &lt;code&gt;u'\u2713'&lt;/code&gt; are effectively neighbours and should work well together.&lt;/p&gt;

&lt;p&gt;I set these variables at the top of the document and I think if I were to do this over again I would move them down closer to where the reports are being built. There is also some code repetition during the loop of dictionary items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"""&amp;lt;html&amp;gt;&amp;lt;table border="1"&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Region&amp;lt;/th&amp;gt;"""&lt;/span&gt;
&lt;span class="n"&gt;csv_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s"&gt;'Region'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="n"&gt;report_headers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;report_headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;th&amp;gt;{}&amp;lt;/th&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"""&amp;lt;/tr&amp;gt;"""&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;report_item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;report_dictionary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report_item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;capitalize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;csv_row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;{}&amp;lt;/td&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;report_dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;report_item&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;report_dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;report_item&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;td&amp;gt;{}&amp;lt;/td&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;csv_row&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;td&amp;gt;{}&amp;lt;/td&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cross&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;csv_row&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cross&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    
    &lt;span class="n"&gt;csv_output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csv_row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        
    &lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;/tr&amp;gt;"&lt;/span&gt;
&lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;/table&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;

&lt;span class="n"&gt;csv_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csv_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'utf-8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;csv_writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csv_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;csv_writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writerows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csv_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;csv_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I didn't want to disturb the existing code any more than was necessary, but I think I should have modified the loop to look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;report_dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;report_item&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; 
  &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;report_dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;report_item&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;cross&lt;/span&gt;
  &lt;span class="n"&gt;html_output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;td&amp;gt;{}&amp;lt;/td&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;csv_row&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Overall fixing this issue was pretty straightforward. I learned a little bit about building/writing CSV files in python and how they're displayed in github.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Mimic-Tools/name-generation/pull/55"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg"&gt;
      &lt;span class="issue-title"&gt;
        Fixes #52: Change report to produce CSV instead of HTML
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#55&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/slaterslater"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cflr2dXa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars2.githubusercontent.com/u/2923048%3Fv%3D4" alt="slaterslater avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/slaterslater"&gt;slaterslater&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Mimic-Tools/name-generation/pull/55"&gt;&lt;time&gt;Oct 20, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;ul&gt;
&lt;li&gt;
&lt;code&gt;region-checker.py&lt;/code&gt; creates a csv file in addition to the html report&lt;/li&gt;
&lt;li&gt;added the ✕ to compliment the ✓&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Mimic-Tools/name-generation/pull/55"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>hacktoberfest</category>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>Checking links &amp; ignoring domains</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Sun, 18 Oct 2020 19:05:28 +0000</pubDate>
      <link>https://forem.com/slaterslater/checking-links-ignoring-domains-5fk6</link>
      <guid>https://forem.com/slaterslater/checking-links-ignoring-domains-5fk6</guid>
      <description>&lt;p&gt;For the past several weeks, I've been working on &lt;a href="https://github.com/slaterslater/gustavo"&gt;Gustavo&lt;/a&gt;: a URL checking command line tool written in python. I wanted to gain some experience forking repos; setting up remotes; and merging branches, so I got permission to work on a new feature for &lt;strong&gt;checkThatLink&lt;/strong&gt; &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/TDDR"&gt;
        TDDR
      &lt;/a&gt; / &lt;a href="https://github.com/TDDR/checkThatLink"&gt;
        checkThatLink
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;a href="https://github.com/TDDR/checkThatLink/issues/11"&gt;The feature I wanted to add&lt;/a&gt; would allow for a command line argument&lt;br&gt;
&lt;code&gt;-i&lt;/code&gt; or &lt;code&gt;--ignore&lt;/code&gt; to be passed along with a path to a file. The program should open the file; read the contents; and if any URLs are present, omit their domain from the HTTP status checking process.

&lt;p&gt;To begin, I needed to understand how this program worked before I could add any features. It just so happens, that &lt;strong&gt;Gustavo&lt;/strong&gt; and &lt;strong&gt;checkThatLink&lt;/strong&gt; are very similar in purpose and language. I'm by no means and expert in Python, but I felt pretty comfortable reading through the source code. As I walked through the program i determined it followed these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a parsed command line arguments object and pass it into a new checkFile object &lt;code&gt;checkFile(args)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;checkFile&lt;/code&gt; initializes all of its member variables from the &lt;code&gt;args&lt;/code&gt; object&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;checkFile&lt;/code&gt; runs its main function &lt;code&gt;checkThatFile()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Each line of the source file is inspected to see if it contains a URL&lt;/li&gt;
&lt;li&gt;A HTTP connection is made for each URL requesting the HEAD and the URL and its response status are appended in a list of dictionaries &lt;code&gt;allLinks&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A series of conditional statements determine the correct function should generate the output from &lt;code&gt;allLinks&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I didn't want the program to waste time checking a link that would later be omitted from the output, so I figured I should insert my feature/check in between step 4. &amp;amp; 5.&lt;/p&gt;

&lt;p&gt;I first created a function that would open the provided file with urls to ignore; use a regular expression to pick out all the valid urls; and return the &lt;code&gt;ignoreList&lt;/code&gt; of domains.&lt;/p&gt;

&lt;p&gt;Next I added a condition before step 5. above, so that each url's domain would be checked against the domains in the &lt;code&gt;ignoreList&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At this point, I thought I was finished. I had the author review my work before merging and I was informed that some updates were needed. The issue requirements stated that if the program receives a file containing domains to ignore, but no comments or urls are present, then the program should exit. It was a pretty straight-forward update to make: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I added another regular expression to find comments.&lt;/li&gt;
&lt;li&gt;If both regular expressions (domains and comments) are empty, the program exits.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getIgnoreList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ignoreFile&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;    
  &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ignoreFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ignoreFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
        &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'^https?://.*[^\s/]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MULTILINE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'^#.*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MULTILINE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;
  &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f'Error with &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ignoreFile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above update passed the test and the code was merged upstream!&lt;/p&gt;

&lt;p&gt;On the other side of the ball, I had a volunteer to &lt;a href="https://github.com/slaterslater/gustavo/issues/8"&gt;implement the same ignore-feature in Gustavo&lt;/a&gt;. We worked through the bugs together. I found it pretty easy to make a new branch from the contributor's remote and make some fixes. I hope I wasn't too overbearing in this regard; I didn't just point out the existence of a bug, I made suggestions and provided the code to fix them.&lt;/p&gt;

&lt;p&gt;I did learn the hard way that it is a good idea to run &lt;code&gt;git status&lt;/code&gt; or &lt;code&gt;git branch&lt;/code&gt; to know where you are in your git tree before fetching or pulling. It wasn't too serious, as I got &lt;code&gt;issue-8&lt;/code&gt; and &lt;code&gt;issue-8-fix&lt;/code&gt; mixed up. I'm getting more comfortable with git each week, but clearly I need more practice.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>Adding flag support to Gustavo </title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Tue, 13 Oct 2020 23:35:49 +0000</pubDate>
      <link>https://forem.com/slaterslater/adding-flag-support-to-gustavo-3aph</link>
      <guid>https://forem.com/slaterslater/adding-flag-support-to-gustavo-3aph</guid>
      <description>&lt;p&gt;I've been tinkering with a command line tool that searches a source file for URLs and generates a report of their status. &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/slaterslater"&gt;
        slaterslater
      &lt;/a&gt; / &lt;a href="https://github.com/slaterslater/gustavo"&gt;
        gustavo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Print a colourized report of all HTTP urls in a file
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 

&lt;p&gt;Gus received a recent PR to &lt;a href="https://github.com/slaterslater/gustavo/pull/1"&gt;add windows &amp;amp; unix style command line arguments&lt;/a&gt;. Once this PR was merged, Gus could accept and do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python gus.py -f some.file  // checks the URLs in some.file
$ python gus.py -v            // shows version info 
$ python gus.py -h            // shows usage instructions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--file&lt;/code&gt;, &lt;code&gt;--version&lt;/code&gt; and &lt;code&gt;--help&lt;/code&gt; work too.&lt;/p&gt;

&lt;p&gt;A great start, but why stop there? I knew I wanted Gus to handle many more arguments, so it no longer made sense to check &lt;code&gt;sys.argv&lt;/code&gt; against strings through a series of conditional statements. I decided to import &lt;a href="https://docs.python.org/3/library/argparse.html"&gt;argparse&lt;/a&gt; to do this heavy lifting for me.&lt;/p&gt;

&lt;p&gt;The first thing I did was change the default output of the program. Instead of automatically producing a Rich Text File, output to the console would be standard. If the user wants a Rich Text File as the output, they can pass Gus &lt;br&gt;
&lt;code&gt;-r&lt;/code&gt; or &lt;code&gt;--rtf&lt;/code&gt; from the command line.&lt;/p&gt;

&lt;p&gt;Next I updated the checker function by swapping the &lt;strong&gt;http.client&lt;/strong&gt; library for &lt;strong&gt;requests&lt;/strong&gt;. I renamed &lt;code&gt;get_status_code()&lt;/code&gt; to &lt;code&gt;get_status()&lt;/code&gt; since it would be returning the code and description as a dictionary. I figured this would be helpful down the road when determining the output format (console or RTF).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;
    &lt;span class="n"&gt;series&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'UNKN'&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;series&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'2'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'GOOD'&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;series&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'4'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'FAIL'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'code'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'desc'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="c1"&gt;# all exceptions default to status == 400
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'code'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'desc'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'FAIL'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One thing I want to point out before moving on... Notice how all exceptions default to &lt;code&gt;status == 400&lt;/code&gt;. I'm not really happy with this, so I opened a &lt;a href="https://github.com/slaterslater/gustavo/issues/6"&gt;new issue to improve exception handling&lt;/a&gt;. Hopefully in the near future I (or someone else 🤞) will have the time to work on this.&lt;/p&gt;

&lt;p&gt;Whichever output format the user chooses, I decided it will be displayed or produced once all URLs have been checked. Since Gus doesn't yet leverage threading, this can take a while. In the event that Gus is taking a long time, I wanted to show the user that everything is ok by showing the progress. After a little research I came up with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f'&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt; Checking URL &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By putting the above print statement in my for loop, each iteration over-writes itself and provides a single line progress update to the user.&lt;/p&gt;

&lt;p&gt;Once everything worked as expected, I created two new branches to develop two new features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/slaterslater/gustavo/issues/3"&gt;Support --json flag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/slaterslater/gustavo/issues/5"&gt;Support --all, --good, and --bad flags&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point I was very happy to have &lt;a href="https://docs.python.org/3/library/argparse.html"&gt;argparse&lt;/a&gt; on board. Argparse was already sending a string parameter &lt;code&gt;output&lt;/code&gt; to the main function. The value of &lt;code&gt;output&lt;/code&gt; could either be &lt;strong&gt;"std"&lt;/strong&gt; or &lt;strong&gt;"rtf"&lt;/strong&gt; and adding &lt;strong&gt;"json"&lt;/strong&gt; into the mix was easy peasy.&lt;/p&gt;

&lt;p&gt;In order to support &lt;code&gt;--all&lt;/code&gt;, &lt;code&gt;--good&lt;/code&gt;, and &lt;code&gt;--bad&lt;/code&gt; flags, argparse needed to send a list parameter &lt;code&gt;wanted&lt;/code&gt; to the main function. By default, the &lt;code&gt;wanted&lt;/code&gt; list would be equal to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'GOOD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;'FAIL'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'UNKN'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Passing &lt;code&gt;--good&lt;/code&gt; or &lt;code&gt;--bad&lt;/code&gt; restrict the values of the above list accordingly. In all cases, the values in &lt;code&gt;wanted&lt;/code&gt; get checked against the returned dictionary from &lt;code&gt;get_status()&lt;/code&gt; and if there is a match, the formatted string is saved for later output.&lt;/p&gt;

&lt;p&gt;Since many functions need to know what the user's output choice is, I decided to make it a &lt;strong&gt;global variable&lt;/strong&gt; instead of passing it from function to function. I'm not sure if this is bad form, but the code looks pretty clean and everything worked as intended.&lt;/p&gt;

&lt;p&gt;To date, these are all the options for Gus:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command line arguments&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-f FILENAME, --file FILENAME&lt;/td&gt;
&lt;td&gt;location of source file to be checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-a, --all&lt;/td&gt;
&lt;td&gt;output includes all results (this is default)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-g, --good&lt;/td&gt;
&lt;td&gt;output includes only [GOOD] results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-b, --bad&lt;/td&gt;
&lt;td&gt;output includes only [FAIL] results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-r, --rtf&lt;/td&gt;
&lt;td&gt;output as colourized rich text file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-j, --json&lt;/td&gt;
&lt;td&gt;output as JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-h, --help&lt;/td&gt;
&lt;td&gt;show information on how to use the tool and exit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-v, --version&lt;/td&gt;
&lt;td&gt;show program's version number and exit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The hard part was the merging of two branches. It was supposed to be a recursive three-way merge, but it ended up a dog's breakfast... I'm certain I screwed up the merging, but the code I want is up on Github so I guess I can't complain. I have two more features planned for Gus, so I'll try merging branches again soon.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>Refactoring Verify-URL</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Sat, 03 Oct 2020 22:10:39 +0000</pubDate>
      <link>https://forem.com/slaterslater/refactoring-verify-url-2p45</link>
      <guid>https://forem.com/slaterslater/refactoring-verify-url-2p45</guid>
      <description>&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/abhaseen"&gt;
        abhaseen
      &lt;/a&gt; / &lt;a href="https://github.com/abhaseen/Verify-URL"&gt;
        Verify-URL
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Python script that verifies the return code of URLs.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 The first thing I noticed was the entire program was written inside the main() function. To help me understand how the program worked, I decided &lt;a href="https://github.com/abhaseen/Verify-URL/pull/9"&gt;I would refactor Verify-URL into smaller functions&lt;/a&gt;.

&lt;p&gt;I reordered main() into the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;get_args()&lt;/li&gt;
&lt;li&gt;check_args()&lt;/li&gt;
&lt;li&gt;get_urls()&lt;/li&gt;
&lt;li&gt;verify_url()&lt;/li&gt;
&lt;li&gt;print_status()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything looked good and worked as expected... except when I supplied a filename.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; python verify_url.py src.html
Invalid URL '': No schema supplied. Perhaps you meant http://?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I traced the error to get_urls() as it looked as though a &lt;strong&gt;NoneType&lt;/strong&gt; object was being appended into what was supposed to be a list of strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To fix, I cast every item as a string and checked to see if it started with 'http'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'http'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;   
    &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I ran the tool again from the command line and supplied a file to check. This time it ran smoothly and printed a colourful list. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/abhaseen/Verify-URL/pull/9"&gt;I submitted a Pull Request&lt;/a&gt;, so hopefully these changes pass the Author's test! That wasn't supposed to rhyme... &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Reviewing URLChecker</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Fri, 02 Oct 2020 04:09:03 +0000</pubDate>
      <link>https://forem.com/slaterslater/reviewing-urlchecker-1ngg</link>
      <guid>https://forem.com/slaterslater/reviewing-urlchecker-1ngg</guid>
      <description>&lt;p&gt;Since I recently started development of a command line tool that searches a source file for URLs and check their status, I decided to review an existing one while I'm at it. My tool is written in Python, but I'm interested to see how the same task could be done using JavaScript.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/danishalim"&gt;
        danishalim
      &lt;/a&gt; / &lt;a href="https://github.com/danishalim/URLChecker"&gt;
        URLChecker
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Bulk check URL status codes
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 First thing I noticed was just how fast async functions are! I ran this tool against the same source file I've been using to develop my own work and it took maybe 15 seconds. &lt;strong&gt;Maybe.&lt;/strong&gt; Usually when I run my Python URL checking tool, I get up to walk around and check back in a few minutes...

&lt;p&gt;My one criticism of URLChecker is &lt;a href="https://github.com/danishalim/URLChecker/issues/6"&gt;the regular expression it uses&lt;/a&gt; to find URLs in a file. I ran into the same issue myself during development and fixing it ended up opening up a whole other can of worms. Once the regex includes characters like &lt;strong&gt;[]&lt;/strong&gt; and &lt;strong&gt;()&lt;/strong&gt; then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://some(web).site&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// matches http://some(web).site&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(http://someweb.site)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// matches http://someweb.site)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Although URLChecker will need to update its regex so it includes &lt;a href="https://developers.google.com/maps/documentation/urls/url-encoding#BuildingURLs"&gt;all valid URL characters&lt;/a&gt;, I am extremely envious of how fast it produces its results. &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Introducing Gustavo</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Thu, 01 Oct 2020 20:48:45 +0000</pubDate>
      <link>https://forem.com/slaterslater/introducing-gustavo-1n3b</link>
      <guid>https://forem.com/slaterslater/introducing-gustavo-1n3b</guid>
      <description>&lt;p&gt;I needed to search a file for URLs and generate a report of their status. So I created Gustavo to do the work for me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get-Url-Status (GUS) Text-As-Visual-Output (TAVO)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sure, the name might be a little corny, but it makes me happy so I'm sticking with it. I also like to imagine Gus as an old mustachioed plumber that checks all the URL connections in a document... &lt;/p&gt;

&lt;p&gt;Gus can be called from the command line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;python gus.py example.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;or from the python shell&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; import gus
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; gus.tavo&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'example.html'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;How does Gus work?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The file at the provided location is opened and the contents are saved as a string.&lt;/li&gt;
&lt;li&gt;A regular expression matches every instance of HTTP or HTTPS and the results are saved as a list.&lt;/li&gt;
&lt;li&gt;For each item in the list, an HTTP connection is made - requesting just the header - and the HTTP response code is returned.&lt;/li&gt;
&lt;li&gt;The returned code corresponds to a status: 2xx is labeled as [GOOD]; 4xx is labeled [WARN]; and everything else defaults to [UNKN].&lt;/li&gt;
&lt;li&gt;The entire list of URLs, codes and their status are printed to the console and also written to a file.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I knew I wanted the written output file to be colourized, so I did some research into producing Rich Text Files. There is lots of great info at &lt;a href="http://www.pindari.com/rtf1.html"&gt;www.pindari.com&lt;/a&gt; but unfortunately my solution ended up being a little hackier than anticipated.&lt;/p&gt;

&lt;p&gt;First I opened TextEdit and created &lt;strong&gt;output.rtf&lt;/strong&gt; with four lines of text. Each line was given a different colour (default, grey, green, &amp;amp; red). Then I had python open the file, read the contents and print it all to the console. Next I copied everything up to the first line of text and saved it to a constant. What remained were the lines of text and the colour-codes I needed! I copied those into a function which would append the appropriate code to the URL string depending on the returned HTTP status.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;check_nested&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;check_status_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;r'\cf2'&lt;/span&gt; &lt;span class="c1"&gt;#grey
&lt;/span&gt;    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'UNKN'&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'2'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;r'\cf4'&lt;/span&gt; &lt;span class="c1"&gt;#green
&lt;/span&gt;      &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'GOOD'&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'4'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;r'\cf3'&lt;/span&gt; &lt;span class="c1"&gt;#red
&lt;/span&gt;      &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'WARN'&lt;/span&gt;
    &lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; [&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] [&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;No doubt there is a lot of room for future improvement, but overall I'm pretty happy with results so far.&lt;/p&gt;

&lt;p&gt;If you're at all interested, check out the repo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/slaterslater"&gt;
        slaterslater
      &lt;/a&gt; / &lt;a href="https://github.com/slaterslater/gustavo"&gt;
        gustavo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Print a colourized report of all HTTP urls in a file
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>Getting started in Open Source development</title>
      <dc:creator>Anthony Slater</dc:creator>
      <pubDate>Fri, 18 Sep 2020 22:01:38 +0000</pubDate>
      <link>https://forem.com/slaterslater/getting-started-in-open-source-development-2i39</link>
      <guid>https://forem.com/slaterslater/getting-started-in-open-source-development-2i39</guid>
      <description>&lt;p&gt;I'm Anthony - a computer programming student living in Toronto, Canada. During my first semester, I remember circling the Open Source Development courses as ones I knew I wanted to take. Each semester I would take all the requisite classes in C++, SQL, Java &amp;amp; Javascript as stepping stones towards the goal of Open Source Development. Now - here I am in my final semester and I feel wholly unprepared and out of my depth. &lt;/p&gt;

&lt;p&gt;It's my understanding that the imposter syndrome is pretty normal for beginner programmers and it's my hope that over the next few months I'm able to shake it.&lt;/p&gt;

&lt;p&gt;I've been taking a look at RxDB &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pubkey"&gt;
        pubkey
      &lt;/a&gt; / &lt;a href="https://github.com/pubkey/rxdb"&gt;
        rxdb
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      💻 🔄 📱 A realtime Database for JavaScript Applications
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 It looks really interesting, as I've had some aspirations to build some mobile apps that could leverage a feature like state change subscriptions. I don't know if I'll be able to contribute anything meaningful to this repo, but it looks to be something I could use in future project of mine.

</description>
      <category>opensource</category>
    </item>
  </channel>
</rss>
