<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[ReverentGeek]]></title><description><![CDATA[Ramblings on bacon, drawing, and technology]]></description><link>https://reverentgeek.com/</link><image><url>https://reverentgeek.com/favicon.png</url><title>ReverentGeek</title><link>https://reverentgeek.com/</link></image><generator>Ghost 3.5</generator><lastBuildDate>Wed, 22 Apr 2020 15:33:23 GMT</lastBuildDate><atom:link href="https://reverentgeek.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Create PDFs with Node.js and Puppeteer]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I love to play music, especially in a band. There's something amazing about the synergy of multiple people harmonizing voices and instruments. However, for a band to be successful, everyone needs to be on the <em>same page</em> or it just sounds like a mess.</p>
<p>Come to think of it, I</p>]]></description><link>https://reverentgeek.com/create-pdfs-with-node-js-and-puppeteer/</link><guid isPermaLink="false">5e3c593e71e5d67de8259700</guid><category><![CDATA[node.js]]></category><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Thu, 06 Feb 2020 18:33:51 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2020/02/charter-example.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2020/02/charter-example.jpg" alt="Create PDFs with Node.js and Puppeteer"><p>I love to play music, especially in a band. There's something amazing about the synergy of multiple people harmonizing voices and instruments. However, for a band to be successful, everyone needs to be on the <em>same page</em> or it just sounds like a mess.</p>
<p>Come to think of it, I could make a lot of comparisons between a group of people that play well together in a band and a productive, highly-performing software team. But, I digress. Maybe another time!</p>
<p>One way a band to be on the <em>same page</em> is to follow sheet music or chord charts.</p>
<p>I recently updated a personal project named <a href="https://github.com/reverentgeek/charter">Charter</a> that uses Node.js to convert ChordPro formatted text files into PDF chord charts. It was a lot of fun!</p>
<p>Now, you may be thinking,</p>
<blockquote>
<p>&quot;I'm not a musician or singer. Why do I care?&quot;</p>
</blockquote>
<p>Regardless of your personal need for chord charts, you might find the source code for this project useful. Here are a few things you might learn:</p>
<ul>
<li>Create a CLI app using Node.js and Yargs</li>
<li>Load a text file and parse text</li>
<li>Use Jest to test Node.js code</li>
<li>Use handlebars to turn text into HTML</li>
<li>Use Puppeteer to convert HTML into a PDF</li>
</ul>
<p>Regarding PDF rendering, I tried lots of solutions including <a href="https://wkhtmltopdf.org/">wkhtmltopdf</a>, <a href="https://www.npmjs.com/package/electron-pdf">electron-pdf</a>, <a href="https://phantomjs.org/">phantomjs</a>, <a href="https://stackoverflow.com/questions/46077392/additional-options-in-chrome-headless-print-to-pdf">automating Chrome</a> with command-line switches, and finally landed on using the latest version of <a href="https://developers.google.com/web/tools/puppeteer">Puppeteer</a>. Puppeteer supports a <a href="https://github.com/puppeteer/puppeteer/blob/v2.1.1/docs/api.md#pagepdfoptions">ton of options</a> for generating PDFs. There's a lot of untapped potential here for doing lots of cool things!</p>
<h2 id="saveanywebpagetopdfusingnodejs">Save Any Web Page to PDF using Node.js</h2>
<p>Assuming you already have <a href="https://nodejs.org">Node.js</a> installed, open your terminal or command line, create a new project folder, and initialize it.</p>
<pre><code class="language-sh">mkdir pdf-test
cd pdf-test
npm init -y
</code></pre>
<p>Next, install Puppeteer as a dependency.</p>
<pre><code class="language-sh">npm install puppeteer
</code></pre>
<p>Here is an example of how to use Puppeteer to turn the Google home page into a PDF. Create a new file named <code>index.js</code> and paste the following code.</p>
<pre><code class="language-js">&quot;use strict&quot;;

const puppeteer = require(&quot;puppeteer&quot;);

