<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mitch Pomery (he/him)</title>
    <description>The latest articles on DEV Community by Mitch Pomery (he/him) (@mitchpommers).</description>
    <link>https://dev.to/mitchpommers</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%2F194709%2Ff0c124fe-5b86-4a14-aa27-a28cd0034117.png</url>
      <title>DEV Community: Mitch Pomery (he/him)</title>
      <link>https://dev.to/mitchpommers</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mitchpommers"/>
    <language>en</language>
    <item>
      <title>My Textable Cat Printer</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Wed, 11 Aug 2021 04:39:08 +0000</pubDate>
      <link>https://dev.to/mitchpommers/my-textable-cat-printer-18ge</link>
      <guid>https://dev.to/mitchpommers/my-textable-cat-printer-18ge</guid>
      <description>&lt;p&gt;I was scrolling on twitter one afternoon and saw that xssfox had a Bluetooth Thermal Cat Printer. I have had an idea that required a thermal printer for a while now and this looked like a really good printer for what I wanted to do, so I ordered one.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1420254881613451272-210" src="https://platform.twitter.com/embed/Tweet.html?id=1420254881613451272"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1420254881613451272-210');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1420254881613451272&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The original idea I had was to set up a thermal printer so you could message it a picture, have it print off and stick it in a guest book, like you might do with a polaroid at a wedding. But It doesn't look like I will be going to a wedding any time soon. So instead, to allow people to interact with it remotely, I decided to give it a phone number and let people send messages that would print out on my desk.&lt;/p&gt;

&lt;p&gt;To contact it, message &lt;code&gt;cat:[message to print]&lt;/code&gt; to one of the below numbers to have it printed.&lt;br&gt;
&lt;strong&gt;Aus:&lt;/strong&gt; +61 480 029 995&lt;br&gt;
&lt;strong&gt;US:&lt;/strong&gt; +1 520 521 0228&lt;/p&gt;
&lt;h1&gt;
  
  
  Giving The Cat Printer A Number
&lt;/h1&gt;

&lt;p&gt;To be able to give the cat printer a number, first I had to get it to print. I pulled out a raspberry pi I had from the time I had my apartment lights controlled using amazon dash buttons. xssfox had some code that allowed you to send messages and images to be printed via HTTP requests. After getting that running on my pi and debugging some differences between how python handles bytes between Windows and Linux, I was able to send my first messages to print!&lt;/p&gt;

&lt;p&gt;The python code I am using is available at &lt;a href="https://gist.github.com/mpomery/6514e521d3d03abce697409609978ede" rel="noopener noreferrer"&gt;https://gist.github.com/mpomery/6514e521d3d03abce697409609978ede&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1420599852061237248-210" src="https://platform.twitter.com/embed/Tweet.html?id=1420599852061237248"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1420599852061237248-210');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1420599852061237248&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Once I had it printing, I went into my Twilio console and started adding some functions to my textable light project. I created a new function that would look at the incoming message for the prefix &lt;code&gt;cat:&lt;/code&gt; and redirect the message to the cat printer. Later I went back and made my light require the prefix &lt;code&gt;light:&lt;/code&gt; and an error message if neither of the prefixes were present.&lt;/p&gt;

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

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

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Twilio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MessagingResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/cat_printer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/textable_light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`"light:[colour]" to add a colour to the light
"cat:[text]" to print on the cat printer`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;I then set up a second function &lt;code&gt;cat_printer&lt;/code&gt; to format the message to be sent to the printer. It takes the incoming message, removes the &lt;code&gt;cat:&lt;/code&gt; prefix, redacts part of the number it was received from and formats it with a timestamp for printing. Then it makes a call to the web server running on my raspberry pi (which was made available to the internet using ngrok) to print it. Once that request has been made, the response from the printer gets sent back to the number who texted it.&lt;/p&gt;


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

&lt;p&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Twilio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MessagingResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;incomingMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;incomingMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;incomingMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;incomingMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;From&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&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;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;printMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-GB&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;timeZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Australia/Sydney&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;From: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;incomingMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;printMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catURL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?text=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;printMessage&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&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;br&gt;
      &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&lt;code&gt;&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;${&amp;lt;/span&amp;gt;&amp;lt;span class="nx"&amp;gt;response&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="nx"&amp;gt;data&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&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;br&gt;
      &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&lt;code&gt;You sent a message with special characters or the cat printer is offline.&lt;/code&gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twiml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Getting People To Message It&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;Once I had it working I started telling people about it. Some of my friends had already seen my textable light, so the idea of sending a text message to something on my desk wasn't new to them. I was initially cryptic about what I had made, but once people knew what it was they started messaging it!&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1420892406476468228-812" src="https://platform.twitter.com/embed/Tweet.html?id=1420892406476468228"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1420892406476468228-812');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1420892406476468228&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Some of my friends made me regret telling them about the cat printer:&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1421019519485571072-645" src="https://platform.twitter.com/embed/Tweet.html?id=1421019519485571072"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1421019519485571072-645');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1421019519485571072&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I streamed it briefly so people could see what they sent print in real time, including this really long message:&lt;br&gt;
&lt;iframe src="https://clips.twitch.tv/embed?clip=PatientInexpensivePigTakeNRG-W0ojMkY5ohNpk5ha&amp;amp;parent=dev.to&amp;amp;autoplay=false" height="399" width="710"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Then I started to see several people sending it messages internationally, so I purchased a second Twilio number so I could respond to them:&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1424959545302937601-107" src="https://platform.twitter.com/embed/Tweet.html?id=1424959545302937601"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1424959545302937601-107');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1424959545302937601&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;And then the TwilioDev twitter account tweeted it, expediting this blog post:&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1425255647017324546-752" src="https://platform.twitter.com/embed/Tweet.html?id=1425255647017324546"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1425255647017324546-752');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1425255647017324546&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Now that I have it built and it has a semi-permanent position on my desk, I need to make a better way to keep all of my projects displayed on my desk. I would really like to make them all visible on the internet permanently. I have ideas on how I could achieve this, but don't have access to what I need to make it possible or the space to do it at the moment.&lt;/p&gt;

&lt;p&gt;And if you are considering making something similar yourself using Twilio Programmable Messaging, you can &lt;a href="//www.twilio.com/referral/QqpNkR"&gt;get $10 when you upgrade using this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>twilio</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Updating My "Get On The Beers" Indicator To Track Vaccinations</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Sun, 08 Aug 2021 23:45:00 +0000</pubDate>
      <link>https://dev.to/mitchpommers/updating-my-get-on-the-beers-indicator-to-track-vaccinations-495b</link>
      <guid>https://dev.to/mitchpommers/updating-my-get-on-the-beers-indicator-to-track-vaccinations-495b</guid>
      <description>&lt;p&gt;Over 6 months have passed since I first made this indicator light, and while it was good during previous outbreaks, the increasing availability of vaccinations in Australia means runs of 0 cases is less important. More important is getting jabbed! So I updated my light to track daily jabs!&lt;/p&gt;

&lt;p&gt;The New Colour Code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No data yet: White&lt;/li&gt;
&lt;li&gt;Under 25,000 jabs in NSW today: Red&lt;/li&gt;
&lt;li&gt;Under 80,000 jabs: Blue&lt;/li&gt;
&lt;li&gt;Under 80,000 jabs: Green&lt;/li&gt;
&lt;li&gt;100,000 plus jabs: Party Mode!&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Finding The Data
&lt;/h1&gt;

&lt;p&gt;Just like the original build, finding a data source to use was critical to making it work. Data NSW didn't have vaccination data available that I could find and I didn't want to go down the path of searching for different API's hoping that one would have the data I wanted.&lt;/p&gt;

&lt;p&gt;The COVID LIVE website has a page with &lt;a href="https://covidlive.com.au/report/daily-vaccinations/nsw"&gt;NSW Daily vaccinations&lt;/a&gt; on it in table form! There's also a nice JSON file with all the data that it's creator &lt;a href="https://twitter.com/migga"&gt;Migga&lt;/a&gt; told me about when he came across my indicator light the first time. The Electric Imp agent has a 2048kB memory limit though, so I can't load the full JSON file in. The page with the table on it will have to do!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AnbIaP5o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xqngtk5cexk26dbgzcsf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AnbIaP5o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xqngtk5cexk26dbgzcsf.png" alt="A screenshot of the COVID LIVE website showing the latest vaccination numbers for NSW."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The source code of the website makes it easy to extract the number I want to make the light colour decision on. I need to find the last column in the first table row (not table header) and understand that number.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w7N8LgSu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0vj6dpuxmufaghude5r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w7N8LgSu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0vj6dpuxmufaghude5r.png" alt="The source code for the COVID LIVE website showing the table of daily vaccinations that I am interested in."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Making It Light Up
&lt;/h1&gt;

&lt;p&gt;I used the code from the &lt;a href="https://dev.to/mitchpommers/get-on-the-beers-indicator-using-electric-imp-17n8"&gt;previous version that tracked daily cases of known local transmission&lt;/a&gt; as the starting point. It has code on the device to set the lights colour based on the number it received. And the agent has code to make a web request and massage data in the response to determine the number and send it oto the device.&lt;/p&gt;

&lt;p&gt;I started with the device code (code that runs on the hardware), changing the numbers for each colour. Then I reversed the order of the logic. This meant it would check if it was going to be party mode first, then work back towards 0 for red, and finally treat any other response (i.e. negative numbers) as an indication to show white. The main driver behind reversing the order of the code was to make it so I only needed to disable party mode once, instead of disabling it for each colour. Once done this was the device code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Once I had the device code updated (and had tested it by feeding it some hardcoded data) I moved on to writing the agent code (code that runs in the cloud).&lt;/p&gt;

&lt;p&gt;I renamed variables and functions to represent what the code would now be doing, then started writing code to parse the HTML that I was extracting the data from. To extract the data I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Found the first line of the table rows&lt;/li&gt;
&lt;li&gt;Found the end of the opening tag for the net change column&lt;/li&gt;
&lt;li&gt;Removed everything prior to that&lt;/li&gt;
&lt;li&gt;Found the first closing tag (which could either be the a span or a td tag)&lt;/li&gt;
&lt;li&gt;Removed it and everything after it&lt;/li&gt;
&lt;li&gt;Checked if there was still an opening tag that needed removing&lt;/li&gt;
&lt;li&gt;Removed it if there was&lt;/li&gt;
&lt;li&gt;Checked if all I had left was a "-" character (indicating that there was no data for the day yet)&lt;/li&gt;
&lt;li&gt;If there wasn't, removed all commas from the string and turned it into an integer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I tried thinking of other ways I could simplify the code for extracting this data, but there weren't any libraries or functions I could see that would help. This was the agent code once I was finished:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h1&gt;
  
  
  Closing
&lt;/h1&gt;

&lt;p&gt;Now that I have it updated and have tested that it is working (and fixed the edge cases I didn't think of when I was first coding it) I have it sitting somewhere a bit more visible on my desk, waiting for the day it first goes multicoloured.&lt;/p&gt;

&lt;p&gt;Personally, I'm hoping it does that on tomorrow because I am getting jabbed today (and that's when today's numbers will be shown).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---EN7tuxX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mayzxknwrmpcmr5oteko.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---EN7tuxX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mayzxknwrmpcmr5oteko.png" alt='"Beers?" indicator lit blue showing that there were between 25000 and 80000 vaccinations administered in NSW. The textable light (lit blue, pink then white) and the textable cat (showing a message of "Goodnight") are also visible'&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>electronics</category>
      <category>electricimp</category>
    </item>
    <item>
      <title>"Get On The Beers" Indicator Using Electric Imp</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Mon, 04 Jan 2021 00:06:03 +0000</pubDate>
      <link>https://dev.to/mitchpommers/get-on-the-beers-indicator-using-electric-imp-17n8</link>
      <guid>https://dev.to/mitchpommers/get-on-the-beers-indicator-using-electric-imp-17n8</guid>
      <description>&lt;p&gt;While I was building my friend an &lt;a href="https://dev.to/mitchpommers/how-i-made-a-light-that-turns-on-when-streaming-1f6l"&gt;On Air Light that turns on when streaming&lt;/a&gt;, I thought it was really cool and wanted to build my own indicator light. I don't stream so had to think of something different to use the light to indicate. I saw this tweet in my twitter feed and it gave me an idea!&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1340944007652753411-690" src="https://platform.twitter.com/embed/Tweet.html?id=1340944007652753411"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1340944007652753411-690');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1340944007652753411&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I could use a light to indicate if there was community transmission of COVID-19 and if it was safe to go to the pub! The colour of the light would indicate how long since the last case of community transmission:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local transmission -&amp;gt; Red&lt;/li&gt;
&lt;li&gt;First week of no local transmission -&amp;gt; Blue&lt;/li&gt;
&lt;li&gt;Second week of no local transmission -&amp;gt; Green&lt;/li&gt;
&lt;li&gt;Further weeks -&amp;gt; Multi-Coloured Rainbow&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Finding The Data
&lt;/h1&gt;

&lt;p&gt;Finding a reliable source of data for this project took a lot of research. The data I am looking for is community transmission in New South Wales, Australia. There are an abundance of COVID-19 APIs available, almost all using data from the &lt;a href="https://github.com/CSSEGISandData/COVID-19" rel="noopener noreferrer"&gt;John Hopkins University CSSE COVID-19 Git Repo&lt;/a&gt;. This dataset does contain NSW data but does not contain information about community transmission, so any API that only uses this as its data source is out of the question.&lt;/p&gt;

&lt;p&gt;Data.NSW has a dataset published for &lt;a href="https://data.nsw.gov.au/data/dataset/nsw-covid-19-cases-by-likely-source-of-infection" rel="noopener noreferrer"&gt;COVID-19 Cases By Likely Source Of infection&lt;/a&gt;, which could be used to determine how many days since the last case of community transmission, but this requires processing to understand. They also have some other datasets with similar information, but I was unable to find one that gave days since last community transmission as a value.&lt;/p&gt;

&lt;p&gt;Then there is &lt;a href="https://www.covid19data.com.au/" rel="noopener noreferrer"&gt;COVID-19 in Australia Data&lt;/a&gt; with beautiful graphs and tables visualising COVID-19 data in a variety of different ways. One of their visualisations is how many days it has been between different milestones, split by state. If I could access the data used for the visaulisations I could use it for my visualisation.&lt;/p&gt;

&lt;p&gt;They use Datawrapper to do the visualisations and by looking at what Datawrapper does in the browser, I was able to see that it loaded a CSV from their CDN with the data in it. I can directly access the CSV files, and after checking multiple days I could see that the filenames did not change!&lt;/p&gt;

&lt;p&gt;The CSV format used is simple. It has a single header row, then the data rows. The data rows start with the state, followed by three integer fields for local, overseas and active cases. CSV is a nice file format because it can generally be easily processed without the need for a library to understand it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;,Days since a new local case,Days since a new overseas case,Days since any active cases
...
NSW,0,0,0
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  Coding the Electric Imp
&lt;/h1&gt;

&lt;p&gt;Now that I know I have the data, I can start working on the code. For this project I'm using an &lt;a href="https://store.electricimp.com/collections/featured-products-1/products/impexplorer-developer-kit" rel="noopener noreferrer"&gt;Electric Imp impExplorer Developer kit&lt;/a&gt;, meaning I don't need to do any electronics. After &lt;a href="https://developer.electricimp.com/gettingstarted/explorer" rel="noopener noreferrer"&gt;performing a BlinkUp, getting familiar with the impCentral IDE and creating a new project&lt;/a&gt; I was ready to start writing some code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxjrpzgam7x1vfzcv38t2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxjrpzgam7x1vfzcv38t2.jpg" title="The Electric Imp impExplorer board" alt="The Electric Imp impExplorer board"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Electric Imp platform gives you both a device and an agent that you can run code on. This lets you do power/resource intensive processing on the agent and send instructions as a result to the device. It also means that as long as the device can communicate with the agent, the agent can reach out to the internet. Conversely from the internet you can talk to the device via the agent. For this project, I want to process the CSV on the agent, send the result to the device and have the device do something as a result.&lt;/p&gt;
&lt;h2&gt;
  
  
  Turning the LED on
&lt;/h2&gt;

&lt;p&gt;The first step in building the light is to get the light on the impExplorer to turn on and log that it has started. To do this, we need to include the &lt;a href="https://developer.electricimp.com/libraries/hardware/ws2812" rel="noopener noreferrer"&gt;WS2812 library&lt;/a&gt;, &lt;a href="https://developer.electricimp.com/hardware/resources/reference-designs/explorerkit" rel="noopener noreferrer"&gt;set pin 1 to be a digital output on the ImpExplorer&lt;/a&gt;, then configure and use the library to turn the LED on.&lt;/p&gt;

&lt;p&gt;Logging on the device can be achieved by using &lt;a href="https://developer.electricimp.com/api/server/log" rel="noopener noreferrer"&gt;server.log&lt;/a&gt;, which will log to impCentral.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Device Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h2&gt;
  
  
  Device To Agent Communication
&lt;/h2&gt;

&lt;p&gt;Now that the LED is turning on when the device starts, we want to use device to agent communication. Electric Imp lets us do this by registering functions that will process a message from the device the the agent and vice-versa.&lt;/p&gt;

&lt;p&gt;On the agent you use &lt;a href="https://developer.electricimp.com/api/device/on" rel="noopener noreferrer"&gt;device.on&lt;/a&gt; to register a function to handle messages from the device. On the device you use &lt;a href="https://developer.electricimp.com/api/agent/send" rel="noopener noreferrer"&gt;agent.send&lt;/a&gt; to send the message to the agent. Using these two functions lets us talk from the device to the agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Device Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Agent To Device Communication
&lt;/h2&gt;

&lt;p&gt;Now that we have the impExplorer asking the agent for an update, we want the agent to respond. Similar to device to agent communication, there is &lt;a href="https://developer.electricimp.com/api/agent/on" rel="noopener noreferrer"&gt;agent.on&lt;/a&gt; to register a function to handle a message on the device and &lt;a href="https://developer.electricimp.com/api/device/send" rel="noopener noreferrer"&gt;device.send&lt;/a&gt; on the agent to send a message to the device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Device Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Colour Decisions
&lt;/h2&gt;