(async () =&gt; {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(&quot;https://google.com&quot;);
  await page.pdf({ path: &quot;./google.pdf&quot;, format: &quot;Letter&quot; });
  await browser.close();
})();
</code></pre>
<p>Run the application using the following command.</p>
<pre><code class="language-sh">node .
</code></pre>
<p>You can change URL to something else. However, keep in mind that some pages load dynamically with JavaScript, so without setting more options, the resulting PDF could appear incomplete.</p>
<h2 id="convertalocalhtmlfiletopdf">Convert a Local HTML File to PDF</h2>
<p>Puppeteer is not limited to loading web pages. You can also load local HTML files. This is how the Charter application creates a chord chart. The Charter app first parses a ChordPro text file, generates an HTML file, and then uses Puppeteer to render the HTML and save as a PDF.</p>
<p>Create a new file named <code>sample.html</code> and paste the following HTML.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;style&gt;
    * html,
    body {
      font-family: Verdana, Arial, Helvetica, sans-serif;
    }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Hello World!&lt;/h1&gt;
  &lt;p&gt;Yay! My own PDF generator!&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>Create a new file named <code>local.js</code> and paste the following code.</p>
<pre><code class="language-js">&quot;use strict&quot;;

const path = require(&quot;path&quot;);
const puppeteer = require(&quot;puppeteer&quot;);

(async () =&gt; {
  const htmlFile = path.resolve(&quot;./sample.html&quot;);
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(&quot;file://&quot; + htmlFile);
  await page.pdf({ path: &quot;./sample.pdf&quot;, format: &quot;Letter&quot; });
  await browser.close();
})();
</code></pre>
<p>Next, run the code from the command line.</p>
<pre><code class="language-sh">node local.js
</code></pre>
<p>You should now have your very own &quot;Hello World!&quot; PDF in your project folder!</p>
<h2 id="createachordchartwithcharter">Create a Chord Chart with Charter</h2>
<p>If you have Node.js 12.x or higher installed and want to take the CLI app for a spin, you can use <code>npx</code> to run the application directly. Of course, you will need a ChordPro text file to test. Here's an example, or you can find others on the Internet.</p>
<pre><code class="language-text">{title: Amazing Grace}
{artist: Words by: John Newton, John P. Rees}
{artist: Music by: William W. Walker, Edwin Othello Excell}
{key: G}  
{tempo: 90}
{time: 3/4 }

{comment: Verse 1}
A - [G]mazing [G/D]grace  [D7]how  [Em]sweet [C]the   [G]sound
That [G]saved a [G/D]wretch  [D/C]like    [G/B]me
I [G]once was [G/B]lost but [C]now am  [G]found
[G/B]Was   [Em]blind but [G/D]now    [D7]I    [G]see
</code></pre>
<p><code>npx</code> will take a little while to download the first time, due to Puppeteer using Chromium.</p>
<pre><code class="language-sh">npx chord-charter -f amazing-grace.chordpro
</code></pre>
<p>I hope you find the project useful! Get out there and be awesome!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[My Most Embarrassing Mistakes as a Programmer]]></title><description><![CDATA[<p>My most embarrassing mistakes as a programmer, in no particular order:</p><ul><li>I didn't ask for help</li><li>I was afraid of what others would think</li><li>I didn't follow through on a promise</li><li>I didn't step up and take responsibility</li><li>I avoided conflict</li><li>I didn't encourage others</li><li>I didn't publicly celebrate the</li></ul>]]></description><link>https://reverentgeek.com/my-most-embarrassing-mistakes-as-a-programmer/</link><guid isPermaLink="false">5db9ee6371e5d67de82596d6</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Wed, 30 Oct 2019 20:12:25 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/10/IMG_2152.JPG" medium="image"/><content:encoded><![CDATA[<img src="https://reverentgeek.com/content/images/2019/10/IMG_2152.JPG" alt="My Most Embarrassing Mistakes as a Programmer"><p>My most embarrassing mistakes as a programmer, in no particular order:</p><ul><li>I didn't ask for help</li><li>I was afraid of what others would think</li><li>I didn't follow through on a promise</li><li>I didn't step up and take responsibility</li><li>I avoided conflict</li><li>I didn't encourage others</li><li>I didn't publicly celebrate the success of others</li></ul><p>My biggest mistakes had nothing to do with programming.</p><p>The most difficult parts of any job, and the most <em>valuable</em> activities of any job, have nothing at all to do with technology.</p><p>It's people. How we value ourselves. How we value others.</p><p>"Soft skills" is an awful term. The things we call "soft skills," such as listening, communication, team dynamics, empathy, ought to be given so much more priority in our workplaces. These are <em>core</em> skills that apply to anyone in any profession.</p><p>Here's the mindset I want.</p><blockquote>To be the most effective member of any team, I must first strive to model integrity and work ethic. I need to be respectful, helpful, patient, gracious, trustworthy, and hardworking. I need to be transparent, such as asking for help, owning mistakes, and asking forgiveness, regardless of my fear of the outcome, because it's the right thing to do. When I see a failure in our system, not just in the work we create but also our system of work and treatment of people, I need to take responsibility, speak up, and see it through correction. I need to give people the benefit of the doubt, try to understand their perspective and circumstance, be slow to anger, and be quick to forgive. I need to encourage and lift others up and help them to see their career and life through a bigger lens.</blockquote><p>I am a work in progress. I may not achieve these things every day, but that's my goal.</p><p>I hope this post gets you thinking of ways you can have a positive impact on the people you work with.</p><p>Remember, every day is a fresh start to be more awesome!</p>]]></content:encoded></item><item><title><![CDATA[A Note of Encouragement]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Earlier this year, I set up a new computer for my son. In the process, I created an &quot;Easter Egg&quot; for him to find. I left a note on the desktop with some instructions on how to run a command-line interface (CLI) application I created.</p>
<pre><code class="language-sh">&gt; heybuddy
</code></pre>
<p><img src="https://reverentgeek.com/content/images/2019/10/hey-buddy.png" alt="Hey buddy, I just want you to know... I know you can do it. Don't give up."></p>
<p>As</p>]]></description><link>https://reverentgeek.com/a-note-of-encouragement/</link><guid isPermaLink="false">5db09e4b71e5d67de825967c</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Wed, 23 Oct 2019 18:51:03 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/10/hey-buddy-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2019/10/hey-buddy-1.png" alt="A Note of Encouragement"><p>Earlier this year, I set up a new computer for my son. In the process, I created an &quot;Easter Egg&quot; for him to find. I left a note on the desktop with some instructions on how to run a command-line interface (CLI) application I created.</p>
<pre><code class="language-sh">&gt; heybuddy
</code></pre>
<p><img src="https://reverentgeek.com/content/images/2019/10/hey-buddy.png" alt="A Note of Encouragement"></p>
<p>As I hoped, I'll sometimes walk by and see he has a terminal window open and has run the app several times 😊</p>
<p>The source code for this application is on <a href="https://github.com/reverentgeek/notes-of-encouragement-cli">GitHub</a>. It's written in JavaScript and uses <a href="https://nodejs.org">Node.js</a>. There are instructions in the <code>readme</code> on how to customize the messages, change the name of the CLI app itself, and install it on someone's computer.</p>
<p>You can certainly take the idea and create your own customized encouragement CLI app, or take it further to create a web, desktop, or mobile application. Or, how about an encouragement robot!</p>
<p>Use the power of technology to make a positive impact on the people you care about! Let me know if there's anything I can do to help 🙂 Thanks for reading, and hope you have an awesome day!</p>
<p><img src="https://reverentgeek.com/content/images/2019/10/get-out-there-and-be-awesome.jpg" alt="A Note of Encouragement"></p>
<!--kg-card-end: markdown--><figure class="kg-card kg-embed-card kg-card-hascaption"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I recently set my son up with a new computer. In the process, I created an &quot;Easter Egg&quot; for him to find. I left a note with some instructions on the desktop on how to run a CLI app I created. Whenever he types &quot;heybuddy&quot; he gets a random note of encouragement 🙂 <a href="https://t.co/zjOVyfkWdK">pic.twitter.com/zjOVyfkWdK</a></p>&mdash; David Neal 🥓🥑 (@reverentgeek) <a href="https://twitter.com/reverentgeek/status/1149743935843131392?ref_src=twsrc%5Etfw">July 12, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<figcaption>Original Tweet</figcaption></figure>]]></content:encoded></item><item><title><![CDATA[Sketchnote Challenge]]></title><description><![CDATA[<p>Sketchnotes are amazing. Check out just a few of the many benefits.</p><ul><li>Helps you stay more engaged.</li><li>Connects both sides of your brain for supercharged learning. </li><li>Helps you to communicate more clearly.</li></ul><p>When you look at your notes weeks, months, or years later, you'll be shocked how much detail you</p>]]></description><link>https://reverentgeek.com/sketchnote-challenge/</link><guid isPermaLink="false">5d69901fd031bf06b18524c5</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Sat, 31 Aug 2019 13:12:45 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/08/660414EF-3D8D-45EF-87AD-A8B5E13E67DA.png" medium="image"/><content:encoded><![CDATA[<img src="https://reverentgeek.com/content/images/2019/08/660414EF-3D8D-45EF-87AD-A8B5E13E67DA.png" alt="Sketchnote Challenge"><p>Sketchnotes are amazing. Check out just a few of the many benefits.</p><ul><li>Helps you stay more engaged.</li><li>Connects both sides of your brain for supercharged learning. </li><li>Helps you to communicate more clearly.</li></ul><p>When you look at your notes weeks, months, or years later, you'll be shocked how much detail you can remember!</p><p>Want to learn to draw sketchnotes? You can! Using simple shapes such as lines, arrows, circles, triangles, and rectangles, you can doodle all sorts of things!</p><p>There are some great books out there</p><p>I posted a "sketch note challenge" on Twitter, and lots of folks followed along. You can follow along with these images I posted, and use them to practice. You'll be doodling all over your notes before you know it!</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Hey!  Want to learn with me how to take better notes using visual elements such as icons, shapes, arrows, and such? Take the <a href="https://twitter.com/hashtag/sketchnotechallenge?src=hash&amp;ref_src=twsrc%5Etfw">#sketchnotechallenge</a> with me! <a href="https://t.co/TVkUHWD2GQ">pic.twitter.com/TVkUHWD2GQ</a></p>&mdash; David Neal 🥓🥑 (@reverentgeek) <a href="https://twitter.com/reverentgeek/status/1158735672590721024?ref_src=twsrc%5Etfw">August 6, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-01-ideas-1.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 1: Ideas!</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-02-problems.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 2: Problem and Warning Icons</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-03-boxes.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 3: Boxes and Frames</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-04-questions.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 4: Questions</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-05-numbers.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 5: Numbers</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-06-lists-bullet-points.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 6: Lists and Bullet Points</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-07-speech-thought-bubbles.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 7: Thought and Speech Bubbles</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-08-arrows.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 8: Arrows</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-09-lettering.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 9: Lettering</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-10-icons.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 10: Icons</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-11-stick-figures.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 11: Stick Figures</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-12-faces.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 12: Faces</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-13-process.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 13: Draw a Process</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/08/sketchnote-challenge-day-14-sketchnote-something.png" class="kg-image" alt="Sketchnote Challenge"><figcaption>Day 14: Put it all together and sketch something!</figcaption></figure><p>Here's a link to a recording of Eva-Lotta's "<a href="https://vimeo.com/181110884">5 Steps to Change Your Note Taking</a>" talk.</p><p>Have fun sketching and learning!</p>]]></content:encoded></item><item><title><![CDATA[Create Engaging Screen Shots with Snagit]]></title><description><![CDATA[<p>Throughout my career, writing documentation and tutorials has been a critical skill. In my experience, good visuals can vastly improve the quality of communication. Explaining a lengthy process with multiple steps, how to use a complex interface, and where to look for features are just a few examples where visuals</p>]]></description><link>https://reverentgeek.com/create-branded-screenshots-with-snagit/</link><guid isPermaLink="false">5d2614bb4a35372945cc227f</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Fri, 12 Jul 2019 14:08:16 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/07/snagit-engaging-screenshots.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://reverentgeek.com/content/images/2019/07/snagit-engaging-screenshots.jpg" alt="Create Engaging Screen Shots with Snagit"><p>Throughout my career, writing documentation and tutorials has been a critical skill. In my experience, good visuals can vastly improve the quality of communication. Explaining a lengthy process with multiple steps, how to use a complex interface, and where to look for features are just a few examples where visuals may benefit the reader. "A picture is worth a thousand words" is certainly true for documentation, too!</p><p><a href="https://www.techsmith.com/screen-capture.html">Snagit</a> has been my primary tool for taking screen shots for years. Out of the box, there are a number of useful elements I frequently use to annotate images, such as arrows, callouts, shapes, and text.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/07/snagit-ootb-example-1.png" class="kg-image" alt="Create Engaging Screen Shots with Snagit"><figcaption>Use Snagit to add pizazz to your screen shots!</figcaption></figure><p>Here are a few examples of tutorials I've written that include screen shots annotated with Snagit.</p><ul><li><a href="https://developer.okta.com/blog/2019/06/18/command-line-app-with-nodejs">Build a Command Line Application with Node.js</a></li><li><a href="https://developer.okta.com/blog/2019/06/14/add-authentication-and-personalization-to-vuepress">Add Authentication and Personalization to VuePress</a></li><li><a href="https://developer.okta.com/blog/2019/03/11/node-sql-server">Build a Secure Node.js App with SQL Server</a></li></ul><h2 id="create-branded-screen-shots">Create Branded Screen Shots</h2><p>One of my favorite features of Snagit is the ability to not only customize these elements, but also create a collection of elements as a "theme." Creating a theme helps to ensure all screen shots will have a consistent look, and my preferred elements are always there when I need them. I can also separate my "work" theme tailored for my company's style and colors from my personal theme!</p><h3 id="create-a-new-theme-in-snagit">Create a New Theme in Snagit</h3><p>To create a new theme in Snagit:</p><ul><li>Click on one of the theme-able tools at the top of the Snagit window, such as <strong>Arrow</strong>, <strong>Text</strong>, <strong>Callout</strong>, or <strong>Shape</strong></li><li>On the right, under <strong>Quick Styles</strong>, click the <em>gear</em> icon</li><li>Click on <strong>New Theme...</strong></li><li>Give your theme a name</li><li>Customize the color and optionally add more colors</li><li>Click <strong>Create</strong></li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/07/snagit-create-new-theme.png" class="kg-image" alt="Create Engaging Screen Shots with Snagit"><figcaption>Steps to create a new Snagit theme</figcaption></figure><h3 id="add-custom-elements-to-a-theme">Add Custom Elements to a Theme</h3><p>When you create a new theme, Snagit automatically creates all the default <strong>Quick Styles</strong> with your theme's color(s). That's a great start, but perhaps you want to remove some of those and add your own.</p><p>For example, as you may have noticed, I have custom callout (speech bubble) that is orange with white text and uses a comic-style font named <a href="https://fonts.google.com/specimen/Bangers">Bangers</a>. To add this element to your theme, follow these steps:</p><ol><li>Click on <strong>Callout</strong> in the toolbar (your toolbar may look slightly different, and Callout may be under <strong><em>More</em></strong>).</li><li>Under <strong>Quick Styles</strong>, click on the desired <strong>Callout</strong> to modify.</li><li>Under <strong>Tool Properties</strong>, select a new font, change the color to white, and adjust the font size to 36pt.</li><li>To save the modified element to your theme (currently grayed out surrounded by a dashed line), click the <strong>Plus (+)</strong>.</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/07/create-new-theme-element.png" class="kg-image" alt="Create Engaging Screen Shots with Snagit"><figcaption>Steps to customize a Snagit element</figcaption></figure><blockquote>Note: To remove any element from your theme's <strong>Quick Styles</strong>, click the <strong>(X)</strong> in the top-left corner of the element.</blockquote><h2 id="share-a-custom-snagit-theme">Share A Custom Snagit Theme</h2><p>When you click the <em>gear</em> icon next to your theme, you'll see there are options to import and export themes. This is a great way to make sure everyone you work with has your awesome custom Snagit theme and will create consistent-looking screen shots!</p><h2 id="get-out-there-and-be-awesome-">Get Out There and Be Awesome!</h2><p>Contributing to documentation and tutorials is an extremely valuable way to give back to the open source community, to support the people you work with, and to help "future you" be more awesome!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2019/07/get-out-there-and-be-awesome.png" class="kg-image" alt="Create Engaging Screen Shots with Snagit"><figcaption>Get out there and be awesome!</figcaption></figure>]]></content:encoded></item><item><title><![CDATA[How to be a Superhuman Communicator]]></title><description><![CDATA[<p>People learn in a variety of ways, such as watching videos, listening to podcasts, reading books and articles, and exploring hands-on. For everyone fortunate to have good vision, visuals such as pictures, illustrations, or diagrams, are a universal and powerful way to learn and understand information.</p><p>Your brain is a</p>]]></description><link>https://reverentgeek.com/how-to-be-a-superhuman-communicator/</link><guid isPermaLink="false">5caf4c78bc58620a44555b18</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Fri, 12 Apr 2019 13:51:40 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/04/how-to-be-a-superhuman-communicator.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://reverentgeek.com/content/images/2019/04/how-to-be-a-superhuman-communicator.jpg" alt="How to be a Superhuman Communicator"><p>People learn in a variety of ways, such as watching videos, listening to podcasts, reading books and articles, and exploring hands-on. For everyone fortunate to have good vision, visuals such as pictures, illustrations, or diagrams, are a universal and powerful way to learn and understand information.</p><p>Your brain is a supercharged visual processing machine. At one glance, your brain can interpret incredible amounts of information. The old saying, "a picture is worth a thousand words," is a vast understatement. </p><h2 id="my-story">My Story</h2><p>In 2011, I finally got up the courage to give my first talk at a user group meeting. Since then, I've been on a journey of encouraging and motivating folks in technology to be more awesome, through speaking at events, writing, and creating videos.</p><p>By 2015, I had accomplished a lot. I had written numerous articles and spoken at dozens of conferences, including an International conference. With practice, I had improved all of my skills. But, I felt like something was missing. It didn't seem like I was having much impact on my readers and audiences.</p><p>In my desperate search for a cure, I came across a <a href="https://www.youtube.com/watch?v=Y1SMm4mOV9A">video of Dan Roam</a> describing how simplified hand-drawn illustrations can make a significant impact on presentations. I was hooked.</p><p>I had a brand new talk to give at Orlando Code Camp 2015, and I made it my goal to draw a few of the slides. Once I got started, a few slides quickly escalated. I couldn't stop. </p><p>When I gave that talk, I instantly knew it was a game changer. Those drawings made me a more comfortable speaker. I was able to tell my story exactly the way I wanted. The audience was far more engaged. The feedback was amazing, and was exponentially better than any of the talks I had given in the past.</p><p>Illustrations have been an integral part of everything I've done since. Not just for presentations, but for articles, videos, and any other type of communication. Drawing "sketch notes" has also become a great way to take notes and is a powerful way to learn and retain new information! </p><h2 id="how-to-start-your-journey">How to Start Your Journey</h2><p>I firmly believe you can take advantage of the power of drawing, too! There's no such thing as "bad" art. Whatever you create, even if it's very poorly drawn stick figures, people will love it! I promise.</p><p>Drawing is something you can do right now! Grab some paper and a pencil, pen, or marker, and start doodling ideas! </p><p>Drawing <em>well</em> is a skill you can learn. It will take practice and learning techniques to get better.</p><figure class="kg-card kg-image-card"><img src="https://reverentgeek.com/content/images/2019/04/journey-of-a-thousand-miles-lao-tzu.png" class="kg-image" alt="How to be a Superhuman Communicator"></figure><p>Some techniques you can learn or your own through experimentation. Study illustrations you like and figure out how you might reproduce the same look in your own drawings.</p><p>Watch others draw on YouTube. Some of it will look like magic. That "magic" is a combination of lots of practice and a collection of techniques. You can learn magic, too!</p><p>You can buy excellent courses on <a href="https://www.udemy.com/">Udemy</a> for as little as $10 when there's a sale. That's less than two drinks from Starbucks!</p><p>To get your drawings on to a computer, I recommend using a scanner app such as <a href="https://www.google.com/photos/scan/">Google PhotoScan</a> (iOS/Android) or <a href="https://itunes.apple.com/us/app/scanner-pro/id333710667?mt=8">Scanner Pro</a> (iOS).</p><h3 id="digital-drawing-and-software">Digital Drawing and Software</h3><p>These days, I rarely draw on paper. I use an <a href="https://www.apple.com/ipad/">iPad</a> and <a href="https://www.apple.com/apple-pencil/">Apple Pencil.</a> My favorite app for drawing illustrations for presentations and articles is Sketches Pro by Tayasui. I also use Adobe Draw or Affinity Designer for specific types of illustration or design work. In my opinion, the apps available for the iPad are the highest quality and easiest to use.</p><ul><li><a href="http://tayasui.com/sketches/">Tayasui Sketches</a> (iOS, Mac, and Android)</li><li><a href="https://www.adobe.com/products/draw.html">Adobe Draw</a> (iOS and Android)</li><li><a href="https://siliconbenders.com/">Sketchable</a> (Windows) - I've used this a few times, and it appears to be the best drawing app currently available for Windows</li><li><a href="https://affinity.serif.com/en-us/designer/">Affinity Designer</a> (Mac, Windows, iOS)</li></ul><h3 id="books">Books</h3><ul><li><a href="https://www.amazon.com/Visual-Thinking-Empowering-Organizations-Collaboration/dp/9063694539/ref=sr_1_3">"Visual Thinking"</a> by Williemien Brand</li><li><a href="https://www.amazon.com/Show-Tell-Everybody-Extraordinary-Presentations/dp/1591848024/ref=sr_1_1">"Show and Tell"</a> by Dan Roam</li><li><a href="https://www.amazon.com/Sketchnote-Handbook-illustrated-visual-taking/dp/0321857895/ref=sr_1_3">"The Sketchnote Handbook: the illustrated guide to visual note taking"</a> by Mike Rohde</li></ul><h3 id="people-to-follow">People to Follow</h3><ul><li><strong>Brad Colbow</strong>: <a href="http://bradcolbow.com/">Website</a> | <a href="https://twitter.com/bradcolbow">Twitter</a> | <a href="https://www.youtube.com/user/thebradcolbow">YouTube</a> | <a href="https://www.udemy.com/user/brad-colbow/">Udemy Courses</a></li><li><strong>Dan Roam</strong>: <a href="https://www.danroam.com/">Website</a> | <a href="https://twitter.com/dan_roam">Twitter</a></li></ul><h3 id="slides">Slides</h3><p>These are the slides from my talk on this subject, <a href="https://speakerdeck.com/reverentgeek/drawing-how-to-be-a-superhuman-communicator">"Drawing: How to be a Superhuman Communicator."</a></p><h3 id="further-reading">Further Reading</h3><ul><li><a href="https://reverentgeek.com/be-patient-and-keep-practicing/">Be Patient and Keep Practicing</a></li><li><a href="https://artplusmarketing.com/captivate-your-audience-using-simple-illustrations-5bf0fcd0e301">Captivate Your Audience Using Simple Illustrations</a></li><li><a href="https://24days.in/umbraco-cms/2018/doodles-a-learning-and-communication-superpower/">Doodles: A Learning and Communication Superpower</a></li></ul><h2 id="you-don-t-need-permission-to-be-awesome">You Don't Need Permission to be Awesome</h2><p>You may not realize it yet, but you are awesome. I believe you can make a significant, positive impact in your workplace, community, and the world, through the power of technology. Share your knowledge and experience with others! Use your own hand-drawn illustrations to make it fun and memorable!</p><figure class="kg-card kg-image-card"><img src="https://reverentgeek.com/content/images/2019/04/you-dont-need-permission-to-be-awesome.jpg" class="kg-image" alt="How to be a Superhuman Communicator"></figure>]]></content:encoded></item><item><title><![CDATA[Respect: The Most Fundamental Principle]]></title><description><![CDATA[<p>Much has been said about "lean" and "agile" approaches to work. Reflecting over more than ten years of personal experience, I have come to this conclusion: Respect for people is the most fundamental principle. When respect is the lens and filter through which decisions are made, there is a much</p>]]></description><link>https://reverentgeek.com/respect-for-people/</link><guid isPermaLink="false">5c8677d4bc58620a44555a5c</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Wed, 13 Mar 2019 15:44:57 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/03/respect-for-people-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://reverentgeek.com/content/images/2019/03/respect-for-people-1.jpg" alt="Respect: The Most Fundamental Principle"><p>Much has been said about "lean" and "agile" approaches to work. Reflecting over more than ten years of personal experience, I have come to this conclusion: Respect for people is the most fundamental principle. When respect is the lens and filter through which decisions are made, there is a much higher chance for success.</p><p>Having respect for people:</p><ul><li>requires listening, empathy, and deeper understanding</li><li>prioritizes health, family, and well-being</li><li>promotes connections and relationships</li><li>fosters community, commitment, and loyalty</li><li>empowers employees to make positive changes</li></ul><p>When respect is modeled top-down, leadership is motivated to maximize focus and alignment, minimize wasteful activities, and reduce friction. Leadership is obligated to make better decisions for the sustainability of the company, because its people deserve stability, work-life balance, and personal/professional development.</p><p>Employees are motivated to do their best work. Mutual respect helps individuals come together as a team, investing in one another, and fighting for each other's success. </p><p>When conflicts arise, respect allows people to focus on solving the issue rather than attacking individuals.</p><p>People are people. They are not your best "assets." They are not fungible resources. </p><p>The "Golden Rule" is still the golden rule.</p>]]></content:encoded></item><item><title><![CDATA[Build a Secure Node.js Application with JavaScript Async Await Using Hapi]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>At the core of the JavaScript language is its asynchronous programming model. Unfortunately, dealing with callback functions has long been a source of frustration for many developers. JavaScript Promises helped make writing complex asynchronous code more manageable, but brought its own set of challenges. With the introduction of async functions</p>]]></description><link>https://reverentgeek.com/build-a-secure-node-js-application-with-javascript-async-await-using-hapi/</link><guid isPermaLink="false">5c423d6dafe73327712d866f</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Fri, 18 Jan 2019 21:02:55 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/03/secure-hapi.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2019/03/secure-hapi.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"><p>At the core of the JavaScript language is its asynchronous programming model. Unfortunately, dealing with callback functions has long been a source of frustration for many developers. JavaScript Promises helped make writing complex asynchronous code more manageable, but brought its own set of challenges. With the introduction of async functions in ES2017 (and the <code>async</code> and <code>await</code> keywords), writing asynchronous JavaScript is now much easier.</p>
<p><a href="https://hapijs.com/">Hapi</a> is one of many frameworks available for Node.js designed for building scalable web application and services. With the release of version 17, hapi has been completely overhauled to use JavaScript async functions. The result is a modern framework for Node.js that is a pleasure to use.</p>
<p>Most Node.js tutorials available today were written for older versions of Node.js using older ES5 syntax. In this tutorial, you will learn the basics of creating a Node.js web application with hapi using more modern JavaScript.</p>
<h2 id="createyourfirsthapiwebserver">Create Your First hapi Web Server</h2>
<p>Open up a terminal (Mac/Linux) or a command prompt (Windows) and type the following command:</p>
<pre><code>node --version
</code></pre>
<p>If you get an error, or the version of Node.js you have is less than version 8, you'll need to <a href="https://nodejs.org">install Node.js</a>. On Mac or Linux, I recommend you first install <a href="https://github.com/creationix/nvm">nvm</a> and use nvm to install Node.js. On Windows, I recommend you use <a href="https://chocolatey.org/">Chocolatey</a>.</p>
<p>After ensuring you have a recent version of Node.js installed, create a folder for your project.</p>
<pre><code class="language-bash">mkdir learning-hapi
cd learning-hapi
</code></pre>
<p>A <code>package.json</code> file is required for your Node.js project and includes things like project information, scripts, and project dependencies. Use the <code>npm</code> command to create a <code>package.json</code> file in the project folder.</p>
<pre><code class="language-bash">npm init -y
</code></pre>
<p>Next, install hapi as a dependency.</p>
<pre><code class="language-bash">npm install hapi
</code></pre>
<p>Now open the project in your editor of choice.</p>
<blockquote>
<p>If you don't already have a favorite code editor, I recommend installing <a href="https://code.visualstudio.com/">Visual Studio Code</a>. VS Code has exceptional support for JavaScript and Node.js, such as smart code completion and debugging. There's also a vast library of free extensions contributed by the community.</p>
</blockquote>
<p>Next, create a folder named <code>src</code>. In this folder, add a new file named <code>index.js</code>. Open the file and add the following JavaScript.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const Hapi = require( &quot;hapi&quot; );