&lt;p&gt;Once we have the device asking the agent for an update and the agent responding, we can start programming the device to have it respond to the messages sent from the agent. The function we wrote to handle the messages from the agent has to have a parameter for the data that the agent sends. This data could be any object. Since we are sending days since the last community transmission, we can send a single integer and make the colour decision on the device from that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Device Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Polling For The Latest Data
&lt;/h2&gt;

&lt;p&gt;Our indicator light is working! We can manually change the data we are sending to get the light to change colour to test out the different colours.&lt;/p&gt;

&lt;p&gt;Something we haven't done is make the device poll for updates. It will get the colour at power on and not update until a restart. We don't want to have to restart the imp regularly, so we need to create a loop.&lt;/p&gt;

&lt;p&gt;We could use a &lt;code&gt;while(true)&lt;/code&gt; loop, but doing this would prevent the imp from going into low power modes and drain the battery quickly (if run on batteries). Instead we can use &lt;a href="https://developer.electricimp.com/api/imp/wakeup" rel="noopener noreferrer"&gt;imp.wakeup&lt;/a&gt; to create a timer that will execute a function when the timer fires. If we put this in the &lt;code&gt;requestUpdate&lt;/code&gt; function and have it call &lt;code&gt;requestUpdate&lt;/code&gt; we create an infinite loop that allows the imp to go into low power modes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Device Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Getting The Correct Data
&lt;/h2&gt;

&lt;p&gt;Now that we have the device polling for the agent for updates and updating the colour of the light based on the response, we need to update the agent to get our CSV, process the data and then send the our response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Working Code
&lt;/h2&gt;

&lt;p&gt;We're nearly done! We have the device polling the agent and updating the lights, and the agent will reach out and get updated information when asked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Device Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Adding Multicoloured Lights
&lt;/h2&gt;

&lt;p&gt;The light going white isn't as flashy as we want for the big achievement of reaching two weeks without any cases of community transmission. For that we want the light to go change colours! We can do this by making a Rainbow Mode! When in rainbow mode we have the light change colour slightly, travelling around the colour wheel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Device Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h1&gt;
  
  
  Housing And Mounting It
&lt;/h1&gt;

&lt;p&gt;Now that the indicator light is working, we need a way to display it so that the information is understandable. Otherwise it's just a bare board and the light could be indicating anything. For this project I drew up a box that the imp could sit inside in CAD and put text on the front of it with the indicator light to explain the status.&lt;/p&gt;

&lt;p&gt;Keeping with the Dan Andrews "Get On The Beers" theme, I went with the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Red - The Pub Is Shut&lt;/li&gt;
&lt;li&gt;Blue - Case Last Week&lt;/li&gt;
&lt;li&gt;Green - Can't Be Any Clearer&lt;/li&gt;
&lt;li&gt;Multicoloured - Get On The Beers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using the laser cutter at my local makerspace I was able to cut out the box and glue it together, making sure not to glue the top so that I could still access the imp inside.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb5blcjtnincnewcqt6zd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb5blcjtnincnewcqt6zd.jpg" title="Attempting to get a good engrave on the laser cutter" alt="Attempting to get a good engrave on the laser cutter"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6rzd0exuaaxxzjwjt894.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6rzd0exuaaxxzjwjt894.jpg" title="A close up of the bad engraving." alt="A close up of the bad engraving. The text is fuzzy and hard to read."&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fylvs614009ljwanxjc0r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fylvs614009ljwanxjc0r.jpg" title="The glue up of the final housing" alt="The glue up of the final housing, making sure to keep the lid off"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frr4zwso8unw6uki84d88.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frr4zwso8unw6uki84d88.jpg" title="The housing glued up and ready to home. The text on it is clear" alt="The housing glued up and ready to home. The text on it is clear and reads "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finding somewhere to put it around the house was difficult. I wanted it somewhere where I would see it every day, but not somewhere where it would be visible to me for most of the day. I try to make sure I head out for a walk at least once a day around lunch time, so decided to mount it by the front door, plugged into an extension cord so I don't have to worry about battery life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffpch1fltfo48nbm2v6yu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffpch1fltfo48nbm2v6yu.jpg" title="The Get On The Beers Indicator Light in it's final home" alt="The Get On The Beers Indicator Light in it's final home. It sits on top of a dusty shelf near a headphone hook, desk light and motorcycle helmet, with a figurine behind it. The indicator light is unfortunately red."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Reflection
&lt;/h1&gt;

&lt;p&gt;I had a lot of fun building this indicator light and writing about it and got to learn more about the laser cutter I get to use. The more I read about Electric Imps, the more I see how I could make improvements to the code I have written. I am going to need to order more of them so I can use them in more projects. &lt;/p&gt;

&lt;p&gt;I have been thinking about what I could an indicator light for when COVID-19 community transmission is no longer a major concern in my area.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I could update it to be a visual clock that indicates morning, lunch, afternoon, when it is time to head to the pub, and bedtime with different colours instead of the actual time.&lt;/li&gt;
&lt;li&gt;I could swap the front panel from the box and make a &lt;a href="https://www.youtube.com/watch?v=8_FdR-L7qrs" rel="noopener noreferrer"&gt;busy light for meetings&lt;/a&gt; like Christine Sunu has done.&lt;/li&gt;
&lt;li&gt;I could send it to the office with my colleagues in another state and use it as a presence light so they can see when I am at my desk and available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The possibilities are endless!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>electronics</category>
      <category>twilio</category>
    </item>
    <item>
      <title>How I made a light that turns on when streaming</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Thu, 24 Dec 2020 02:32:57 +0000</pubDate>
      <link>https://dev.to/mitchpommers/how-i-made-a-light-that-turns-on-when-streaming-1f6l</link>
      <guid>https://dev.to/mitchpommers/how-i-made-a-light-that-turns-on-when-streaming-1f6l</guid>
      <description>&lt;p&gt;I asked my friend Ben what I could get him for Christmas this year and he said that I should surprise him and make something. When I was looking at my list of projects thinking what I could make him it hit me: I had an idea of making an indicator light for our apartment so my partner could see if I was in a meeting when getting home from work&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. I could do something similar for Ben and make him an "On Air" sign that turns on when he starts streaming!&lt;/p&gt;

&lt;h1&gt;
  
  
  Electronics
&lt;/h1&gt;

&lt;p&gt;The first thing I needed to figure out was the electronics. I had a couple of NodeMCU boards that have been sitting in my box of random things for years that I had yet to play around with. I could use one to act as a webserver and turn LEDs on and off using some webhooks. I pulled one of them out of the box, opened it and started looking at the documentation for them.&lt;/p&gt;

&lt;p&gt;A lot of what I did to get the board set up is outlined in the &lt;a href="https://tutorials-raspberrypi.com/introduction-programming-esp8266-nodemcu-board/" rel="noopener noreferrer"&gt;tutorial I followed&lt;/a&gt;. Getting started with the code was straight forward and got me really far really quickly. At the start I needed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect the board to my computer&lt;/li&gt;
&lt;li&gt;Flash it with some default firmware&lt;/li&gt;
&lt;li&gt;Connect to it using the ESPlorer software&lt;/li&gt;
&lt;li&gt;Write some basic code to connect it to my Wifi&lt;/li&gt;
&lt;li&gt;Write some code so it could handle web requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That got me to this point with the code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After I had it connected to my WiFi and acting as a webserver I started running into problems. I couldn't get the &lt;a href="https://nodemcu.readthedocs.io/en/release/lua-modules/httpserver/" rel="noopener noreferrer"&gt;HTTP Server Module&lt;/a&gt; to load, so didn't have access to nice functions for understanding the requests and responding to them.  I decided I would keep it simple and do basic string manipulation to understand the requests and some basic error handling.&lt;/p&gt;

&lt;p&gt;I also tried to use &lt;a href="https://nodemcu.readthedocs.io/en/release/modules/pwm/" rel="noopener noreferrer"&gt;Pulse Width Modulation&lt;/a&gt; to control the RGB LEDs and had some difficulty understanding the documentation. Once the LEDs were lighting up and controllable I noticed that they were flickering. I stopped using pulse width modulation to control them and used a binary on/off instead. I would have liked to have more control over the colour of the LEDs, but the strip I had bought was fairly dull and didn't look that great even at full brightness.&lt;/p&gt;

&lt;p&gt;The end result is some functional code.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I don't think I will come back to this code (or my other NodeMCU boards) any time soon for other projects.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting OBS to trigger webhooks
&lt;/h1&gt;

&lt;p&gt;I found getting OBS to trigger webhooks was easier than I initially expected. I searched for "OBS Trigger Webhook" and came across an &lt;a href="https://gist.github.com/Parik27/3fca8328812c28375dbc3d05a982fc49" rel="noopener noreferrer"&gt;OBS plugin for sending webhooks to discord&lt;/a&gt; that made me aware of OBS Scripts. I used Parik27's code to figure out the minimum code I needed.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This was a good starting point, but the script wasn't outputting anything or running. Time to look at the &lt;a href="https://obsproject.com/docs/scripting.html" rel="noopener noreferrer"&gt;OBS Scripting documentation&lt;/a&gt;. Reading this I saw what was causing my problems listed as a note.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: On windows, currently only Python 3.6 is supported.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After installing Python 3.6 and setting the Python install directory to point to it, my script was working!&lt;/p&gt;