const port = 8080;
const server = Hapi.server( { port } );

// Define a route for the URL http://localhost:8080/
server.route( {
    method: &quot;GET&quot;,
    path: &quot;/&quot;,
    handler: () =&gt; {
        // a handler can return text, HTML, JSON,
        // a file, or just about anything
        return &quot;My first hapi server!&quot;;
    }
} );

const start = async () =&gt; {
    try {
        // start the server
        await server.start();
        console.log( `Server running at http://localhost:${ port }` );
    } catch ( err ) {
        console.log( err );
        process.exit( 1 );
    }
};

start();
</code></pre>
<p>As you can see in the previous code, the line <code>const start = async () =&gt; {</code> declares an asynchronous function named <code>start</code> using the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow function</a> syntax. <code>server.start()</code> is itself an asynchronous function, which requires the <code>await</code> keyword. The <code>await</code> keyword instructs the application to pause execution until the async function completes before moving on to the next line of code.</p>
<p>Dealing with errors in asynchronous code before <code>async/await</code> was tricky at best. Another advantage of using <code>async</code>/<code>await</code> is the ability to use straight-forward <code>try</code>/<code>catch</code> blocks to catch any errors that may occur.</p>
<p>Next, edit the <code>package.json</code> file and change the <code>&quot;main&quot;</code> property value to <code>&quot;src/index.js&quot;</code>. This property points Node to a file to execute when the application starts.</p>
<pre><code class="language-javscript">  &quot;main&quot;: &quot;src/index.js&quot;,
</code></pre>
<p>Now you can start the application. Go back to the terminal window and type in the following command.</p>
<pre><code class="language-bash">node .
</code></pre>
<p>You should see the message <code>Server running at http://localhost:8080</code>. Open your browser and navigate to <code>http://localhost:8080</code>. Your browser should display something like the following.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/hello-hapi.png" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<p>Success! You are on your way to hapi-ness!</p>
<h2 id="hapiprojectstructure">Hapi Project Structure</h2>
<p>As a Node.js project grows beyond a simple &quot;hello world&quot; example, it's essential to set up a good project structure. There are countless opinions on how you might organize a project, but a good starting point for a web application might look something like the following.</p>
<pre><code>├── package.json
├── client
│   ├── index.html
│   ├── css
│   └── js
├── src
│   ├── app.js
│   ├── index.js
│   ├── plugins
│   │   └── index.js
│   ├── routes
│   │   └── index.js
│   └── views
└── test
    └── index.js
</code></pre>
<p>Hapi can serve static files, such as HTML, CSS, and front-end JavaScript, using the <a href="https://hapijs.com/tutorials/serving-files">inert</a> plugin (more on plugins later). The <code>client</code> folder is where you might store these static assets. Of course, the contents and structure inside the <code>client</code> folder may differ depending on your front-end framework of choice.</p>
<p>Under the <code>src</code> folder, you might organize your server-side code into the following files and folders:</p>
<ul>
<li><code>app.js</code> to configure the hapi server,</li>
<li><code>index.js</code> to start the server,</li>
<li><code>plugins</code> for registering external and custom hapi plugins,</li>
<li><code>routes</code> for defining the resources, or <a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier">URIs</a>, of your application,</li>
<li>and <code>views</code> for any back-end dynamically-rendered content.</li>
</ul>
<p>Hapi can render server-side content using the <a href="https://github.com/hapijs/vision">vision</a> plugin combined with a template engine such as <a href="https://github.com/mde/ejs">ejs</a>, <a href="http://handlebarsjs.com/">handlebars</a>, or <a href="https://pugjs.org">pug</a>. It is up to you whether you want your application to serve static content using <code>inert</code>, server-rendered content using <code>vision</code>, or a mixture of both.</p>
<blockquote>
<p>Note: If you are building an application that only acts as a service or only exposes an API, you may not have a need for the <code>inert</code> and <code>vision</code> plugins, or a need to have folders for <code>client</code> and <code>views</code>.</p>
</blockquote>
<h3 id="refactorthehapiproject">Refactor the Hapi Project</h3>
<p>Before continuing further, refactor your project with the following steps.</p>
<p>Create a folder under <code>src</code> named <code>plugins</code>. Create a new file under <code>src/plugins</code> named <code>index.js</code>. Add the following code to this file.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

module.exports.register = async server =&gt; {
    // more to come later
};
</code></pre>
<p>Create a new folder under <code>src</code> named <code>routes</code>. Create a new file under <code>src/routes</code> named <code>index.js</code>. Add the following code to this file.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

module.exports.register = async server =&gt; {
    server.route( {
        method: &quot;GET&quot;,
        path: &quot;/&quot;,
        handler: () =&gt; {
            // a handler can return text, HTML, JSON,
            // a file, or just about anything
            return &quot;My first hapi server!&quot;;
        }
    } );
};
</code></pre>
<p>Create a new file under <code>src</code> named <code>app.js</code>. Add the following code to this file.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const Hapi = require( &quot;hapi&quot; );
const plugins = require( &quot;./plugins&quot; );
const routes = require( &quot;./routes&quot; );

module.exports.createServer = async config =&gt; {
    const server = Hapi.server( config );
    // register plugins
    await plugins.register( server );

    // register routes
    await routes.register( server );

    return server;
};
</code></pre>
<p>Last, modify <code>src/index.js</code> to match the following code.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const app = require( &quot;./app&quot; );

const port = 8080;
const config = { port };

const start = async () =&gt; {
    try {
        // create the server
        const server = await app.createServer( config );

        // start the server
        await server.start();

        console.log( `Server running at  http://localhost:${ port }` );
    } catch ( err ) {
        console.log( err );
        process.exit( 1 );
    }
}

start();
</code></pre>
<h2 id="extendhapiwithpluginsandlibraries">Extend Hapi with Plugins and Libraries</h2>
<p>By design, the core hapi service focuses on basic server functionality. <a href="https://hapijs.com/tutorials/plugins">Plugins</a> add additional features and capabilities to hapi. Your application may use a mix of official plugins, third-party plugins, and custom plugins you write. Here are just a sample of the more commonly used plugins.</p>
<table>
<thead>
<tr>
<th>Plugin</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://github.com/hapijs/inert">inert</a></td>
<td>Use to serve static files and directories.</td>
</tr>
<tr>
<td><a href="https://github.com/hapijs/vision">vision</a></td>
<td>Render templates.</td>
</tr>
<tr>
<td><a href="https://github.com/danielb2/blipp">blipp</a></td>
<td>Displays all the defined routes on startup.</td>
</tr>
<tr>
<td><a href="https://github.com/pinojs/hapi-pino">hapi-pino</a></td>
<td>Fast application logger that logs information in JSON format.</td>
</tr>
<tr>
<td><a href="https://github.com/hapijs/bell">bell</a></td>
<td>Third-party authentication.</td>
</tr>
</tbody>
</table>
<p>Here are a few useful libraries commonly found in hapi projects.</p>
<table>
<thead>
<tr>
<th>Library</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://github.com/hapijs/joi">joi</a></td>
<td>JSON object schema validation.</td>
</tr>
<tr>
<td><a href="https://github.com/hapijs/boom">boom</a></td>
<td>Use to generate and return HTTP error messages.</td>
</tr>
<tr>
<td><a href="https://github.com/hapijs/bounce">bounce</a></td>
<td>Selectively catch and rethrow errors.</td>
</tr>
<tr>
<td><a href="https://github.com/hapijs/wreck">wreck</a></td>
<td>Collection of HTTP client utilities.</td>
</tr>
<tr>
<td><a href="https://github.com/hapijs/lab">lab</a></td>
<td>Testing framework with code coverage analysis.</td>
</tr>
<tr>
<td><a href="https://github.com/hapijs/code">code</a></td>
<td>Test assertion library to use with <code>lab</code>.</td>
</tr>
</tbody>
</table>
<h3 id="installandregisterhapiplugins">Install and Register hapi Plugins</h3>
<p>In this next step, install two hapi plugins and configure them. From the command line, install <code>blipp</code> and <code>hapi-pino</code>.</p>
<pre><code class="language-bash">npm install blipp hapi-pino
</code></pre>
<p>Next, modify <code>src/plugins/index.js</code> and replace the contents of this file with the following code.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const blipp = require( &quot;blipp&quot; );
const pino = require( &quot;hapi-pino&quot; );

const isDev = process.env.NODE_ENV !== &quot;production&quot;;

module.exports.register = async server =&gt; {
    await server.register( [ blipp, {
        plugin: pino,
        options: {
            prettyPrint: isDev,
            logEvents: [ &quot;response&quot;, &quot;onPostStart&quot; ]
        }
    } ] );
};
</code></pre>
<p><code>server.register()</code> can take a single plugin or an array of plugins. A plugin can be registered using an instance of the plugin itself, such as the case with registering <code>blipp</code>. A plugin can also be registered using the plugin configuration object syntax, demonstrated by registering <code>hapi-pino</code> with its configuration options.</p>
<h3 id="createacustomhapiplugin">Create a Custom hapi Plugin</h3>
<p>You can create your custom plugins for hapi to do all sorts of things, such as modify server configuration, add routes, or listen for <a href="https://hapijs.com/api#-serverevents">server events</a>. In this step, create a plugin that listens for when a server starts and logs a message.</p>
<p>Create a new file under <code>src/plugins</code> named <code>serverStart.js</code>. In this file, add the following code.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

module.exports = {
    name: &quot;serverStart&quot;,
    version: &quot;1.0.0&quot;,
    register: async ( server, { message } ) =&gt; {
        server.events.on( &quot;start&quot;, () =&gt; {
            const msg = message || `Server running at ${ server.info.uri }`;
            server.log( [ &quot;info&quot;, &quot;server&quot; ], msg );
        } );
    }
};
</code></pre>
<p>A hapi plugin is a JavaScript object with a <code>name</code> property, a <code>version</code> property, and a <code>register</code> function with two arguments: <code>server</code> and <code>options</code>. Your <code>serverStart</code> plugin has an asynchronous <code>register</code> function that takes a <code>server</code> argument and uses <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring">object destructuring</a> to take a <code>message</code> passed in the options. If the code does not specify a message, the plugin generates a default message.</p>
<p>To use this new plugin, modify <code>src/plugins/index.js</code> with the following code.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const Blipp = require( &quot;blipp&quot; );
const HapiPino = require( &quot;hapi-pino&quot; );
const serverStart = require( &quot;./serverStart&quot; );

const isDev = process.env.NODE_ENV !== &quot;production&quot;;

module.exports.register = async server =&gt; {
    await server.register( [ Blipp, {
        plugin: HapiPino,
        options: {
            prettyPrint: isDev,
            logEvents: [ &quot;response&quot; ]
        }
    }, {
        plugin: serverStart,
        options: {
            message: `My hapi server is running at ${ server.info.uri }`
        }
    } ] );
};
</code></pre>
<p>Now run your application using:</p>
<pre><code class="language-bash">node .
</code></pre>
<p>Your console output should look similar to the following.</p>
<pre><code class="language-bash">method  path                          description
------  ----------------------------  -----------
GET     /

[1544478627595] INFO  (7408 on mycomputer):
    tags: [
      &quot;info&quot;,
      &quot;server&quot;
    ]
    data: &quot;My hapi server is running at http://mycomputer:8080&quot;
</code></pre>
<h2 id="addserverrenderedtemplatesforabetterui">Add Server Rendered Templates for a Better UI</h2>
<p>So far the application has only returned plain text. A hapi application can respond to requests with text, static files, content dynamically generated from templates, or other types of media, such as JSON. In this step, add support for <a href="https://github.com/mde/ejs">Embedded JavaScript templates</a>, or EJS.</p>
<p>First, install the required dependencies using <code>npm</code>.</p>
<pre><code class="language-bash">npm install vision ejs
</code></pre>
<p>Create a new file in the <code>src/views</code> folder named <code>layout.ejs</code>. Add the following HTML to this file.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
    &lt;title&gt;&lt;%= title %&gt;&lt;/title&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://fonts.googleapis.com/icon?family=Material+Icons&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;%- content %&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>Create a new file in the <code>src/views</code> folder named <code>index.ejs</code>. Add the following HTML to this file.</p>
<pre><code class="language-html">&lt;div class=&quot;container&quot;&gt;
    &lt;h1 class=&quot;header&quot;&gt;&lt;%= title %&gt;&lt;/h1&gt;
    &lt;p&gt;&lt;%= message %&gt;&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>Next, update <code>src/app.js</code> to configure the <code>vision</code> plugin and <code>ejs</code> template engine.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const Hapi = require( &quot;hapi&quot; );
const vision = require( &quot;vision&quot; );
const ejs = require( &quot;ejs&quot; );
const plugins = require( &quot;./plugins&quot; );
const routes = require( &quot;./routes&quot; );

module.exports.createServer = async config =&gt; {
    const server = Hapi.server( config );

    // add the vision plugin and 
    // register EJS template view support
    await server.register( vision );
    server.views( {
        engines: { ejs },
        relativeTo: __dirname,
        path: &quot;views&quot;,
        layout: true
    } );

    // register plugins
    await plugins.register( server );

    // register routes
    await routes.register( server );

    return server;
};
</code></pre>
<p>Now, update <code>src/routes/index.js</code> to return the rendered view instead of text.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

module.exports.register = async server =&gt; {
    server.route( {
        method: &quot;GET&quot;,
        path: &quot;/&quot;,
        handler: async ( request, h ) =&gt; {
            try {
                const message = &quot;My first hapi server!&quot;;
                return h.view( &quot;index&quot;, {
                    title: &quot;Home&quot;,
                    message
                } );
            } catch ( err ) {
                server.log( [ &quot;error&quot;, &quot;home&quot; ], err );
            }
        }
    } );
};
</code></pre>
<blockquote>
<p>Note: In the previous <code>handler</code> function, the <a href="https://hapijs.com/api#request"><code>request</code></a> contains information about the incoming request, and <code>h</code> is the <a href="https://hapijs.com/api#response-toolkit">response toolkit</a> that includes properties and utilities for creating responses.</p>
</blockquote>
<h2 id="secureyourhapiserverwithbellandokta">Secure Your hapi Server with Bell and Okta</h2>
<p>Unless you are building a static website, chances are your application needs a way to allow visitors to register for an account, log in, reset their password, and so forth. Add to the mix the ever-changing landscape of security concerns, and you can easily see implementing and maintaining a sound security strategy is far from a trivial task.</p>
<p>The good news is Okta's <a href="https://developer.okta.com">developer platform</a>, built on the latest open security standards, makes this step very easy.</p>
<p>To begin, create a free developer account with Okta at <a href="https://developer.okta.com/">developer.okta.com</a>. Click the <strong>Create Free Account</strong> button, or click the <a href="https://developer.okta.com/signup/">Sign Up</a> button.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/add-application-00.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<p>After creating your account, click the <strong>Applications</strong> link at the top, and then click <strong>Add Application</strong>.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/add-application-01.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<p>Next, choose a <strong>Web Application</strong> and click <strong>Next</strong>.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/add-application-02.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<p>Enter a name for your application, such as <em>My Hapi Server</em>. Verify the port number is the same as configured for your local web application. Then, click <strong>Done</strong> to finish creating the application.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/add-application-03.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<h3 id="enableselfserviceregistration">Enable self-service registration</h3>
<p>One of the great features of Okta is allowing users of your application to sign up for an account. By default, this feature is disabled, but you can easily enable it. First, click on the <strong>Users</strong> menu and select <strong>Registration</strong>.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/self-service-registration-01.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<ol>
<li>Click on the <strong>Edit</strong> button.</li>
<li>Change <strong>Self-service registration</strong> to <em>Enabled</em>.</li>
<li>Click the <strong>Save</strong> button at the bottom of the form.</li>
</ol>
<p><img src="https://reverentgeek.com/content/images/2019/01/self-service-registration-02.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<h3 id="manageconfigurationwithdotenv">Manage Configuration with DotEnv</h3>
<p>Node.js applications typically use environment variables for configuration. However, managing environment variables can be a chore. A popular module for managing application configuration data is <a href="https://www.npmjs.com/package/dotenv">dotenv</a>.</p>
<p>Install <code>dotenv</code> as a project dependency.</p>
<pre><code class="language-bash">npm install dotenv
</code></pre>
<p>Create a file named <code>.env</code> in the root folder of the project, and add the following configuration.</p>
<blockquote>
<p>Note: When using a source control system such as <code>git</code>, <strong>do not</strong> add the <code>.env</code> file to source control. Each environment requires a custom <code>.env</code> file. It is recommended you document the values expected in the <code>.env</code> file in the project README or a separate <code>.env.sample</code> file.</p>
</blockquote>
<pre><code class="language-bash"># Server configuration
NODE_ENV=production
PORT=8080
HOST_URL=http://localhost:8080
COOKIE_ENCRYPT_PWD=superAwesomePasswordStringThatIsAtLeast32CharactersLong!

# Okta configuration
OKTA_ORG_URL=https://{yourOktaDomain}
OKTA_CLIENT_ID={yourClientId}
OKTA_CLIENT_SECRET={yourClientSecret}
</code></pre>
<p>Now, update <code>src/index.js</code> to use the <code>dotenv</code> module.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

// Load in environment configuration
require( &quot;dotenv&quot; ).config();
const app = require( &quot;./app&quot; );

const DEFAULT_PORT = 8080;
const port = process.env.PORT || DEFAULT_PORT;
const config = { port };

const start = async () =&gt; {
    try {
        // create the server
        const server = await app.createServer( config );

        // start the server
        await server.start();
    } catch ( err ) {
        console.log( err );
        process.exit( 1 );
    }
};

start();
</code></pre>
<p>Go to your Okta account and click on the Dashboard link. On the right side of the page, you should find your <strong>Org URL</strong>. Copy and paste this value into your <code>.env</code> file to replace the value for <code>OKTA_ORG_URL</code>.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/your-org-url.png" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<p>Click on the <strong>Applications</strong> link, and then click on the name of your new application. Click on the <strong>General</strong> tab, and find near the bottom of the page a section titled <strong>Client Credentials</strong>. Copy the <strong>Client ID</strong> and <strong>Client secret</strong> values and paste them into your <code>.env</code> file to replace <code>{yourClientId}</code> and <code>{yourClientSecret}</code>, respectively.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/add-application-04.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<h3 id="createasecurewebapplication">Create A Secure Web Application</h3>
<p>First, install the <a href="https://www.npmjs.com/package/bell"><code>bell</code></a> and <a href="https://www.npmjs.com/package/hapi-auth-cookie"><code>hapi-auth-cookie</code></a> plugins. Bell is an authentication plugin, and <code>hapi-auth-cookie</code> is for cookie-based session management.</p>
<pre><code class="language-bash">npm install bell hapi-auth-cookie
</code></pre>
<p>Under <code>src/plugins</code> create a new file named <code>auth.js</code> and add the following code.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const bell = require( &quot;bell&quot; );
const authCookie = require( &quot;hapi-auth-cookie&quot; );

const isSecure = process.env.NODE_ENV === &quot;production&quot;;

module.exports.register = async server =&gt; {
    // register plugins
    await server.register( [ authCookie, bell ] );

    // configure cookie authorization strategy
    server.auth.strategy( &quot;session&quot;, &quot;cookie&quot;, {
        password: process.env.COOKIE_ENCRYPT_PWD,
        redirectTo: &quot;/authorization-code/callback&quot;, // If there is no session, redirect here
        isSecure // Should be set to true (which is the default) in production
    } );

    // configure bell to use your Okta authorization server
    server.auth.strategy( &quot;okta&quot;, &quot;bell&quot;, {
        provider: &quot;okta&quot;,
        config: { uri: process.env.OKTA_ORG_URL },
        password: process.env.COOKIE_ENCRYPT_PWD,
        isSecure,
        location: process.env.HOST_URL,
        clientId: process.env.OKTA_CLIENT_ID,
        clientSecret: process.env.OKTA_CLIENT_SECRET
    } );
};
</code></pre>
<p>Next, update <code>src/plugins/index.js</code> to register the new module.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const blipp = require( &quot;blipp&quot; );
const pino = require( &quot;hapi-pino&quot; );
const serverStart = require( &quot;./serverStart&quot; );
const auth = require( &quot;./auth&quot; );

const isDev = process.env.NODE_ENV !== &quot;production&quot;;

module.exports.register = async server =&gt; {
    await server.register( [ blipp, {
        plugin: pino,
        options: {
            prettyPrint: isDev,
            logEvents: [ &quot;response&quot; ]
        }
    }, {
        plugin: serverStart,
        options: {
            message: `My hapi server is running at ${ server.info.uri }`
        }
    } ] );
    await auth.register( server );
};
</code></pre>
<p>Now, modify <code>src/routes/index.js</code> to the following code.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const boom = require( &quot;boom&quot; );

module.exports.register = async server =&gt; {
    server.route( {
        method: &quot;GET&quot;,
        path: &quot;/&quot;,
        config: {
            auth: {
                strategy: &quot;session&quot;,
                mode: &quot;optional&quot;
            }
        },
        handler: async ( request, h ) =&gt; {
            try {
                const message = request.auth.isAuthenticated ? `Hello, ${ request.auth.credentials.profile.firstName }!` : &quot;My first hapi server!&quot;;
                return h.view( &quot;index&quot;, {
                    title: &quot;Home&quot;,
                    message,
                    isAuthenticated: request.auth.isAuthenticated
                } );
            } catch ( err ) {
                server.log( [ &quot;error&quot;, &quot;home&quot; ], err );
            }
        }
    } );

    server.route( {
        method: &quot;GET&quot;,
        path: &quot;/login&quot;,
        options: {
            auth: &quot;session&quot;,
            handler: async request =&gt; {
                return `Hello, ${ request.auth.credentials.profile.email }!`;
            }
        }
    } );

    server.route( {
        method: &quot;GET&quot;,
        path: &quot;/authorization-code/callback&quot;,
        options: {
            auth: &quot;okta&quot;,
            handler: ( request, h ) =&gt; {
                if ( !request.auth.isAuthenticated ) {
                    throw boom.unauthorized( `Authentication failed: ${ request.auth.error.message }` );
                }
                request.cookieAuth.set( request.auth.credentials );
                return h.redirect( &quot;/&quot; );
            }
        }
    } );

    server.route( {
        method: &quot;GET&quot;,
        path: &quot;/logout&quot;,
        options: {
            auth: {
                strategy: &quot;session&quot;,
                mode: &quot;try&quot;
            },
            handler: ( request, h ) =&gt; {
                try {
                    if ( request.auth.isAuthenticated ) {
                        // clear the local session
                        request.cookieAuth.clear();
                    }

                    return h.redirect( &quot;/&quot; );
                } catch ( err ) {
                    request.log( [ &quot;error&quot;, &quot;logout&quot; ], err );
                }
            }
        }
    } );
};
</code></pre>
<p>Create a new folder under <code>src/views</code> named <code>partials</code>. Create a new file in the <code>partials</code> folder named <code>navigation.ejs</code>. Add the following HTML to this file.</p>
<pre><code class="language-html">&lt;nav&gt;
    &lt;div class=&quot;nav-wrapper&quot;&gt;
    &lt;% if ( isAuthenticated ) { %&gt;
    &lt;a href=&quot;/logout&quot;&gt;Logout&lt;/a&gt;
    &lt;% } else { %&gt; 
    &lt;a href=&quot;/login&quot;&gt;Login&lt;/a&gt;
    &lt;% } %&gt;
&lt;/nav&gt;
</code></pre>
<p>Update <code>src/views/layout.ejs</code> to include the <code>navigation.ejs</code> file when it renders.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
    &lt;title&gt;&lt;%= title %&gt;&lt;/title&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://fonts.googleapis.com/icon?family=Material+Icons&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;% include partials/navigation %&gt;
    &lt;%- content %&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>Now, you are ready to start your application again.</p>
<pre><code class="language-bash">node .
</code></pre>
<p>In your browser, navigate to <code>http://localhost:8080/</code>. Click on the <strong>Login</strong> button at the top. You should see a prompt to log in to your Okta account.</p>
<blockquote>
<p>Note: To verify authentication is working as expected, you may need to open a new browser or use a private/incognito browser window.</p>
</blockquote>
<p><img src="https://reverentgeek.com/content/images/2019/01/okta-login.jpg" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<p>After logging in, you should be redirected back to the home page and see something like the following.</p>
<p><img src="https://reverentgeek.com/content/images/2019/01/authenticated-home-page.png" alt="Build a Secure Node.js Application with JavaScript Async Await Using Hapi"></p>
<p>After authentication, the following profile information is available on every request as part of <code>request.auth</code>.</p>
<pre><code class="language-javascript">// request.auth (Example)
{
    &quot;isAuthenticated&quot;: true,
    &quot;credentials&quot;: {
        &quot;provider&quot;: &quot;okta&quot;,
        &quot;token&quot;: &quot;...&quot;,
        &quot;expiresIn&quot;: 3600,
        &quot;profile&quot;: {
            &quot;id&quot;: &quot;0012345&quot;,
            &quot;username&quot;: &quot;john.henry@company.com&quot;,
            &quot;firstName&quot;: &quot;John&quot;,
            &quot;lastName&quot;: &quot;Henry&quot;,
            &quot;email&quot;: &quot;john.henry@company.com&quot;,
            &quot;raw&quot;: {
                &quot;sub&quot;: &quot;0012345&quot;,
                &quot;name&quot;: &quot;John Henry&quot;,
                &quot;locale&quot;: &quot;en-US&quot;,
                &quot;email&quot;: &quot;john.henry@company.com&quot;,
                &quot;preferred_username&quot;: &quot;john.henry@company.com&quot;,
                &quot;given_name&quot;: &quot;John&quot;,
                &quot;family_name&quot;: &quot;Henry&quot;,
                &quot;zoneinfo&quot;: &quot;America/Los_Angeles&quot;,
                &quot;updated_at&quot;: 1544212558,
                &quot;email_verified&quot;: true
            }
        }
    }
}
</code></pre>
<h2 id="addteststoyourhapiproject">Add Tests to Your Hapi Project</h2>
<p>A hapi project would not be complete without tests. <a href="https://github.com/hapijs/lab#readme">Lab</a> and <a href="https://github.com/hapijs/code#readme">code</a> are the preferred test libraries for hapi projects. <a href="https://www.npmjs.com/package/testdouble">TestDouble</a> is also a handy utility for replacing, mocking dependencies, and verifying behavior.</p>
<p>From the command line, install the following developer dependencies required for testing.</p>
<pre><code class="language-bash">npm install --save-dev code lab testdouble
</code></pre>
<p>Create a new folder in the root of the project named <code>test</code>. Add a file to this folder named <code>app.js</code>. In this file, add the following code.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

const td = require( &quot;testdouble&quot; );
td.replace( &quot;hapi-pino&quot; );
require( &quot;dotenv&quot; ).config();
const { expect } = require( &quot;code&quot; );
const Lab = require( &quot;lab&quot; );

const app = require( &quot;../src/app&quot; );

const lab = exports.lab = Lab.script();
const { describe, it } = lab;

describe( &quot;App&quot;, () =&gt; {
    it( &quot;home page returns valid response&quot;, async () =&gt; {
        const server = await app.createServer( { port: 12345 } );
        await server.initialize();
        const res = await server.inject( {
            url: &quot;/&quot;,
            method: &quot;GET&quot;
        } );
        expect( res.statusCode ).to.equal( 200 );
        expect( res.result ).to.exist();
        expect( res.result ).to.contain( &quot;My first hapi server!&quot; );
    } );
} );
</code></pre>
<p>Modify your <code>package.json</code> file, and change the <code>test</code> scripts property to the following.</p>
<pre><code class="language-javascript">    &quot;test&quot;: &quot;lab -c&quot;
</code></pre>
<p>Now, run the test from the command line using the following command.</p>
<pre><code class="language-bash">npm run test
</code></pre>
<p>The output from this first test should look similar to the following.</p>
<pre><code class="language-bash">  .

1 tests complete
Test duration: 67 ms
No global variable leaks detected
Coverage: 88.73% (16/142)
src/plugins/serverStart.js missing coverage on line(s): 8, 9
src/routes/index.js missing coverage on line(s): 17, 24, 35, 46-50, 64, 65, 69, 75, 77, 78
</code></pre>
<p>One of the great features of <code>lab</code> is the ability to analyze your tests for code coverage. The code analysis report includes lines of your source code currently missing test coverage.</p>
<h2 id="gogethapi">Go Get Hapi!</h2>
<p>In this tutorial, you have learned the basics of creating a modern web application with <strong>hapi</strong> and some of the tools that are part of the hapi ecosystem. Below are more resources to explore.</p>
<ul>
<li><a href="https://developer.okta.com/blog/2018/06/08/add-authentication-to-any-web-page-in-10-minutes">Add Authentication to Any Web Page in 10 Minutes</a></li>
<li><a href="https://developer.okta.com/blog/2018/04/24/simple-node-authentication">Simple Node Authentication</a></li>
<li><a href="https://developer.okta.com/blog/2018/11/15/node-express-typescript">Use TypeScript to Build a Node API</a></li>
<li><a href="https://developer.okta.com/blog/2017/06/21/what-the-heck-is-oauth">What the Heck is OAuth?</a></li>
<li><a href="https://hueniverse.com/why-you-should-consider-hapi-6163689bd7c2">Why You Should Consider hapi</a> by <a href="https://twitter.com/eranhammer">Eran Hammer</a>, principal creator of hapi</li>
</ul>
<p>You can find the complete <a href="https://github.com/reverentgeek/secure-node-app-hapi">project source code</a> on GitHub.</p>
<p>Thanks for reading, and happy... er... <em>hapi</em> coding!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Hey, Okta! Where's the Bacon?]]></title><description><![CDATA[<p>I am so excited to announce I have joined <a href="https://developer.okta.com/">Okta</a>'s developer relations team as a Senior Developer Advocate! My focus is on all the JavaScripts: Node.js, Vue, React, and a bazillion other things!</p><h2 id="why-okta">Why Okta?</h2><p>Have you ever secured an application? It's not a trivial task! Even more,</p>]]></description><link>https://reverentgeek.com/hey-okta-wheres-the-bacon/</link><guid isPermaLink="false">5b916fbcafe73327712d85d1</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Thu, 06 Sep 2018 21:51:50 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2018/09/developer-advocado.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://reverentgeek.com/content/images/2018/09/developer-advocado.jpg" alt="Hey, Okta! Where's the Bacon?"><p>I am so excited to announce I have joined <a href="https://developer.okta.com/">Okta</a>'s developer relations team as a Senior Developer Advocate! My focus is on all the JavaScripts: Node.js, Vue, React, and a bazillion other things!</p><h2 id="why-okta">Why Okta?</h2><p>Have you ever secured an application? It's not a trivial task! Even more, it's a critical component of every application you can't afford to get wrong!</p><p>Okta is a trusted leader in single sign-on, multi-factor authentication, and user management. Okta's <a href="https://developer.okta.com/product/">developer products</a> provide a painless solution for implementing a great security experience for customers. Their products also provide the peace of mind your applications remain secure as new threats emerge.</p><figure class="kg-card kg-image-card"><img src="https://reverentgeek.com/content/images/2018/09/reverentgeek-okta.jpg" class="kg-image" alt="Hey, Okta! Where's the Bacon?"></figure><p>However, my decision to join Okta is not only about believing in their products. My team is a fantastic group of folks who are genuinely passionate about the developer community. I am so excited to be serving the developer community with them!</p><h2 id="first-week-mind-blown">First week == mind blown</h2><p>Okta has an amazing process to ensure that every new hire is successful in starting their adventure as an Okta employee. Day one is full of training and orientation, and designed not only to inform and equip new employees, but to get them excited about the products and culture.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2018/09/okta-swag.jpg" class="kg-image" alt="Hey, Okta! Where's the Bacon?"><figcaption>Okta SWAG!</figcaption></figure><p>Okta is a company that participates in the <a href="https://pledge1percent.org/">Pledge 1%</a> to support nonprofits, called <a href="https://www.okta.com/okta-for-good/">Okta for Good</a>. On Day 2, new hires volunteered at <a href="https://familyhouseinc.org/">Family House, Inc.</a>, a home for families of a child undergoing cancer treatment. I did a lot of vacuuming! Others helped serve breakfast or with fun arts &amp; crafts projects. It was a fantastic, eye-opening experience.</p><figure class="kg-card kg-image-card"><img src="https://reverentgeek.com/content/images/2018/09/family-house-volunteers.jpg" class="kg-image" alt="Hey, Okta! Where's the Bacon?"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://reverentgeek.com/content/images/2018/09/family-house.jpg" class="kg-image" alt="Hey, Okta! Where's the Bacon?"><figcaption>Messages left by families blessed by Family House</figcaption></figure><h2 id="how-can-i-help-you-be-more-awesome">How can I help you be more awesome?</h2><p>Over the last five years, I have resolved to make it my mission to give back to the developer community. I want to encourage folks to see the world through a bigger lens. All of us have incredible potential to impact our workplace, family, community, and the entire world, using the technology within our grasp.</p><figure class="kg-card kg-image-card"><img src="https://reverentgeek.com/content/images/2018/09/you-dont-need-permission2.jpg" class="kg-image" alt="Hey, Okta! Where's the Bacon?"></figure><!--kg-card-begin: markdown--><p>If there's anything I can do for you, please let me know! Contact me on Twitter at <a href="https://twitter.com/reverentgeek">@reverentgeek</a>. You can also follow my silly drawings on <a href="https://instagram.com/reverentgeek">Instagram</a>, check out my <a href="https://github.com/reverentgeek">GitHub</a>, see my slides on <a href="https://speakerdeck.com/reverentgeek">SpeakerDeck</a>, and connect with me <a href="https://www.linkedin.com/in/davidneal">LinkedIn</a>!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Makin' Bacon with Node.js, Hapi, and Vue]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I recently created a new demo for my <a href="https://speakerdeck.com/reverentgeek/node-dot-js-crash-course-kcdc-2018">Node.js Crash Course</a> talk that I've given at several conferences. This application is a &quot;bacon ipsum&quot; generator using <a href="https://nodejs.org/">Node.js</a>, <a href="https://hapijs.com/">Hapi</a>, and <a href="https://vuejs.org/">Vue</a>. I know I'm not the first to come up with the idea of a &quot;bacon</p>]]></description><link>https://reverentgeek.com/makin-bacon-with-node-js-hapi-and-vue/</link><guid isPermaLink="false">5b7d83816ada047f703ba992</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Wed, 18 Jul 2018 16:37:17 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2018/10/makin-bacon-article.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2018/10/makin-bacon-article.png" alt="Makin' Bacon with Node.js, Hapi, and Vue"><p>I recently created a new demo for my <a href="https://speakerdeck.com/reverentgeek/node-dot-js-crash-course-kcdc-2018">Node.js Crash Course</a> talk that I've given at several conferences. This application is a &quot;bacon ipsum&quot; generator using <a href="https://nodejs.org/">Node.js</a>, <a href="https://hapijs.com/">Hapi</a>, and <a href="https://vuejs.org/">Vue</a>. I know I'm not the first to come up with the idea of a &quot;bacon ipsum&quot; generator, but I thought it'd be a fun project to create one in Node.js.</p>
<p>API Requirements:</p>
<ul>
<li>Using a list of bacon names and other associated words...</li>
<li>Return a specified number of paragraphs, maximum of 25</li>
<li>Paragraphs should consist of between 3 to 6 sentences</li>
<li>Each sentence should be capitalized</li>
<li>A sentence should end with random punctuation, weighted towards more frequent use of periods</li>
<li>A sentence should consist of between 4 to 12 unique words</li>
</ul>
<p>UI Requirements:</p>
<ul>
<li>Customer can choose to generate 1 to 21 &quot;pounds&quot; of bacon</li>
<li>Customer can easily copy the generated text to their clipboard</li>
</ul>
<p><a href="https://node-bacon-generator.herokuapp.com/">See it in action!</a></p>
<p>When you click on the &quot;Make the Bacon!&quot; button, the Vue application uses <a href="https://www.npmjs.com/package/axios">Axios</a> to call the API for bacon. When the API call returns, the Vue app updates its state with the array of paragraphs. This triggers re-rendering the UI to list the paragraphs and show the &quot;Copy to the clipboard!&quot; button.</p>
<pre><code class="language-javascript">makeTheBacon: function() {
  return axios
    .get( &quot;/api/bacon/&quot; + this.numberOfPounds )
    .then( res =&gt; ( this.paragraphs = res.data.paragraphs ) )
},
</code></pre>
<h3 id="vuecomputedproperties">Vue computed properties</h3>
<p>The Vue app uses a computed property, <code>hazBacon</code>, to show/hide the &quot;Copy to the clipboard!&quot; button based on there being any paragraphs of bacon text to display.</p>
<p>When copying text to the clipboard, the Vue app uses another computed property, <code>paragraphText</code>, to join the array of paragraphs together into a single string.</p>
<pre><code class="language-javascript">computed: {
  paragraphText: function() {
    return this.paragraphs.join( &quot;\n\n&quot; );
  },
  hazBacon: function() {
    return this.paragraphs.length &gt; 0;
  },
  poundText: function() {
    return this.numberOfPounds == 1 ? &quot;pound&quot; : &quot;pounds&quot;;
  }
},
</code></pre>
<h3 id="otherdependencies">Other dependencies</h3>
<p>In addition to Node.js, Hapi, and Vue, here are the dependencies and plugins used by the project. Some of these are my current favorites for building Node.js applications.</p>
<ul>
<li><a href="https://www.npmjs.com/package/vue-clipboard2">Vue-Clipboard2</a> - Vue component used to copy text to the clipboard</li>
<li><a href="https://www.npmjs.com/package/axios">Axios</a> - HTTP client for browsers or Node.js</li>
<li><a href="https://www.npmjs.com/package/fs-extra">fs-extra</a> - Promise-based file system module</li>
<li><a href="https://www.npmjs.com/package/joi">Joi</a> - Object schema validation plugin for Hapi</li>
<li><a href="https://www.npmjs.com/package/eslint">ESLint</a> - JavaScript linting</li>
<li><a href="https://www.npmjs.com/package/nodemon">Nodemon</a> - Developer tool that automatically restarts the application when any change is made to source code</li>
<li><a href="https://www.npmjs.com/package/boom">Boom</a> - Hapi plugin for returning errors</li>
<li><a href="https://www.npmjs.com/package/hapi-pino">hapi-pino</a> - Pino logging plugin for Hapi</li>
<li><a href="https://www.npmjs.com/package/inert">Inert</a> - Static resource plugin for Hapi</li>
<li><a href="https://www.npmjs.com/package/lab">Lab</a> and <a href="https://www.npmjs.com/package/code">Code</a> - Test and assertion utilities for Hapi</li>
</ul>
<p><a alt="Check out the source!" href="https://github.com/reverentgeek/node-bacon-generator"><img src="https://reverentgeek.com/content/images/2018/07/check-out-the-source.png" alt="Makin' Bacon with Node.js, Hapi, and Vue"></a></p>
<p style="text-align:center">
<a href="https://github.com/reverentgeek/node-bacon-generator">github.com/reverentgeek/node-bacon-generator</a>
</p>
<h3 id="happycomputering">Happy computering!</h3>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Choose Your Own Framework: The Curse of JavaScript Fatigue]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>How will your project die? Choose from 2,147,483,647 possible endings!</p>
<!--kg-card-end: markdown-->]]></description><link>https://reverentgeek.com/choose-your-own-framework-the-curse-of-javascript-fatigue/</link><guid isPermaLink="false">5b7d83816ada047f703ba991</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Wed, 13 Jun 2018 17:15:35 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/03/choose-your-own-adventure.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2019/03/choose-your-own-adventure.jpg" alt="Choose Your Own Framework: The Curse of JavaScript Fatigue"><p>How will your project die? Choose from 2,147,483,647 possible endings!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[The MONSTER at the end of this Book]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>The Monster at the end of this book...</p>
<p><img src="https://reverentgeek.com/content/images/2018/05/the-monster-2.jpeg" alt="See?"></p>
<!--kg-card-end: markdown-->]]></description><link>https://reverentgeek.com/the-monster-at-the-end-of-this-book/</link><guid isPermaLink="false">5b7d83816ada047f703ba990</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Fri, 25 May 2018 22:34:45 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/03/the-monster-1.jpeg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2019/03/the-monster-1.jpeg" alt="The MONSTER at the end of this Book"><p>The Monster at the end of this book...</p>
<p><img src="https://reverentgeek.com/content/images/2018/05/the-monster-2.jpeg" alt="The MONSTER at the end of this Book"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Not All Heroes Wear Capes]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>On the morning of November 25, 1982, we all piled in our car and made the 2-hour trip to my Aunt and Uncle’s house near Atlanta, GA. It’s Thanksgiving. As was tradition on my mother’s side of the family, we joined hands, gave thanks for our blessings,</p>]]></description><link>https://reverentgeek.com/not-all-heroes-wear-capes/</link><guid isPermaLink="false">5b7d83816ada047f703ba98d</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Tue, 06 Mar 2018 16:03:06 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2018/10/not-all-heroes-wear-capes.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2018/10/not-all-heroes-wear-capes.jpg" alt="Not All Heroes Wear Capes"><p>On the morning of November 25, 1982, we all piled in our car and made the 2-hour trip to my Aunt and Uncle’s house near Atlanta, GA. It’s Thanksgiving. As was tradition on my mother’s side of the family, we joined hands, gave thanks for our blessings, and enjoyed a meal together.</p>
<p>This particularly momentous Thanksgiving Day, I discovered the TRS-80.</p>
<p><img src="https://reverentgeek.com/content/images/2018/03/BB7D74CD-ECCF-4AC0-83D2-65A864064EFE.jpeg" alt="Not All Heroes Wear Capes"></p>
<p>I don’t remember if I spent the <em>entire</em> day at that keyboard. What I do know is, I must have made an impression on my Uncle.</p>
<h3 id="anamazingactofkindness">An amazing act of kindness</h3>
<p>Some time after that Thanksgiving, we made another trip to my Aunt and Uncle’s house. Waiting for me there was a big cardboard box. Inside was the TRS-80, a cassette drive, a floppy drive, a dot matrix printer, cables, and a book titled, “Getting Started With Color BASIC.”</p>
<p><img src="https://reverentgeek.com/content/images/2018/03/5B73C5D9-CE5F-4167-819E-FD803E1079A9.jpeg" alt="Not All Heroes Wear Capes"></p>
<p>This one very kind and generous act launched me on a journey of computers and programming. I am forever grateful, and in their debt, for helping me to discover something that has not only been my career, but a source of learning, passion, and delight.</p>
<h3 id="youcanmakeanimpact">You can make an impact!</h3>
<p><em>You</em> have an amazing opportunity to impact your own family and community in powerful, and far-reaching ways! Even one simple act of kindness, encouragement, or investment of your time could be the catalyst that launches a young person’s life-long journey of exploration and livelihood.</p>
<p>Here are just a few ways you can invest in someone:</p>
<ul>
<li>Take your family to an event like <a href="https://www.thatconference.com/">THAT Conference</a> or <a href="http://www.codemash.org/">CodeMash</a>. Not only is there a water park, there is an entire schedule of science and technology sessions specifically for kids and young adults.</li>
<li>Submit to give a Family session at <a href="https://www.thatconference.com/Sessions/Submit">THAT Conference</a>!</li>
<li>Encourage the young women in your family or community to connect to a local <a href="https://girlswhocode.com">Girls Who Code</a> group, and <em>volunteer</em>!</li>
<li>Consider gifting a <a href="https://www.amazon.com/Kano-1000D-01-Computer-Kit/dp/B00WRGTVWI/">Kano Computer Kit</a>, a <a href="https://www.amazon.com/Piper-Computer-Educational-Teaches-Coding/dp/B016HLFW44/">Piper Computer Kit</a>, an <a href="https://ozobot.com/">Ozobot</a>, <a href="https://www.lego.com/en-us/mindstorms">Lego Mindstorms</a>, or countless other learning kits.</li>
<li>Get involved in a local <a href="https://spaces.makerspace.com/directory/">makerspace</a> or <a href="https://www.meetup.com/topics/makers/">maker meetup</a>.</li>
<li>Reach out to your local schools and ask how you can get involved.</li>
</ul>
<h3 id="thankyou">Thank you</h3>
<p><img src="https://reverentgeek.com/content/images/2018/03/aunt-and-uncle_sm.jpg" alt="Not All Heroes Wear Capes"></p>
<p>I can’t thank my Aunt and Uncle enough for the impact they have made in my life. I continue to be inspired by their example of investing not only in their family, but the lives of countless others.</p>
<p>Thank you, to all of you who are making an impact, and all of you who <em>will</em> make an impact, in your families and communities.</p>
<p>Go, and be awesome!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Confront Your Inner Critic]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Have you ever felt inadequate? Like a fraud? Like you don't belong where you are? That someone is going to expose you for who you really are?</p>
<p>Maybe you're experiencing <a href="https://en.wikipedia.org/wiki/Impostor_syndrome">impostor syndrome</a>.</p>
<p>I would wager you do awesome things. Maybe you just don't realize it. Because your inner critic keeps</p>]]></description><link>https://reverentgeek.com/confront-your-inner-critic/</link><guid isPermaLink="false">5b7d83816ada047f703ba98c</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Fri, 02 Mar 2018 13:37:27 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/03/Inner-critic.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2019/03/Inner-critic.jpg" alt="Confront Your Inner Critic"><p>Have you ever felt inadequate? Like a fraud? Like you don't belong where you are? That someone is going to expose you for who you really are?</p>
<p>Maybe you're experiencing <a href="https://en.wikipedia.org/wiki/Impostor_syndrome">impostor syndrome</a>.</p>
<p>I would wager you do awesome things. Maybe you just don't realize it. Because your inner critic keeps cutting you down.</p>
<h3 id="yourenotalone">You're not alone</h3>
<p>I sometimes struggle with this, too. Most people have experienced, or are currently fighting with impostor syndrome right now.</p>
<p>Really successful people.</p>
<p>I put on pants today. I consider that a win.</p>
<h3 id="dontfallintothecomparisontrap">Don't fall into the comparison trap</h3>
<p>There’s no need to compare yourself to others. You aren’t them. They aren’t you. Focusing on someone else’s accomplishments and using their success to beat yourself up is a terrible waste of time and only leads to despair.</p>
<p>Let others inspire you. But, don't let their successes fuel your inner critic.</p>
<h3 id="theresnothingwrongwithbeingabeginner">There's nothing wrong with being a beginner</h3>
<p>Regardless of how long you've been doing your thing, there will be times when you are a beginner.</p>
<p>Are you learning a new technology or skill? Have you joined a new team or company?</p>
<p>You <em>will</em> have legitimate feelings of inadequacy and anxiety. This is totally normal! You're going to stink at it for a while. Keep moving forward and getting better!</p>
<p>It's okay to speak up, and ask others for help!</p>
<h3 id="surroundyourselfwithawesomepeople">Surround yourself with awesome people</h3>
<p>Find people who will not only encourage you, but who are transparent about their own struggles. It helps to know you're not alone.</p>
<p>When someone gives you positive feedback, don't dismiss it! Write it down. Collect these moments to silence your inner critic.</p>
<h3 id="keeparecordofwhatyouvedone">Keep a record of what you've done</h3>
<p>Day to day, or week by week, it may feel like you're not making any progress. However, if you look back over a longer period of time, such as six months or a year, you can start to see just how far you've come.</p>
<p>In software development, some teams have regular <a href="https://en.wikipedia.org/wiki/Retrospective">retrospectives</a> to identify successes and things to improve.</p>
<p>Have a personal retrospective. No, this is not where you beat yourself up and have a pity party. Make a list of the things you've accomplished, no matter how small. Make a list of actionable goals and things you can improve.</p>
<h3 id="shareyourknowledgeortime">Share your knowledge or time</h3>
<p>Teach others what you know. You may have this feeling the things you know are obvious and simple. It might surprise you to discover there are a lot of people who would love to possess the knowledge you already have.</p>
<p>For me, giving talks and writing blog posts have been things that have caused me the most anxiety and feelings of impostor syndrome. At the same time, hearing stories of the positive impact I’ve made on people has been one of the key strategies to combating my inner critic.</p>
<p>Not ready to teach? How about volunteering to help a local non-profit? It doesn't take a lot of time, or usually any special skill.</p>
<p>Whether you teach or volunteer, you can have an amazing impact on others. The dividends are huge.</p>
<h3 id="bebraveandseekamentor">Be brave, and seek a mentor!</h3>
<p>I am very grateful to have a dear friend in my life who has been my cheerleader for many years. He has the gift of encouragement. He knows how to listen to my struggles, and always seems to uncover the gold in what only looks like a trash heap to me.</p>
<h3 id="beamentor">Be a mentor!</h3>
<p>Invest in someone. Encourage them. Help them to see their potential, and to believe. When they accomplish great things, you can know you played a part.</p>
<h3 id="beyou">Be you!</h3>
<p>Give yourself freedom to fail. Celebrate your successes. Keep challenging yourself.</p>
<p>You got this.</p>
<p>Go, and be awesome!</p>
<hr>
<p>Here's <a href="https://youtu.be/qh9KcV9HKS4">an episode on Impostor Syndrome</a> I recorded with the <a href="https://www.youtube.com/channel/UCYVTUh34eDCAXrB5iIWH4yA">Script &amp; Style Web technology podcast</a>. Check it out!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[5 Essential Ingredients for an Awesome Tech Talk]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I believe one of the big reasons people are afraid of public speaking (or writing) is <a href="https://en.wikipedia.org/wiki/Impostor_syndrome">impostor syndrome</a>. You may think...</p>
<blockquote>
<p>“I’m not an expert! I barely know anything! Everyone will know I’m a fraud!”</p>
</blockquote>
<p>Psst... here’s a secret: You don’t have to be an expert!</p>]]></description><link>https://reverentgeek.com/5-essential-ingredients-for-an-awesome-tech-talk/</link><guid isPermaLink="false">5b7d83816ada047f703ba98b</guid><dc:creator><![CDATA[David Neal]]></dc:creator><pubDate>Mon, 01 Jan 2018 20:12:13 GMT</pubDate><media:content url="https://reverentgeek.com/content/images/2019/03/the-tech-talk-handbook.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://reverentgeek.com/content/images/2019/03/the-tech-talk-handbook.jpg" alt="5 Essential Ingredients for an Awesome Tech Talk"><p>I believe one of the big reasons people are afraid of public speaking (or writing) is <a href="https://en.wikipedia.org/wiki/Impostor_syndrome">impostor syndrome</a>. You may think...</p>
<blockquote>
<p>“I’m not an expert! I barely know anything! Everyone will know I’m a fraud!”</p>
</blockquote>
<p>Psst... here’s a secret: You don’t have to be an expert!</p>
<p>In fact, you have something no one else in the entire world has. <em>Your</em> experience.</p>
<p>Here’s a recipe for turning your experience into an awesome presentation!</p>
<h2 id="1whydidyouchoosethistechnology">1. Why did you choose this technology?</h2>
<p>People can argue semantics, “best practices,” architecture, speed, or “Technology A” vs. “Technology B” all day long. But, no one can dispute <em>your</em> experience. Tell people your story. What was your motivation for choosing this technology, or for replacing “Technology A” with “Technology B?” What problems were you trying to solve? Chances are, your reasons “why” will resonate with other people in similar situations.</p>
<h2 id="2whatdoesthistechnologydo">2. What does this technology do?</h2>
<p>Do some research and put together a short list of highlights, features, and capabilities. This is your opportunity to geek out and dive a little deeper into this technology beyond your particular use case. Seek to find other scenarios where this technology is a good fit. This information can help bridge gaps for your audience.</p>
<h2 id="3howdidyoumakeitwork">3. How did you make it work?</h2>
<p>Give your audience more of your story. They want to hear about the challenges and issues you faced along the way. Most of all, they want your insights! You learned the hard way what worked and what didn’t work, so share the good stuff! Including…</p>
<h3 id="whatmistakesdidyoumake">What mistakes did you make?</h3>
<p><img src="https://reverentgeek.com/content/images/2018/01/A0AA2FA8-EB76-40AA-90F6-EA5DFC5F4F3F.jpeg" alt="5 Essential Ingredients for an Awesome Tech Talk"></p>
<blockquote>
<p>“No way! I already feel like an impostor, and now you want me to remove any doubt?!”</p>
</blockquote>
<p>You might think admitting your mistakes will harm your reputation or credibility. Nope! Being transparent about your mistakes and what you learned from them <em>adds</em> to your credibility! I don’t know about you, but I make mistakes all the time. I want to hear from <em>real</em> humans doing <em>real</em> work -- people I can relate to.</p>
<p>If you were to do it all over, what would you do differently? Turn your challenges and mistakes into key takeaways for your audience!</p>
<h3 id="demoifyoumust">Demo, if you must</h3>
<p>A good demo can be the final puzzle piece needed to convince someone to try this technology. A working demo is great, but so are screen shots or a recorded video!</p>
<p>For the love of all that is holy, don’t do any live coding unless you are specifically demoing features of an IDE!</p>
<p>Your demo should only exist to reinforce your “why” for choosing this technology. Make it short and to the point, and show them something awesome! Don’t waste your audience’s time showing “how.” They can easily find that information for themselves on the Internet later. Your job is to convince them to go try it!</p>
<p>In my opinion, no demo is better than a bad one.</p>
<h2 id="4wheretogetstarted">4. Where to get started?</h2>
<p>You did the research. You made it work. Give your audience links to put them on the fast track! Better yet, give them <em>one</em> link where they can go to get your slides, your contact information, and a list of all the resources you recommend.</p>
<h2 id="5dropthemic">5. Drop the mic*</h2>
<p>Wrap it up. Send them off with a call to action and high-fives!</p>
<h2 id="bakeintheovenat350for45minutes">Bake in the oven at 350 for 45 minutes</h2>
<p>Imagine yourself in the future. You just finished giving a talk covering these five essential ingredients. Guess what?</p>
<p><strong>BOOM.</strong></p>
<p>You just gave an awesome talk. Your audience is now walking away with <em>valuable</em> information they could not have found anywhere else.</p>
<p>Now, go make it happen!</p>
<p>*Metaphorically speaking. Real microphones are fragile, and expensive. Just ask <a href="https://twitter.com/kylewelch">Kyle Welch</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>