&lt;p&gt;Now that I had it logging out on events, triggering webhooks was next. Adding in a urllib request on the events hardcoded to the IP Address of the NodeMCU board was going to be more than sufficient for this project.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I want to come back to this code in the future, parameterize it and add in more events that you can trigger webhooks from.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Housing
&lt;/h1&gt;

&lt;p&gt;A spaghetti of electronics isn't exactly a nice sign that you could proudly have sitting on your desk, so I needed to create a housing for it. Fortunately for me I have a Cricut that I can use to cut text out of vinyl with, and my local makerspace has a laser cutter I could use to make the housing.&lt;/p&gt;

&lt;p&gt;Cutting the text on the Cricut was simple. My partner had already pulled it out of the cupboard so I just needed to plug it in, put the text into a project in Cricut Design Space, load my material and then press cut. The machine had been in the cupboard for almost a year, and if it was still there I probably would have painted on the text or engraved it instead.&lt;/p&gt;

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

&lt;p&gt;It took me two attempts to cut the housing out with the laser cutter. The first attempt failed because I had the speed too high and the laser didn't cut all the way through, and I moved the origin so I couldn't do another pass&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. Attempt number two was better and I had a housing!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4f17ftz0a329h618ip9x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4f17ftz0a329h618ip9x.jpg" alt="All the pieces on the workbench being glued together and prepared for assembly"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5bdvobwsn9repm13jisw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5bdvobwsn9repm13jisw.jpg" alt="Assembled with the last part of the glue drying"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Future Improvements
&lt;/h1&gt;

&lt;p&gt;It's always good to look back on a project and think about what could be done differently next time.&lt;/p&gt;

&lt;p&gt;Things I have thought about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Putting the source code into version control.&lt;/strong&gt; It would make it harder for me to hard code values because they would be publicly visible. It would also make it easier to go back when I made a mistake and revert to code I knew worked, instead of needing to fix forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using a different board.&lt;/strong&gt; The NodeMCU Boards are really nice for playing around with, but I'm giving this to someone else. I don't want to have to reprogram the sign when he moves house so I can connect it to his Wifi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not needing direct network access.&lt;/strong&gt; This would make it easier to set up and would allow me to make it go into a party mode remotely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better LEDs.&lt;/strong&gt; The ones I used where the cheapest 5V LED strip I could find. They aren't individually addressable so you can't do cool patterns like rolling colours. Either the NodeMCU board or the LEDs themselves didn't like PWM, which limits the range of colours and patterns I could do. At full brightness you can also see the distinct red, green, and blue, and they aren't as bright as I would have liked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A better housing.&lt;/strong&gt; The housing I made works, but having to open it up to access the board is annoying. Plus having the board and excess wiring inside it gets in the way of the LEDs and casts shadows, though better LEDs could make this a non-issue. I also didn't have access to any frosted acrylic, so did what I could with some non-laser safe acrylic I had, cutting it to size on the bandsaw and leaving the plastic protecting sheets on the backside to act as an opaque layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had a different development board arrive right after I finished this, which is a better platform to work from. I have made version two, which I will give to Ben and write a follow up guide if you want to make one yourself.&lt;/p&gt;

&lt;h1&gt;
  
  
  Delivery
&lt;/h1&gt;

&lt;p&gt;Getting this to Ben and setting up OBS on his machine to use it wasn't as straight forward as I would have liked. I had to talk to his dad to get permission to add it to the network. His dad gave me permission to add it to their guest Wifi, but I need direct access to be able to call the webhooks. After talking to his dad some more and explaining what it is and how it works, he gave me the details for the main network so I could program it in. If I didn't need to upload the program to change the network it connected to, I could have given it to Ben without the details programmed in and gotten him to do that himself.&lt;/p&gt;

&lt;p&gt;Delays caused by unexpected car trouble and an outbreak of Covid19 in Sydney mean that I didn't get to give this to Ben when we had initially planned to catch up, so instead he got the improved version two that I haven't written about yet&lt;sup id="fnref3"&gt;3&lt;/sup&gt;, and he loves it! Version two is easier to reprogram to connect it to wifi, but we encountered issues when doing that. The new board I started using doesn't like connecting to Channel 12 or 13 which it appears Ben's home network was on (it was set to auto). It took around 40 minutes of me and his dad going back and forth trying some different settings to get it to work. Ben also uses Streamlabs OBS, which is different to OBS Studio and doesn't have the scripts menu or something similar. Instead of automating it, I set it up so that he has a simple UI that he can use to control it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwps1a7dp1mxqn2hb5fhd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwps1a7dp1mxqn2hb5fhd.jpg" alt="Version two sitting on top of Ben's PC lit up as a rainbow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkmwem7d0vepxbfarlscl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkmwem7d0vepxbfarlscl.jpg" alt="Version one next to an in progress version two."&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;I got my idea from Christine on the &lt;a href="https://www.twitch.tv/twilio" rel="noopener noreferrer"&gt;Twilio Remote Participants&lt;/a&gt; stream when she talked about the &lt;a href="https://www.youtube.com/watch?v=8_FdR-L7qrs" rel="noopener noreferrer"&gt;light to indicate of she is in a meeting&lt;/a&gt; she made. This stream has been something I look forward to while I haven't been able to travel and see friends and I still think &lt;a href="https://dev.to/philnash"&gt;Phil&lt;/a&gt; should consider the pull request I made to the video chat application he made on his stream and add the "CRIME" reaction to it. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;I found out on my next makerspace visit that the lens and the mirrors had a light coating of smoke and were absorbing some of the lasers power, making it cut less. I now know how to check and clean these to help maintain the laser cutter. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;I am planning on writing about the version two build as a guide that you could follow, with a different trigger for the lighting (I'm thinking something data driven). ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>showdev</category>
      <category>electronics</category>
      <category>christmas</category>
    </item>
    <item>
      <title>The dangers of choosing the wrong identifier for your users when federating logins</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Mon, 27 Jul 2020 06:09:43 +0000</pubDate>
      <link>https://dev.to/mitchpommers/the-dangers-of-choosing-the-wrong-identifier-for-your-users-when-federating-logins-4p15</link>
      <guid>https://dev.to/mitchpommers/the-dangers-of-choosing-the-wrong-identifier-for-your-users-when-federating-logins-4p15</guid>
      <description>&lt;p&gt;&lt;strong&gt;Preface:&lt;/strong&gt; I was going to title this something along the lines of "Twitter's username clean up is dangerous", but I felt that made it sound too much like what twitter was doing was the dangerous part, and not that other applications failing to follow good practice puts their user data at risk, regardless of what twitter is doing. I also started writing this and then promptly forgot about it for 8 months.&lt;/p&gt;

&lt;p&gt;If you haven't seen what twitter did, they &lt;a href="https://www.theverge.com/2019/11/26/20984328/twitter-removing-inactive-accounts-usernames-available-date"&gt;removed inactive accounts to free up the usernames&lt;/a&gt;. On top of the the issues that others raised with this, freeing up twitter handles made it possible for someone to potentially get access to data that is not theirs.&lt;/p&gt;

&lt;p&gt;There's a lot of maybes there. I don't think this has happened, but it is theoretically possible. It is not because of a mistake that twitter has made. It is possible because people changing usernames could uncover issues where a third party application is not linking accounts from twitter as an identity provider correctly.&lt;/p&gt;

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

&lt;p&gt;If you use twitter as an Identity Provider for your application, you have to use a piece of information twitter gives you to link between a twitter account and your application. If you use their twitter username (or email) as this key between your user will experience issues if they change it. If someone else starts using a previously used twitter handle they also gain access to the old users information in your application.&lt;/p&gt;

&lt;p&gt;Instead of using a username or email address between you application and an identity provider, which could change, you should look at a field that can't change. If you are using OIDC, you should use the &lt;strong&gt;subject&lt;/strong&gt; claim (and other claims that don't change).&lt;/p&gt;

&lt;p&gt;If you think that users information doesn't change, between starting this blog post 8 months ago and finishing it, I lost access to data in one application because I changed the email address I use for Facebook.&lt;/p&gt;

</description>
      <category>security</category>
      <category>identity</category>
    </item>
    <item>
      <title>My First Website (A look back at what I did at the start of the decade)</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Wed, 27 Nov 2019 03:18:20 +0000</pubDate>
      <link>https://dev.to/mitchpommers/my-first-website-a-look-back-at-what-i-did-at-the-start-of-the-decade-5ch5</link>
      <guid>https://dev.to/mitchpommers/my-first-website-a-look-back-at-what-i-did-at-the-start-of-the-decade-5ch5</guid>
      <description>&lt;p&gt;At the start of the year I was planning to move across the country and needed to get rid of things. One of those things was my old HP Microserver that I used as a NAS. I couldn't remember putting anything important on it that I wanted to keep, so sent it with my parents to my brother so that he could put it to use. Him being the amazing person he is, checked to see what was on it before formatting it and found some of my personal files from 2014. The other night we finally got all of those files across the country and back to me, and spent some time looking through them together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F9WqNtF9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F9WqNtF9.jpg" alt="Picture of my microserver in my home network "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Among them is the code from my first website. Unfortunately I didn't know how to use version control back then (though I had installed mercurial server and did have a Bitbucket account), so the revision history has been lost. Fortunately though, I did keep some screenshots!&lt;/p&gt;

&lt;p&gt;Time for some archaeology!&lt;/p&gt;

&lt;p&gt;I started playing with web hosting around 2009 while I was in high school. I had an old Dell desktop, that one of the computer technicians at school gave me, sitting in the corner of my bedroom that I used as my server. A network cable ran out of my bedroom door, across the doorway for the bathroom and plugged in to a switch at the family computer desk that I had bought.&lt;/p&gt;

&lt;p&gt;I set it up a WAMP server (Windows, Apache, MySQL and PHP), configured our router to run DynDNS and started hosting a proxy on it, so I could get around the school firewall. The IT Department knew I was doing this, and never blocked it, but they did talk to me about it and tell me that I shouldn't be bypassing the school's proxy.&lt;/p&gt;

&lt;p&gt;In 2010 I got bored of just running proxies and wanted to build my own website, so I started by looking at different websites that existed and drawing designs that I liked. I then wrote all the HTML and CSS for the layout in Notepad++, relying on search engines to help me learn the syntax. I didn't want to have to update HTML files every time so I built my own CMS system, including the login screen, myself. This was a major security mistake, as one of my friends was able to deface my website within a week.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fn2eGtKn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fn2eGtKn.png" alt="My desk at the start of 2011"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2011 I realized I didn't want to have to manage my own web server, so I bought a domain and paid for some web hosting with my first ever debit card. And with that I decided to do a complete website redesign. And I have pictures of it!&lt;/p&gt;

&lt;p&gt;I won't explain each image, but you can see the progression in the images below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4cf0RO5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4cf0RO5.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FNF25TYi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FNF25TYi.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FO5CgvOo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FO5CgvOo.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FyYg4Uv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FyYg4Uv3.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F1OiiYqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F1OiiYqe.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4lKQsru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4lKQsru.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FfZwAG5Y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FfZwAG5Y.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FVSUlK5s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FVSUlK5s.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also kept my CMS system and started updating it to use a database in the backend instead of the flat files I had been using. This was great for making it easier to add new pages, but as a result I lost all of the content from my website, because I never took a database backup.&lt;/p&gt;

&lt;p&gt;My home server ended up becoming a minecraft server for me and my friends, and I ended up working on some other projects (including building a job management system). I will have to do a deep dive on some of those projects, and put the code into public source control so that others can learn from my mistakes.&lt;/p&gt;

&lt;p&gt;Footnote: If any one of the ten other active CaL members from 2010-2012 reads this, hi!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>My Graveyard of Abandoned Posts</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Thu, 07 Nov 2019 00:27:35 +0000</pubDate>
      <link>https://dev.to/mitchpommers/my-graveyard-of-abandoned-posts-248o</link>
      <guid>https://dev.to/mitchpommers/my-graveyard-of-abandoned-posts-248o</guid>
      <description>&lt;p&gt;I've started a heap of draft posts here. Some are just just post titles, others are starting to get fleshed out. Before I go and delete them to clean up my dashboard, I thought I would list them out here with mini descriptions for what it was supposed to be about. &lt;/p&gt;

&lt;h3&gt;
  
  
  My Journey So Far
&lt;/h3&gt;

&lt;p&gt;A timeline starting when I started to get into technology and acquired my first PC (from dumpster diving). It would talk about the communities I participated in, the jobs I have had and the different skills I have developed. I think I will keep this in my dashboard and work on fleshing it out more.&lt;/p&gt;

&lt;h3&gt;
  
  
  101 ways to do passwords wrong
&lt;/h3&gt;

&lt;p&gt;A listicle on everything to do with passwords that people (developers and users) do wrong. Number 5 will shock you!&lt;/p&gt;

&lt;h3&gt;
  
  
  Startups Guide On When To Use "X"
&lt;/h3&gt;

&lt;p&gt;Basically a long form version of this tweet thread.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zi4dBbPH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1120471439902162945/ooJJCnDy_normal.png" alt="Chief Problem Solver Mitch profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Chief Problem Solver Mitch
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="comment-mentioned-user" href="https://dev.to/mitchpommers"&gt;@mitchpommers&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      &lt;a href="https://twitter.com/meacod"&gt;@meacod&lt;/a&gt; &lt;a href="https://twitter.com/evanderkoogh"&gt;@evanderkoogh&lt;/a&gt; When you stop talking about needing something and start talking about the tradeoffs and benefits of using it instead of something else
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      00:39 AM - 18 Jun 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1140781061103734784" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WwRENZp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1140781061103734784" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PFD0MJBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1140781061103734784" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6wx1BHu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  "My Door Is Always Open" - getting feedback
&lt;/h3&gt;

&lt;p&gt;I dislike the phrase "my door is always open". It puts it onto another person to provide feedback, when you really should be going out and seeking feedback. For other people to really feel safe providing feedback, they need to see that feedback is listened to and something happens as a result of it. Basically, if you aren't getting feedback on something, go looking for it!&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Pipeline" Problem
&lt;/h3&gt;

&lt;p&gt;This is another post i want to work more on and finish, especially after how one of my friends put it the other week. Claiming that the reason you don't have diversity in your team or organisation because there aren't enough people interested is a hand-wavy way of saying it's not your problem. What about the people you already have, how do they feel, are you providing them the opportunities to learn and grow?&lt;/p&gt;

&lt;p&gt;This is another post I will keep around to flesh out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing Expectations
&lt;/h3&gt;

&lt;p&gt;At the end of last year my graphics card died. No big deal, I just took it back to the shop I bought it from to get them to fix it under warranty. What followed was 3 months of me chasing them up to find out what was happening with it. If all they had said was "we expect an update in 4 weeks", I would have been a lot happier with the service.&lt;/p&gt;

&lt;h3&gt;
  
  
  In the day of the T-Shaped Engineer, the resume should be dead
&lt;/h3&gt;

&lt;p&gt;I think I could confidently say I have had the responsibilities of over 15 distinct job titles during my 10 years working in tech. All at only 5 companies. It doesn't map nicely onto a 2 page resume. I have to be selective about what skills I do and don't include. LinkedIn helps a little, but there really needs to be a better way to convey this information.&lt;/p&gt;

&lt;h3&gt;
  
  
  At some point in time, you will need to trust your engineers
&lt;/h3&gt;

&lt;p&gt;I've worked for several people who don't trust anyone who works for them. At some point in time they need to trust the people they hire otherwise no work will get done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who is in your team and what do they do outside work?
&lt;/h3&gt;

&lt;p&gt;A question I like to ask in interviews. Do the people hiring really know the people in their team and what they do out of the office? I don't need to hear something deep, just some hobbies or holidays that their teammates have had. It helps convince me that you can bring your full self to work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who is after your data?
&lt;/h3&gt;

&lt;p&gt;A discussion about different threat actors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Simple Patterns Not Complex Code
&lt;/h3&gt;

&lt;p&gt;I've seen some really complicated libraries that were supposed to make development easier for other teams. Instead of that you could define simple guardrails and guidelines and let the teams work within them, trusting that they will do the right thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community Building
&lt;/h3&gt;

&lt;p&gt;My experiences in gaming communities, student clubs and running events. The importance of getting the right people involved at the start so you grow organically with the right values. The importance of clearing the path and letting doers do and training them to lead, instead of forcing them to.&lt;/p&gt;

&lt;h3&gt;
  
  
  My past projects
&lt;/h3&gt;

&lt;p&gt;Things I have built myself. I really want to write this, but all the files I want for screenshots and to jog my memory are stored on my brothers machine on the other side of the country and he hasn't sent them to me yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security is everybody's job
&lt;/h3&gt;

&lt;p&gt;Listicle of things that everyone is able to do to improve the security of the systems they are building.&lt;/p&gt;

&lt;h3&gt;
  
  
  The pit of success
&lt;/h3&gt;

&lt;p&gt;Making it hard for people to fail. Alternatively, making them fail into the correct place.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to be lazy and get paid for it
&lt;/h3&gt;

&lt;p&gt;This is something I've been working on for over a year. It's a piece about reducing the amount of work you have to do through automation, simplification and just stopping doing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minimum Viable Engineering
&lt;/h3&gt;

&lt;p&gt;Engineering standards and how they relate to MVP's.&lt;br&gt;
Liquid error: internal&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplicity is a feature
&lt;/h3&gt;

&lt;p&gt;I remember reading a blog post about a timetable app and how they asked users what features they wanted. With over 50 new feature requests, adding all of them would remove the one biggest feature of the app; It's simplicity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build versus Deploy
&lt;/h3&gt;

&lt;p&gt;I've seen teams that treat these two topics as one. There are clear boundaries between the two but if you're not careful you can accidentally merge them into one, which makes it harder to do some things.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Cost Of Volunteering
&lt;/h3&gt;

&lt;p&gt;I've volunteered at a lot of events this year and wanted to write up what it cost me to volunteer, because it definitely was not free. I need to start tracking my volunteering expenses better, but this year it has cost me at least 3 tanks of fuel and a day of parking in the city.&lt;/p&gt;

</description>
      <category>graveyard</category>
    </item>
    <item>
      <title>How Computers Shuffle - Explained with Cards and Dice</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Mon, 04 Nov 2019 09:20:36 +0000</pubDate>
      <link>https://dev.to/mitchpommers/how-computers-shuffle-explained-with-cards-and-dice-3lhp</link>
      <guid>https://dev.to/mitchpommers/how-computers-shuffle-explained-with-cards-and-dice-3lhp</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;This is meant as a hands-on way of looking at different shuffling methods and the steps a computer takes to do them. It is meant as a way of introducing the ideas of &lt;a href="https://en.wikipedia.org/wiki/Algorithmic_efficiency"&gt;algorithmic efficiency&lt;/a&gt; without talking about &lt;a href="https://en.wikipedia.org/wiki/Big_O_notation"&gt;Big O notation&lt;/a&gt;. For more detail about the performance of these algorithms, or for further reading, I suggest Mike Bostock's blog post on the &lt;a href="https://bost.ocks.org/mike/shuffle/"&gt;Fisher-Yates Shuffle&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Materials
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;6 different cards&lt;/li&gt;
&lt;li&gt;Paper with 1 to 6 written on it&lt;/li&gt;
&lt;li&gt;Dice&lt;/li&gt;
&lt;li&gt;Paddle pop stick&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see the materials I used in the header image for this post.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note on Dice Rolls:&lt;/em&gt; At times we don't want to roll a number between 1 and 6. Instead we want a number between 1 and something less than 6. To do this, we can roll the dice and ignore results that we don't want and instead roll the dice again. Alternatively, you can do what I did and make 5, 4, 3, 2 and 1 sided dice by putting crosses on the excess sides.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Do Humans Shuffle
&lt;/h1&gt;

&lt;p&gt;There are several techniques that people use to shuffle. Two techniques that you may have seen or used are smooshing and the overhand shuffle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smooshing&lt;/strong&gt; - spread all of the cards out on the table and move them around pushing them into each other. Keep mixing them for a minute. Gather them up into a single pile.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LqhZ7o0K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/jJtiOQk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LqhZ7o0K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/jJtiOQk.gif" alt="An example of smooshing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overhand Shuffle&lt;/strong&gt; - Hold all the cards in one hand, grab some and then drop them back into the deck. Keep doing this until you're ready.&lt;/p&gt;

&lt;p&gt;Numberphile has a great video on &lt;a href="https://www.youtube.com/watch?v=AxJubaijQbI"&gt;different shuffling techniques&lt;/a&gt; and how long you need to shuffle for to ensure that the deck is in a random order.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Can Computers Shuffle
&lt;/h1&gt;

&lt;p&gt;Computers don't have hands that they can use, or physical cards to move around. So how can they shuffle?&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy Naive Shuffle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Process:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Start with a deck of cards laid out and an empty deck to put the shuffled cards into.&lt;/li&gt;
&lt;li&gt;Roll a six sided dice&lt;/li&gt;
&lt;li&gt;Check if the card has already been shuffled&lt;/li&gt;
&lt;li&gt;If it hasn't, move it to the shuffled pile&lt;/li&gt;
&lt;li&gt;Repeat until no cards are left to be shuffled&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h2f07e6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/2o7Ss7P.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h2f07e6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/2o7Ss7P.gif" alt="Naive Shuffle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Lazy Naive Shuffle Questions:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;How many times did you need to roll the dice?&lt;/li&gt;
&lt;li&gt;What happens if you never roll a six?&lt;/li&gt;
&lt;li&gt;What would happen if you were shuffling a deck of 52 cards? How many times would you roll a number that had already been shuffled?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Better Naive Shuffle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Process:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Start with a deck of cards laid out and an empty deck to put the shuffled cards into.&lt;/li&gt;
&lt;li&gt;Roll an n-sided dice (n is how many cards are left to be shuffled)&lt;/li&gt;
&lt;li&gt;Move the card in that position to the shuffled pile&lt;/li&gt;
&lt;li&gt;Move cards left one at a time to fill in the now empty space&lt;/li&gt;
&lt;li&gt;Repeat until all cards are shuffled&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tWSnKVrd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/GrURwvH.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tWSnKVrd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/GrURwvH.gif" alt="A Less Naive Shuffle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Naive Shuffle Questions:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;How many times did you need to roll the dice? Why was this?&lt;/li&gt;
&lt;li&gt;What would happen if you were shuffling a deck of 52 cards? How many cards would you need to move if you rolled a 1?&lt;/li&gt;
&lt;li&gt;What are the advantages of this approach over the Lazy Naive Shuffle? What are the disadvantages?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Fisher-Yates Shuffle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Process:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Start with a deck of cards laid out with a marker at the end to show which cards have been shuffled.&lt;/li&gt;
&lt;li&gt;Roll an n-sided dice (n is how many cards are left to be shuffled)&lt;/li&gt;
&lt;li&gt;Swap the card in that position with the last unshuffled card&lt;/li&gt;
&lt;li&gt;Move the shuffled marker forwards one space&lt;/li&gt;
&lt;li&gt;Repeat until no cards are left to be shuffled&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0UwL6FCe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/frxy0kC.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0UwL6FCe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/frxy0kC.gif" alt="Fisher-Yates Shuffle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fisher-Yates Shuffle Questions:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;How many times did you need to roll the dice? Why was this?&lt;/li&gt;
&lt;li&gt;What would happen if you were shuffling a deck of 52 cards? How many times would you need to move cards if you rolled a 1?&lt;/li&gt;
&lt;li&gt;Is this still shuffling because you are swapping cards instead of moving them to a new deck?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Answers/Discussion Ideas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lazy Naive Shuffle:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;You likely needed to roll the dice more than six times, unless you got really lucky.&lt;/li&gt;
&lt;li&gt;If you never roll a six, you will never shuffle all of the cards. The same happens if you only ever roll a six. These situations are unlikely, but possible.&lt;/li&gt;
&lt;li&gt;After half the cards (26 cards) have been shuffled, there is a 50% chance of rolling a number that has already been shuffled. Shuffling more cards gives you more chances to roll the same number twice making shuffling slower the more cards you start with.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Better Naive Shuffle:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;You only needed to roll the dice six times. You could do this because now instead of rolling to fill a space, you would move the cards to fill the space.&lt;/li&gt;
&lt;li&gt;If you rolled a 1, you would need to move every single unshuffled card forward one space before rolling again. You end up needing to move most of the cards several times while shuffling. If you only ever rolled a 1, then you need to move the last card 52 times, the card before it 51, then 50 and so on.&lt;/li&gt;
&lt;li&gt;This approach is better as you only need to roll once for each card. It is worse because now you need to move cards multiple times.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Fisher-Yates Shuffle:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;You only needed to roll the dice six times. You could do this because you were always rolling top pick one of the unshuffled cards.&lt;/li&gt;
&lt;li&gt;If you rolled a 1, you would only need to swap the first card with the last unshuffled card. This means that for a deck of 52 cards, you only swap/move cards 52 times.&lt;/li&gt;
&lt;li&gt;This is still shuffling. Every time you roll the dice there is an equal chance that one of the unshuffled cards will be picked and moved. They do not need to stay in the order they started in and they do not need to start in order. See the below for an example of items being shuffled that have no clear order.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SRbIJIZp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/svRwPyL.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRbIJIZp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.imgur.com/svRwPyL.gif" alt="Fisher-Yates Shuffle starting with random items"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>educational</category>
    </item>
    <item>
      <title>My First Experiences Deploying Things</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Mon, 14 Oct 2019 23:37:25 +0000</pubDate>
      <link>https://dev.to/mitchpommers/my-first-experiences-deploying-things-3fkg</link>
      <guid>https://dev.to/mitchpommers/my-first-experiences-deploying-things-3fkg</guid>
      <description>&lt;p&gt;This is my response to the following tweet, asking about developer's first experiences deploying something. &lt;br&gt;
&lt;/p&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--KXscxhJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1151859809911623681/aHOppbdi_normal.png" alt="Hayley van Waas profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Hayley van Waas
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @hayleyavw
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Devs, do you remember your first experience deploying something? Share your experiences, I'd like to share it with my students :)
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      11:38 AM - 14 Oct 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1183708646871449600" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WwRENZp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1183708646871449600" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PFD0MJBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1183708646871449600" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6wx1BHu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;h1&gt;
  
  
  Very First Personal Websites (2010)
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;What:&lt;/strong&gt; Several PHP websites, built completely from scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; I wanted to learn how to make dynamic websites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment Process:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collect an old PC from school&lt;/li&gt;
&lt;li&gt;Wipe it and install Windows 7 onto it&lt;/li&gt;
&lt;li&gt;Set up WAMP (Windows, Apache, MySQL, PHP) Server&lt;/li&gt;
&lt;li&gt;DynDNS set up on our home router&lt;/li&gt;
&lt;li&gt;.tk domains hiding the DynDNS domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Things that went wrong:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The network cable rang across the bathroom door which made my parents unhappy with the trip hazard&lt;/li&gt;
&lt;li&gt;WAMP was hard to set up and run&lt;/li&gt;
&lt;li&gt;OS Patching? What's that!&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  C# IRC Bot (2010/11)
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;What:&lt;/strong&gt; An IRC bot that I wrote without any libraries that could sit in a server with me and around 5 other people and their bots. All it would do is respond to commands (and log messages).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Everyone else in the server had one and I wanted to learn some C#.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment Process:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile code on my machine&lt;/li&gt;
&lt;li&gt;Copy it to the server from before&lt;/li&gt;
&lt;li&gt;Run the executable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Things that went wrong:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It would occasionally crash and I would need to start it again&lt;/li&gt;
&lt;li&gt;Still not OS patching&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Stocktake System (2011/12)
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;What:&lt;/strong&gt; A rewrite of my works stocktake system, with the aim of making it easier/faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Stocktake would take an entire day because you had to print off a sheet, find all the items that we had and mark them off, and then go and select all the items that didn't exist on the web interface and select them. New system was to enter the IDs of every item we could find, and then press "complete stocktake" which would take all of the items we didn't find and mark them as lost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment Process:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write code on the in-house developers machine&lt;/li&gt;
&lt;li&gt;Copy it to the web server&lt;/li&gt;
&lt;li&gt;Test it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Things that went wrong:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accidentally screwed up the entire production database (Thank goodness I took a backup first)&lt;/li&gt;
&lt;li&gt;No one else wanted to use the software I wrote even though it was faster (writing it, testing it and doing a stocktake only took me a Saturday morning)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Websites for myself and others (2012-2015)
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;What:&lt;/strong&gt; Several websites (static and PHP)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; People wanted websites and I knew how to make them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment Process:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up an account with a hosting provider&lt;/li&gt;
&lt;li&gt;Configure databases in cPanel if I needed them&lt;/li&gt;
&lt;li&gt;FTP the code to the server&lt;/li&gt;
&lt;li&gt;Check it all&lt;/li&gt;
&lt;li&gt;Quickly fix anything that I needed to fix&lt;/li&gt;
&lt;li&gt;Zip up the website locally and keep it as a backup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Things that went wrong:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One hosting provider I was required to use didn't stop you from being able to see others websites code (and therefore their database passwords) so I had to convert one website from wordpress to static. All 300+ pages of it&lt;/li&gt;
&lt;li&gt;I would occasionally have links set wrong&lt;/li&gt;
&lt;li&gt;To save money on hosting providers I was writing PHP to split all my domains to different folders on the hosting provider. And that would regularly have edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How I do deployments now
&lt;/h1&gt;

&lt;p&gt;Looking back all of my deployments were manual, poorly tested, and very low impact if something went wrong (with the exception of both 300+ static page sites). Last week I wrote about one deployment I did, and so much has improved in them. You can read about that below:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mitchpommers" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lFuLSzFz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--NycnFA6f--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/194709/f0c124fe-5b86-4a14-aa27-a28cd0034117.png" alt="mitchpommers image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mitchpommers/halloween-story-the-friday-deploy-1f6a" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Halloween Story: The Friday Deploy&lt;/h2&gt;
      &lt;h3&gt;Mitch Pomery (he/him) ・ Oct  3 '19 ・ 5 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#spooktober&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>beginners</category>
      <category>deployments</category>
    </item>
    <item>
      <title>Halloween Story: The Friday Deploy</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Thu, 03 Oct 2019 23:35:37 +0000</pubDate>
      <link>https://dev.to/mitchpommers/halloween-story-the-friday-deploy-1f6a</link>
      <guid>https://dev.to/mitchpommers/halloween-story-the-friday-deploy-1f6a</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While it does draw inspiration from several real events this story is a work of fiction. After the story are some of my thoughts on Friday deploys.&lt;/p&gt;

&lt;p&gt;It's Friday, 10AM. Standup has finished and I'm looking at the log files on our test servers. Hang on, our log files aren't rotating. Is this happening in production? I look. This is bad. The disk is going to be full before Monday unless we do something. I call over Bethany and Thomas and show them what I've found.&lt;/p&gt;

&lt;p&gt;We call incident management to tell them about the issue. They tell us to do what we have to to fix it and end the call. We agree that we should aim to fix this before 11:30. We have a team lunch that we don't want to miss.&lt;/p&gt;

&lt;p&gt;Thomas starts raising a change request. He needs to find someone from another team to approve it and finds Alexandra. She has reviewed our changes before and knows how our team works. He tells her that we will be sending her a change for approval around 11.&lt;/p&gt;

&lt;p&gt;Meanwhile Bethany and I are investigating the issue. The config changed and so stopped rotating our log files. It will be a simple thing to fix. How long has this issue existed? Were we lucky to have not had issues before? We look back at our change history and find it. The issue has existed for 3 months.&lt;/p&gt;

&lt;p&gt;10:30AM. All we need to do is change one line in a config file. I make the change. Our build system kicks off.&lt;/p&gt;

&lt;p&gt;Tests run.&lt;br&gt;
Package built.&lt;br&gt;
Deployment initiated.&lt;/p&gt;

&lt;p&gt;We watch the deployment to our Test environment. All tests pass. Test environment deployment completed. Now to our Stage environment.&lt;/p&gt;

&lt;p&gt;I click "Deploy To Stage". Our deployment script raises a change request and The deployment steps kick off. All the tests pass. Stage environment deployment complete.&lt;/p&gt;

&lt;p&gt;11AM. Thomas links the stage change to our production change and goes to submit it. "Change must be more than 10 minutes in the future". None of us have ever seen that message before. Thomas sets the change to start at 11:12 and submits it again. Bethany messages to let Alexandra know. The change gets approved almost immediately.&lt;/p&gt;

&lt;p&gt;Incident management calls back.&lt;br&gt;
"How is everything going?"&lt;br&gt;
"Good, we're waiting for our change window to start"&lt;br&gt;
"Why did you do that? You can get approval later."&lt;br&gt;
"Our normal process is fast enough so we decided to do it."&lt;br&gt;
"Oh, okay."&lt;br&gt;
The call ends.&lt;/p&gt;

&lt;p&gt;It's time for our change window. We hit the deploy button and wait.&lt;/p&gt;

&lt;p&gt;The deployment kicks off.&lt;br&gt;
We wait.&lt;br&gt;
The tests run.&lt;br&gt;
We wait.&lt;/p&gt;

&lt;p&gt;Tests pass. Change complete! We head to the lifts to leave the office for our team lunch.&lt;/p&gt;

&lt;p&gt;Incident Management calls me at 12PM. They came to see our team and couldn't find us and wanted to know how the incident was going. I let them know that we are out for a team lunch and the issue is fixed.&lt;/p&gt;

&lt;p&gt;2PM. Team lunch was great. I had the lamb shank. Everyone headed straight home afterwards. I lived close to the restaurant so am home first. I log into work and close the change.&lt;/p&gt;




&lt;h1&gt;
  
  
  My Thoughts On Friday Deploys
&lt;/h1&gt;

&lt;p&gt;This isn't a scary story. Everyone is happy with what is happening and nothing goes wrong. This is what changes should be like. Deployments shouldn't be scary and dangerous. They should be something that is normal and boring.&lt;/p&gt;

&lt;p&gt;I have worked in a team where everyone worked hard to build confidence in our pipelines and processes. We were always looking for ways to build more confidence. We wanted to stay at the point where we could diagnose issues quickly and deploy fixes even faster.&lt;/p&gt;

&lt;p&gt;We didn't start there.&lt;/p&gt;

&lt;p&gt;We started with our deployments being scary and dangerous. We did them at 7PM in the middle of the week so that if any issues occurred they wouldn't cause a major impact. Our deployments would fail without warning. Doing the same thing again would work.&lt;/p&gt;

&lt;p&gt;One change we did started at 1PM on Valentines Day and should have finished by 2PM. Every time we deployed, the new version would fall over. We would look at it, it would be a pipeline problem, so we would try again. We extended the change window 3 times and eventually had to call someone from the networks team for help. At 8PM we finally had a successful deployment. My valentines day plans disrupted, my workmates evening gone, and the network engineers picnic date disturbed.&lt;/p&gt;

&lt;p&gt;After this, we worked to improve our deployments. Infrastructure was causing the failures, but the application was what we were changing. So we split our infrastructure from our application. This gave us an immediate improvement.&lt;/p&gt;

&lt;p&gt;We slowly built more confidence.&lt;/p&gt;

&lt;p&gt;Infrastructure deployments still failed too often, so we investigated. We found that the timeout was too low, which caused the deployment fail on a random step. So we looked at what the timeout should be and gave it a buffer. That made our infrastructure deployments more stable.&lt;/p&gt;

&lt;p&gt;We looked back to our application deployments. We had integration tests, but they had to be manually run. So we automated them. We looked at what tests we had and saw places where we could add more. Everyone in the team worked to write these tests together to give us all more confidence.&lt;/p&gt;

&lt;p&gt;We found holes in our monitoring and alerting. There were metrics that we cared about that we couldn't see. So we made them easier to see. And we added alerts on them to tell us when they weren't right. More confidence.&lt;/p&gt;

&lt;p&gt;We looked at the entire process from beginning to end. We could make a change and deploy it to our stage environment the same day. Moving that change to production would then take a week due to change processes outside the control of our team.&lt;/p&gt;

&lt;p&gt;We spoke to change management to find out what we could do to reduce the lead time. They came back with suggestions to template our changes and re-evaluate the risk classification. We looked at how we were classifying our changes and found we were erring on the side of caution. Our changes were safer than ever before. We standardized our steps and created a template. The change management team removed the lead time after we started using the template.&lt;/p&gt;

&lt;p&gt;We talked to the people approving our changes and found out what they cared about. We were doing changes so often and they weren't failing. Having to approve our changes became a pain for the other teams. They wanted to be removed, and only added if we thought the change we were making required extra scrutiny, so we removed them. We had built enough confidence in our system that they were happy.&lt;/p&gt;

&lt;p&gt;After a year of slowly building confidence, we were finally at the point where we could make a change and have it safely deployed to production the same day.&lt;/p&gt;

&lt;p&gt;And then we did have an incident where we had to make a change and deploy it the same day. And we did leave as a team for team lunch as soon as it finished.&lt;/p&gt;

&lt;p&gt;But we weren't done. There were always things we could find that would build our confidence. We investigated contract tests, performance tests and UI tests. We weighed up the effort to implement them against the confidence it would build. Where it made sense we added them to our pipelines. There is always room for more improvement, but we were at the point where we would happily deploy on a Friday.&lt;/p&gt;

&lt;p&gt;Should you deploy on a Friday?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you've got the confidence in your build and deploy pipelines, go for it.&lt;/li&gt;
&lt;li&gt;If you don't, go build some confidence.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>spooktober</category>
      <category>devops</category>
    </item>
    <item>
      <title>What would it take to increase the password max length limit?</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Sun, 22 Sep 2019 22:26:38 +0000</pubDate>
      <link>https://dev.to/mitchpommers/what-would-it-take-to-increase-the-password-max-length-limit-23lj</link>
      <guid>https://dev.to/mitchpommers/what-would-it-take-to-increase-the-password-max-length-limit-23lj</guid>
      <description>&lt;p&gt;In the last post we established that &lt;a href="https://dev.to/mitchpommers/password-max-length-limits-are-dumb-but-we-need-them-1dpp"&gt;password maximum length limits are good&lt;/a&gt; if they are set at a reasonable limit. They enable testing to ensure that passwords can not be set to longer than your systems (infrastructure, libraries, hashing algorithms and your own code) allow. Lets look at the restrictions used by some Australian Banks and determine what steps to take to bring them in line with the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html"&gt;OWASP recommendations for password length&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To start we need to know what the current rules and limits are. I found the length restriction for 8 banks and have summarized the information below.&lt;/p&gt;

&lt;h1&gt;
  
  
  Password Length Limits
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bank&lt;/th&gt;
&lt;th&gt;Input Field Limit&lt;/th&gt;
&lt;th&gt;Password Limit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ANZ&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bankwest&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bendigo Bank&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BoQ&lt;/td&gt;
&lt;td&gt;255&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commonwealth Bank&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Macquarie&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;td&gt;256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suncorp&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Westpac&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note: NABs &lt;a href="https://www.nab.com.au/about-us/security/cyber-safety-tips-for-you/six-simple-ways-to-protect-your-passwords"&gt;password tips page&lt;/a&gt; flexes on the ability to set a 17 character password. As I was unable to find their password rules I have left them out from this list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grouping Them
&lt;/h2&gt;

&lt;p&gt;We can split the banks into several groups:&lt;/p&gt;

&lt;p&gt;Those that have a low max length and a limited input length:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bankwest&lt;/li&gt;
&lt;li&gt;Bendigo Bank&lt;/li&gt;
&lt;li&gt;Commonwealth Bank&lt;/li&gt;
&lt;li&gt;Westpac&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those with a low max length and a higher input length:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ANZ&lt;/li&gt;
&lt;li&gt;BOQ&lt;/li&gt;
&lt;li&gt;Suncorp&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Macquarie Bank, which is already in a good position&lt;/p&gt;

&lt;h1&gt;
  
  
  Going from Low to Woah!
&lt;/h1&gt;

&lt;p&gt;To increase the length limit we are going to need to make some changes. Our assumptions for doing this are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passwords are currently stored hashed&lt;/li&gt;
&lt;li&gt;Your password is not sent to an ancient mainframe (with a low rate of change and a high cost for change)&lt;/li&gt;
&lt;li&gt;There is no technical limitation preventing a higher password limit&lt;/li&gt;
&lt;li&gt;There is only one system uses the password&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Low max length and a limited input length
&lt;/h2&gt;

&lt;p&gt;The first step for working towards a better state is increasing the length of the password that that can be entered on login. If we started with the password set and change screens instead, then users would be able to create passwords longer than they could log in with. This would cause issues. Increasing the login screen limit can also cause issues.&lt;/p&gt;

&lt;p&gt;Take, for example, the password: "bankpassword123456" (18 characters)&lt;/p&gt;

&lt;p&gt;Imagine that this is my internet banking password.&lt;/p&gt;

&lt;p&gt;It is what I typed in when I registered and it is what I type in every time I go to log in.&lt;/p&gt;

&lt;p&gt;But my bank only has a 16 character password limit.&lt;/p&gt;

&lt;p&gt;When I first set my password, I typed in those 18 characters on my keyboard. The field length limit stopped the last two characters from being entered. Then only 16  characters out of my 18 character password were sent to the server. Their login screen also limits me to 16 characters. I type in 18 characters every time and log in fine though. To me, 18 characters is correct and 16 is not.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What I type: bankpassword123456&lt;br&gt;
What I see: ****************&lt;br&gt;
What the server sees: bankpassword1234&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So how do you increase the password field length when users may be typing in characters that your server does not see? Passwords are not stored in plain text so you can not identify the affected users ahead of time. You will need to determine a plan to handle this case.&lt;/p&gt;

&lt;p&gt;You might think that this is an edge case. I have seen a poorly handled removal of a password length restriction. It caused chaos. Users were unable to log in and they had no idea why. There were hundreds of calls to the support line from users trying to log in. In the end we had to reinstate the limit to restore some order.&lt;/p&gt;

&lt;p&gt;Your options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attempting to communicate with every customer&lt;/li&gt;
&lt;li&gt;Spend time determining which customers will be impacted&lt;/li&gt;
&lt;li&gt;prepare for an increase in calls from users who are locked out&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have chosen your option and spent time planning, then you can get to executing it.&lt;/p&gt;

&lt;p&gt;This is a lot of work for no new features, enhancements that users will notice (unless they are somewhat technical) or significant security benefit (&lt;a href="https://www.troyhunt.com/banks-arbitrary-password-restrictions-and-why-they-dont-matter/"&gt;given what banks are already doing on top of passwords for security&lt;/a&gt;). Banks are revenue driven businesses. Getting changes made requires a legal obligation or benefits that outweigh the costs. Increasing the password length is neither at the present time, so these first group are unlikely to make changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Low max length and a higher input length
&lt;/h2&gt;

&lt;p&gt;Any bank that passes the first barrier gets into easier territory with this next group. What users type in is what gets validated. Anyone with the password "bankpassword1234" already fails to log in if they type in "bankpassword123456". To make passwords longer you need to increase the limit on your password change, set and login fields. You also need to ensure that you do not move back in to the first group, where the max input length equals the max password length.&lt;/p&gt;

&lt;p&gt;And that is it. You are done. You have made the change. Get to testing and prove that there is not a security appliance in the middle of yoour network that expects short passwords.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;There is a lot to think about before making changes to your password rules. Making changes to them is not as easy as increasing the length of your username or name fields. You need to be aware that your users do not count how many characters appear in the password field. You need to know about every system that sees your users passwords. Every system that has it's own login screen will need to go through these changes together. Only once they are all ready can you increase the max length that you allow users to enter.&lt;/p&gt;

&lt;p&gt;Next time will be about centralizing your password screens or about why password rules are so bad in the first place. I have not decided which one yet.&lt;/p&gt;

</description>
      <category>passwords</category>
      <category>security</category>
    </item>
    <item>
      <title>What are your favourite meetups?</title>
      <dc:creator>Mitch Pomery (he/him)</dc:creator>
      <pubDate>Sun, 15 Sep 2019 22:32:56 +0000</pubDate>
      <link>https://dev.to/mitchpommers/what-are-your-favourite-meetups-5882</link>
      <guid>https://dev.to/mitchpommers/what-are-your-favourite-meetups-5882</guid>
      <description>&lt;p&gt;What are your favourite meetups and what makes you enjoy them?&lt;/p&gt;

&lt;p&gt;I enjoy &lt;a href="https://juniordev.io/"&gt;Junior Dev&lt;/a&gt; because I get to see all the cool things people have been learning about and building. I want to get a Junior Dev meetup set up in Sydney now that I'm living there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/fendersperth"&gt;Perth Fenders&lt;/a&gt; is also great. While I'm not a professional front end developer, I love playing around with HTML, JS and CSS at home on my own projects. The amount of work they put in to making sites accessible, fast and work across browsers and devices is amazing.&lt;/p&gt;

&lt;p&gt;And &lt;a href="https://twitter.com/ISM_Sydney"&gt;Identity And Security Meetup Sydney&lt;/a&gt; is one that I will always remember as it is the first meetup that I gave a presentation at, and now I want to give more.&lt;/p&gt;

&lt;p&gt;I'm also keen to get along to the &lt;a href="https://www.meetup.com/Syd-Technology-Leaders/"&gt;Sydney Technology Leaders&lt;/a&gt; meetup and the Microsoft Reactor Lunch And Learns to catch up with friends, learn and network.&lt;/p&gt;

&lt;p&gt;Oh, and I'm not big on food/drinks at meetups. I normally grab a snack before I go and dinner on the way home.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>meetups</category>
    </item>
  </channel>
</rss>
