<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joe Steinbring</title>
    <description>The latest articles on DEV Community by Joe Steinbring (@steinbring).</description>
    <link>https://dev.to/steinbring</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2921%2Fcdbec439-3b9a-4f2f-a81f-61dd790f4e6e.png</url>
      <title>DEV Community: Joe Steinbring</title>
      <link>https://dev.to/steinbring</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/steinbring"/>
    <language>en</language>
    <item>
      <title>How to deploy a PHP app to Azure</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Tue, 27 Sep 2022 11:56:58 +0000</pubDate>
      <link>https://dev.to/steinbring/how-to-deploy-a-php-app-to-azure-2m1m</link>
      <guid>https://dev.to/steinbring/how-to-deploy-a-php-app-to-azure-2m1m</guid>
      <description>&lt;p&gt;In a previous post, we covered &lt;a href="https://dev.to/steinbring/how-to-deploy-a-nodejs-app-to-azure-an0"&gt;how to deploy a Node.js app to Azure&lt;/a&gt;.  This time, we are going to cover how to deploy a &lt;a href="https://jws.news/tag/php/"&gt;PHP&lt;/a&gt; app to Azure.  Just like last time, we are going to be using the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"&gt;Azure CLI&lt;/a&gt; to do this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites: PHP and Azure CLI
&lt;/h2&gt;

&lt;p&gt;Before we go any further, you need to have &lt;a href="https://formulae.brew.sh/formula/php#default"&gt;PHP&lt;/a&gt; installed.  We can install it using &lt;a href="https://brew.sh/"&gt;Homebrew&lt;/a&gt;.  PHP is what is going to allow you to test your code before deploying it to the server.  You are also going to need to have &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"&gt;Azure CLI&lt;/a&gt; installed on your computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a PHP app to deploy
&lt;/h2&gt;

&lt;p&gt;Our test app is going to be pretty simple, this time.  It is just going to be &lt;code&gt;echo "Hello Flavortown!";&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ervxn8ibksmretey3s4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ervxn8ibksmretey3s4.png" alt="echo " width="787" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to test the app, you can run &lt;code&gt;php -S localhost:8080&lt;/code&gt; from the terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6cnfqf8k2i7u6sm9tqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6cnfqf8k2i7u6sm9tqt.png" alt="php -S localhost:8080" width="795" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the PHP Development Server running, you can open &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt; in a browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F105ti4hhzj1r67chlo9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F105ti4hhzj1r67chlo9d.png" alt="http://localhost:8080/" width="799" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Deploy to Azure
&lt;/h2&gt;

&lt;p&gt;From within the project folder, you can deploy the project by running &lt;code&gt;az webapp up --runtime "PHP:8.0" --resource-group jsteinbring-demo-apps --name JWS-PHP-Example --os-type=linux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyxxkzetkdvulexjm23a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyxxkzetkdvulexjm23a.png" alt="az webapp up --runtime " width="795" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, you can visit &lt;a href="https://jws-php-example.azurewebsites.net/"&gt;https://jws-php-example.azurewebsites.net/&lt;/a&gt; to see the end-result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7l5t44wcq6pnj5e0y3cq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7l5t44wcq6pnj5e0y3cq.png" alt="https://jws-php-example.azurewebsites.net/" width="799" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Redeploying to Azure
&lt;/h2&gt;

&lt;p&gt;Similar to &lt;a href="https://dev.to/steinbring/how-to-deploy-a-nodejs-app-to-azure-an0"&gt;last time&lt;/a&gt;, the details for the project are stored within .azure/config, so running &lt;code&gt;az webapp up --runtime "PHP:8.0" --os-type=linux&lt;/code&gt; from the project folder should update what we have on the server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0uwpubvpy5kvbld0tgd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0uwpubvpy5kvbld0tgd.png" alt=".azure/config" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we update the index.php file ...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsgu316p8fhxjuvv17ua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsgu316p8fhxjuvv17ua.png" alt="echo " width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... and then run &lt;code&gt;az webapp up --runtime "PHP:8.0" --os-type=linux&lt;/code&gt; ...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi10wwq8agegia859it9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi10wwq8agegia859it9l.png" alt="az webapp up --runtime " width="795" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... the app should deploy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jws-php-example.azurewebsites.net/"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faikv9fbd7hk2w7ld7qfq.png" alt="https://jws-php-example.azurewebsites.net/" width="799" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike last time, with PHP we do need to specify the runtime when updating the application.  The process is pretty similar, though.&lt;/p&gt;

&lt;p&gt;Have any questions, comments, or concerns? See something that I am doing wrong here? Please feel free to drop a comment, below.&lt;/p&gt;

&lt;p&gt;[ Cover photo by &lt;a href="https://unsplash.com/@vishnurnair?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Vishnu R Nair&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/hacking?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt; ]&lt;/p&gt;

</description>
      <category>php</category>
      <category>azure</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to deploy a Node.js app to Azure</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Thu, 08 Sep 2022 11:07:03 +0000</pubDate>
      <link>https://dev.to/steinbring/how-to-deploy-a-nodejs-app-to-azure-an0</link>
      <guid>https://dev.to/steinbring/how-to-deploy-a-nodejs-app-to-azure-an0</guid>
      <description>&lt;p&gt;So far, we haven't talked much about &lt;a href="https://jws.news/tag/azure/"&gt;Azure&lt;/a&gt; or &lt;a href="https://jws.news/tag/node-js/"&gt;Node.js&lt;/a&gt; on either of my blogs.  The only Azure-specific post that I could find was the &lt;a href="https://dev.to/steinbring/ms-is-eoling-azure-functions-which-use-net-core-31-on-december-3-b85"&gt;MS is EOLing Azure Functions which use .NET Core 3.1 on December 3&lt;/a&gt; from July.  I figured that we would address that, today.  In today's tutorial, we are going to be covering how to deploy a node app to Azure using the command-line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites:  Node, NPM, and Azure CLI
&lt;/h2&gt;

&lt;p&gt;Before we go any further, you should make sure that you have &lt;a href="https://nodejs.org/en/"&gt;node and NPM&lt;/a&gt; installed and that you have the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"&gt;Azure CLI&lt;/a&gt; installed.  You can see if you have node installed by running &lt;code&gt;node --version&lt;/code&gt; from the terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxppdxytfnrsx7wjnge29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxppdxytfnrsx7wjnge29.png" alt="node --version" width="655" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a Node.js app to deploy
&lt;/h2&gt;

&lt;p&gt;For this example, we'll use the &lt;a href="https://expressjs.com/en/starter/generator.html"&gt;Express Generator&lt;/a&gt;.  You can create your new app by running &lt;code&gt;npx express-generator node-example --view ejs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3qxf2fs8aa83x60d30j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3qxf2fs8aa83x60d30j.png" alt="npx express-generator node-example --view ejs" width="655" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, if you &lt;code&gt;cd node-example &amp;amp;&amp;amp; npm install&lt;/code&gt;, you will navigate into the project folder and install the dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibtypisxds7loorpbu79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibtypisxds7loorpbu79.png" alt="cd node-example &amp;amp;&amp;amp; npm install" width="655" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, you can run the server by just running &lt;code&gt;npm start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmha0fbnbnhwj83o7yu7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmha0fbnbnhwj83o7yu7z.png" alt="npm start" width="655" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to get the debugging info also, you can alternately run &lt;code&gt;DEBUG=node-example:* npm start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4diljzpv8a61xnt0ouu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4diljzpv8a61xnt0ouu.png" alt="DEBUG=node-example:* npm start" width="655" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the server running, you can see the output at &lt;a href="http://localhost:3000/"&gt;http://localhost:3000/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4aj7u228zqu846owwl3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4aj7u228zqu846owwl3.png" alt="http://localhost:3000/" width="653" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Change the server port
&lt;/h2&gt;

&lt;p&gt;As you can see above, the server is using port 3000 but if you open bin/www and look for &lt;code&gt;process.env.PORT&lt;/code&gt;, you can change what port the startup script uses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffc2991kk55fon4euzrrw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffc2991kk55fon4euzrrw.png" alt="process.env.PORT" width="740" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we are going to deploy this to Azure, we should probably change that to 80.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Deploy to Azure
&lt;/h2&gt;

&lt;p&gt;From within the project folder, you can deploy the project by running &lt;code&gt;az webapp up --sku F1 --name &amp;lt;unique-project-name&amp;gt;&lt;/code&gt;.  The &lt;code&gt;&amp;lt;unique-project-name&amp;gt;&lt;/code&gt; bit must be a value that is unique across all of azure and contain only characters that are a-z, 0-9, and -.  The &lt;code&gt;F1&lt;/code&gt; SKU is on their free-pricing tier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxneb15u9jxlexf0lvtm0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxneb15u9jxlexf0lvtm0.png" alt="az webapp up --sku F1 --name JWS-Node-Example" width="655" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, your node app is live.  You can see the demo app at &lt;a href="http://jws-node-example.azurewebsites.net"&gt;http://jws-node-example.azurewebsites.net&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3mwuwanz8hr6t7n1u9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3mwuwanz8hr6t7n1u9o.png" alt="https://jws-node-example.azurewebsites.net/" width="653" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Redeploying to Azure
&lt;/h2&gt;

&lt;p&gt;The next, natural question is how to redeploy the app after you make changes to it.  If we look at routes/index.js, the variable &lt;code&gt;title&lt;/code&gt; is set to the value "Express" on line 6.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx7cpunuq5fjtd3haq7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx7cpunuq5fjtd3haq7n.png" alt="routes/index.js" width="702" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we change that value to "Flavortown", it should change the output on the site.  To save your changes to Azure, you can use the terminal command &lt;code&gt;az webapp up&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbzf1sbrd14ofajm31mv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbzf1sbrd14ofajm31mv.png" alt="az webapp up" width="634" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will notice that the command that we used had no arguments.  If you look into .azure/config within the project folder, the details are defined there.  If you need to change something, you can do it there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzn5y2sene54az77bnym5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzn5y2sene54az77bnym5.png" alt=".azure/config" width="702" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, &lt;a href="https://jws-node-example.azurewebsites.net/"&gt;our demo site&lt;/a&gt; says "Welcome to Flavortown".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fga6o5oztdgkxvjjkru7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fga6o5oztdgkxvjjkru7f.png" alt="https://jws-node-example.azurewebsites.net/" width="660" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have any questions, comments, or concerns?  See something that I am doing wrong here?  Please feel free to drop a comment, below.  I am by no means an expert in &lt;a href="https://jws.news/tag/node-js/"&gt;Node&lt;/a&gt; or &lt;a href="https://jws.news/tag/azure/"&gt;Azure&lt;/a&gt; but hopefully we can help each other.&lt;/p&gt;

&lt;p&gt;[ Cover photo by &lt;a href="https://unsplash.com/@arget?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Arget&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/hacking?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt; ]&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>azure</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Better living through database normalization</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Tue, 26 Jul 2022 09:26:24 +0000</pubDate>
      <link>https://dev.to/steinbring/better-living-through-database-normalization-36oc</link>
      <guid>https://dev.to/steinbring/better-living-through-database-normalization-36oc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note:  This is a &lt;a href="https://jws.news/2013/better-living-through-database-normalization/"&gt;republication of a post&lt;/a&gt; that I wrote almost 10 years ago, &lt;a href="https://jws.news/"&gt;over on my other blog&lt;/a&gt;.  I was on vacation last week and I am at &lt;a href="https://that.us/events/wi/2022/"&gt;That Conference&lt;/a&gt; this week, so I didn't have the time to write something new.  Database normalization isn't really an evolving topic, though.  Enjoy! :)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Database normalization is a process meant to reduce or eliminate data redundancy.  Typically, a normalized database exists in first normal form (1NF), second normal form (2NF), or third normal form (3NF).&lt;/p&gt;

&lt;h2&gt;
  
  
  First Normal Form
&lt;/h2&gt;

&lt;p&gt;In order for a database to be in first normal form, your tables &lt;strong&gt;must not contain repeating groups of data&lt;/strong&gt;.  Let’s look at a simple example.  In the table below, we are tracking basic contact information.  We have an ID, a first name, a last name, and the contact’s phone numbers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3wy9jiofw568bkg9kex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3wy9jiofw568bkg9kex.png" alt="Image description" width="594" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, what wrong with this table?  Users can have more than one phone number, so we are storing multiple values within the “PhoneNumbers” column.  This means that our DBMS is storing multiple values as a single value and we have to manage the phone number values manually.  How can we better this?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8fedyikowqf11qx3swk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8fedyikowqf11qx3swk.png" alt="Image description" width="321" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above example, we placed phone numbers into their own table.  We connected the contacts to their phone numbers using the “ContactID” column. Notice that there are no duplicate rows and every row/column intersection contains exactly one value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second Normal Form
&lt;/h2&gt;

&lt;p&gt;In order for a database to be in second normal form, it first must satisfy the conditions for first normal form.  In addition to that, &lt;strong&gt;all of it’s non-key attributes must be fully dependent upon its primary key&lt;/strong&gt;.  Let’s look at a table that tracks the things our contacts are experts in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7964e0ypf3q59eb9tjrl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7964e0ypf3q59eb9tjrl.png" alt="Image description" width="427" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will notice in the above table that contacts #2 and #3 are experts in two things.  In the case of contact #2, he is an expert in PHP and Digital Design.  You will also notice that we keep repeating the facility where the contact is.  This was probably placed there to make it easy to find a ColdFusion expert at the Downtown facility.  This example table can cause problems because, if contact #2 relocates to the Downtown facility, there is a chance that only one record will be modified, leave contradicting information.  So, how do we fix it?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2mygkiix1smjee4zuhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2mygkiix1smjee4zuhu.png" alt="Image description" width="782" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this new example, the facility is now part of the “Contacts” table.  You can still find your ColdFusion expert at the Downtown office but you can avoid update anomalies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Third Normal Form
&lt;/h2&gt;

&lt;p&gt;In order for a database to be in second normal form, it first must satisfy the conditions for first normal form.  In addition to that, &lt;strong&gt;the columns should depend solely upon the primary key of the table&lt;/strong&gt;.  What does this mean?  Let’s take a look at our “Contact Expertise” table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cn2wrnlqtrjnkqljdqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cn2wrnlqtrjnkqljdqg.png" alt="Image description" width="286" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s say that we want to see a list of possible skills somebody could be an expert in.  This could be so that we can indicate which skill a new contact is an expert in.  Right now, we can query “Contact Expertise” for unique values in the “Expertise” column but if we don’t already have an expert in that skill, it won’t be available as an option.  We can solve that with a “Skills” table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag9q2odml7j4rxx2q0lx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag9q2odml7j4rxx2q0lx.png" alt="Image description" width="522" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that you can now query for possible skills that a contact can specialize in.  Additionally, all values are dependent upon the primary key of the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to “cheat” at database normalization
&lt;/h2&gt;

&lt;p&gt;A recent post on the &lt;a href="http://blogs.perl.org/users/ovid/2013/07/how-to-fake-database-design.html"&gt;Perl blog&lt;/a&gt; had a great set of rules to make sure your database is adequately normalized.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Every “noun” gets its own table.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“many to many” relationship get their own tables&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“one to many” relationship require the table that “owns” another table have its ID in that other table&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any time a table has an ID that refers to a row in another table, use a foreign key constraint to make sure that ID really exists&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember, your database is the foundation of your application.  If you build it wrong, your application will struggle to succeed.&lt;/p&gt;

</description>
      <category>database</category>
      <category>rdbms</category>
      <category>sql</category>
    </item>
    <item>
      <title>I’m speaking at That Conference Wisconsin, the week after next.</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Tue, 12 Jul 2022 12:33:36 +0000</pubDate>
      <link>https://dev.to/steinbring/im-speaking-at-that-conference-wisconsin-the-week-after-next-387e</link>
      <guid>https://dev.to/steinbring/im-speaking-at-that-conference-wisconsin-the-week-after-next-387e</guid>
      <description>&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;Well, heck.  I just heard this morning that they are moving my talk to September 15's &lt;a href="https://that.us/events/thatus/2022-9/"&gt;THAT Online - September&lt;/a&gt;.  The problem is that I land in Delhi, India at 1pm (local time) on Sept 15th.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, I am speaking at &lt;a href="https://that.us/events/wi/2022/"&gt;That Conference&lt;/a&gt;, later this month.  I will be giving the talk “&lt;a href="https://that.us/activities/4CYljqsNWFJrs70dvEp6"&gt;Locating your user in meatspace&lt;/a&gt;” on Tuesday, July 26, 2022 at 1:00 PM CDT.  Swing by and I’ll show you what I have learned about geolocation and how to add it to your web application. You can pick up a $99 “ON THAT Camper” ticket at:  &lt;a href="https://that.us/events/wi/2022/tickets/"&gt;https://that.us/events/wi/2022/tickets/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What am I going to cover?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to &lt;a href="https://jws.news/tag/geolocation/"&gt;find your user’s location&lt;/a&gt; using &lt;a href="https://jws.news/2020/how-to-get-the-users-street-address-using-navigator-geolocation-and-mapquest/"&gt;what their device returns&lt;/a&gt; and using &lt;a href="https://codepen.io/steinbring/pen/MWvwMgb"&gt;their IP Address&lt;/a&gt; (and &lt;a href="https://jws.news/2021/state-parks-app-i-made-some-new-apis-for-the-app/"&gt;how to make IP-based geolocation suck less&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;How to use the &lt;a href="https://www.census.gov/"&gt;United States census bureau&lt;/a&gt;‘s &lt;a href="https://www.census.gov/geographies/reference-files/time-series/geo/gazetteer-files.html"&gt;U.S. Gazetteer Files&lt;/a&gt; to build a web service to convert from a zip code to latitude/longitude coordinates and from a city and state to latitude/longitude coordinates.&lt;/li&gt;
&lt;li&gt;Finally, I intend to show how to &lt;a href="https://jws.news/2021/how-to-sort-a-list-of-locations-by-how-close-they-are-to-you/"&gt;use the haversine formula to determine the distance between where the user is and possible points of interest&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the process, I am also going to show how to &lt;a href="https://dev.to/steinbring/i-built-my-first-cloudflare-worker-1aa4"&gt;use Cloudflare workers to minimize the amount of this logic that you have on the client side&lt;/a&gt;.  Hopefully you find this mildly interesting.&lt;/p&gt;

&lt;p&gt;I’ll see you there!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>MS is EOLing Azure Functions which use .NET Core 3.1 on December 3</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Tue, 05 Jul 2022 11:36:52 +0000</pubDate>
      <link>https://dev.to/steinbring/ms-is-eoling-azure-functions-which-use-net-core-31-on-december-3-b85</link>
      <guid>https://dev.to/steinbring/ms-is-eoling-azure-functions-which-use-net-core-31-on-december-3-b85</guid>
      <description>&lt;p&gt;Earlier this month, Microsoft sent out an email stating that "&lt;strong&gt;On 3 December 2022, .NET Core 3.1 will be retired. As a result, Azure Functions runtime versions 2.x and 3.x, which use .NET Core 3.1, will also be retired on that date.&lt;/strong&gt;"  They went on to encourage folks to update their Functions applications to use runtime version 4.x before then.  My intention is to use this article to explore the differences between .NET Core 3.1 and more modern versions and ultimately figure out what changes you might need to make to your code.&lt;/p&gt;

&lt;p&gt;Microsoft is infamous for supporting dependencies for a frighteningly long time.  If we look back at the &lt;strong&gt;&lt;em&gt;breaking&lt;/em&gt;&lt;/strong&gt; changes between .NET Core 3.0 and 3.1, the biggest change was to how &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite"&gt;SameSite cookies&lt;/a&gt; (something supported since .NET Core 2.0) are handled.  There was a change to the standards that meant that if the SameSite attribute is not specified, the cooke would default to &lt;code&gt;SameSite=Lax&lt;/code&gt;.  Previously, the default was that cookies were sent for all requests.  With &lt;code&gt;SameSite=Lax&lt;/code&gt;, cookies are not sent on normal cross-site subrequests.  In .NET Core 3.1, it changed the behavior for &lt;code&gt;SameSiteMode.None&lt;/code&gt; and added a new &lt;code&gt;SameSiteMode.Unspecified&lt;/code&gt; value to deal with this change.&lt;/p&gt;

&lt;p&gt;So, what version do you move to next?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkg1n08u87h4qsb8795uh.png" alt=".NET and .NET Core release lifecycle" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3.1 was the old LTS (Long Term Support) version.  With 5.0 going out of support on May 5th and 7.0 still being only a release candidate, your only remaining option seems to be the new LTS version (6.0.6).  Version 6 goes out of support on November 12, 2024.  Since .NET 6 isn't .Net &lt;em&gt;&lt;strong&gt;Core&lt;/strong&gt;&lt;/em&gt; 6, the upgrade path looks a little complicated, though.  My suggestion would be to check out &lt;strong&gt;&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/migration/31-to-60?view=aspnetcore-6.0&amp;amp;tabs=visual-studio-mac"&gt;Migrate from ASP.NET Core 3.1 to 6.0&lt;/a&gt;&lt;/strong&gt; on the microsoft site.&lt;/p&gt;

&lt;p&gt;Have any any additional advice for folks dealing with this upgrade?  Have a question?  Please feel free to drop a comment, below.  I'm not normally a ".NET Guy", so I'm learning this stuff as I go too. :)&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>azure</category>
      <category>dotnetcore</category>
    </item>
    <item>
      <title>How to add a JavaScript calendar to your Vue.js app</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Tue, 28 Jun 2022 12:51:45 +0000</pubDate>
      <link>https://dev.to/steinbring/how-to-add-a-javascript-calendar-to-your-vuejs-app-1omo</link>
      <guid>https://dev.to/steinbring/how-to-add-a-javascript-calendar-to-your-vuejs-app-1omo</guid>
      <description>&lt;p&gt;In last week's post, we went over &lt;a href="https://dev.to/steinbring/how-to-add-a-javascript-calendar-to-your-app-59oo"&gt;how to add a JavaScript calendar to your app&lt;/a&gt;.  This week, we are going to go over how to add a calendar to your &lt;a href="https://blog.jws.app/tag/vue-js/"&gt;Vue.js&lt;/a&gt; app, while using the &lt;a href="https://blog.jws.app/tag/vue-cli/"&gt;Vue CLI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first step is to &lt;a href="https://cli.vuejs.org/guide/installation.html"&gt;install Vue CLI&lt;/a&gt; and &lt;a href="https://cli.vuejs.org/guide/creating-a-project.html"&gt;create the app&lt;/a&gt;.  (We have &lt;a href="https://blog.jws.app/2021/playing-with-the-vue-cli-and-webpack/"&gt;done this once before&lt;/a&gt; if you wanted to see a deeper dive into the process.)  If you navigate into the folder from your terminal and run &lt;code&gt;npm run serve&lt;/code&gt;, you should then be able open &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt; in a web browser and see the Vue CLI "hello world" app.&lt;/p&gt;

&lt;p&gt;Next, to install the &lt;a href="https://fullcalendar.io/docs/vue"&gt;FullCalendar plugins&lt;/a&gt;, you can run &lt;code&gt;npm install --save @fullcalendar/vue3 @fullcalendar/core @fullcalendar/daygrid @fullcalendar/timegrid&lt;/code&gt;.  After that, you should be able to build out your calendar component like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fullcalendar/core/vdom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// solves problem with Vite&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;FullCalendar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fullcalendar/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dayGridPlugin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fullcalendar/daygrid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;timeGridPlugin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fullcalendar/timegrid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;interactionPlugin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fullcalendar/interaction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;FullCalendar&lt;/span&gt; &lt;span class="c1"&gt;// make the &amp;lt;FullCalendar&amp;gt; tag available&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;calendarOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;dayGridPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeGridPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;interactionPlugin&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;initialView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayGridMonth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// Don't show the weekends&lt;/span&gt;
        &lt;span class="na"&gt;weekends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// Define the header for the calendar&lt;/span&gt;
        &lt;span class="na"&gt;headerToolbar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prev,next today&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayGridMonth,timeGridWeek,timeGridDay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// Define Event Data&lt;/span&gt;
        &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://gist.githubusercontent.com/steinbring/80157cc5866de53c8cd975a1673f4425/raw/72d8dfb2880b76ffbd7bb8a48f3803aab3b804ba/events.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FullCalendar&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calendarOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You might remember last time, &lt;a href="https://codepen.io/steinbring/pen/qBxJrQj"&gt;we built out a calendar&lt;/a&gt; that gets its data from a &lt;a href="https://gist.githubusercontent.com/steinbring/80157cc5866de53c8cd975a1673f4425/raw/72d8dfb2880b76ffbd7bb8a48f3803aab3b804ba/events.json"&gt;mock JSON api&lt;/a&gt; that we created.  This demo should use the same header layout, use the same defaults, and (most importantly) use that same mock API.  I created &lt;a href="https://github.com/steinbring/vue-calendar-demo"&gt;a github repo showing how to do this&lt;/a&gt; as well as &lt;a href="https://vue-calendar-demo.jws.app/"&gt;a demo site, so that you can see the end-result&lt;/a&gt;.  The demo URL is hosted on &lt;a href="https://render.com/"&gt;Render&lt;/a&gt;, &lt;a href="https://blog.jws.app/tag/render/"&gt;like my previous examples&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/steinbring"&gt;
        steinbring
      &lt;/a&gt; / &lt;a href="https://github.com/steinbring/vue-calendar-demo"&gt;
        vue-calendar-demo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An example of how to use FullCalendar with a vue app
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;vue-calendar-demo&lt;/h1&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project setup&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Compiles and hot-reloads for development&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm run serve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Compiles and minifies for production&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Lints and fixes files&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm run lint
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Customize configuration&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;See &lt;a href="https://cli.vuejs.org/config/" rel="nofollow"&gt;Configuration Reference&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/steinbring/vue-calendar-demo"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;The next step in this journey is to show how to replace that mock api with a real one.  Stay tuned for that.  Until then, feel free to drop a comment if you have any question, comments, etc.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>fullcalendar</category>
      <category>vue</category>
    </item>
    <item>
      <title>How to add a JavaScript calendar to your app</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Tue, 21 Jun 2022 12:04:18 +0000</pubDate>
      <link>https://dev.to/steinbring/how-to-add-a-javascript-calendar-to-your-app-59oo</link>
      <guid>https://dev.to/steinbring/how-to-add-a-javascript-calendar-to-your-app-59oo</guid>
      <description>&lt;p&gt;I recently got it into my head that I wanted to figure out how I would write a "time-off calendar".  Feature zero of any time-off calendar tends to be the calendar itself.  Today, I figured that we would look at one option for that.&lt;/p&gt;

&lt;p&gt;I combed through the assorted google results and found a promising looking solution called &lt;a href="https://fullcalendar.io/"&gt;FullCalendar&lt;/a&gt;.  It advertises itself as working with &lt;a href="https://dev.to/t/react"&gt;React&lt;/a&gt;, &lt;a href="https://dev.to/t/vue"&gt;Vue&lt;/a&gt;, &lt;a href="https://dev.to/t/angular"&gt;Angular&lt;/a&gt;, or just plain &lt;a href="https://dev.to/t/javascript"&gt;javascript&lt;/a&gt;.  For today's post, we are going to be looking at their vanilla-javascript, 100% framework agnostic solution.&lt;/p&gt;

&lt;p&gt;Let's start by looking at &lt;a href="https://codepen.io/steinbring/pen/abqRdXW"&gt;the absolutely, most basic example of a monthly calendar&lt;/a&gt; with the library.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/abqRdXW?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You will notice that we are waiting for the DOM to load, using &lt;code&gt;document.getElementById()&lt;/code&gt; to identify the element that is going to contain the calendar, and then we are using that new &lt;code&gt;calendarEl&lt;/code&gt; element to render the calendar.  We are defining an &lt;a href="https://fullcalendar.io/docs/initialView"&gt;initialView&lt;/a&gt; of 'dayGridMonth' but there are the alternate options 'dayGridWeek', 'timeGridDay', or 'listWeek'.&lt;/p&gt;

&lt;p&gt;There are a lot more options that you can apply to a calendar, beyond just &lt;a href="https://fullcalendar.io/docs/initialView"&gt;initialView&lt;/a&gt;.  For &lt;a href="https://codepen.io/steinbring/pen/bGLmqoQ"&gt;our next example&lt;/a&gt;, let's check out &lt;a href="https://fullcalendar.io/docs/weekends"&gt;weekends&lt;/a&gt; and &lt;a href="https://fullcalendar.io/docs/headerToolbar"&gt;headerToolbar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/bGLmqoQ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;By setting &lt;code&gt;weekends&lt;/code&gt; to false, we are getting closer to the "time-off calendar" vibe and the &lt;code&gt;headerToolbar&lt;/code&gt; value allows us to both make the calendar look less "standard" and expose the "month", "week", and "day" toggles.  The &lt;a href="https://fullcalendar.io/docs/toolbar"&gt;toolbar&lt;/a&gt; has a heck of a lot more options, too.&lt;/p&gt;

&lt;p&gt;So, the next step is to populate the calendar with actual events.  In our next example, &lt;a href="https://codepen.io/steinbring/pen/ExQdWQy"&gt;we are directly populating an "events" object with an array of events&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/ExQdWQy?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;When creating an event, &lt;a href="https://fullcalendar.io/docs/event-object"&gt;there are a lot of options available&lt;/a&gt;.  For this example, we are going to keep it pretty basic, though.  We have two multi-day events and two single-day events.  Each event has a unique ID, a title, a start, and a background color.  The multi-day events also have an end.  The start and end values take a &lt;a href="https://fullcalendar.io/docs/date-object"&gt;date object&lt;/a&gt; and can include a time.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://codepen.io/steinbring/pen/qBxJrQj"&gt;our final example&lt;/a&gt;, we are going to look at how pull in the event data from &lt;a href="https://gist.githubusercontent.com/steinbring/80157cc5866de53c8cd975a1673f4425/raw/72d8dfb2880b76ffbd7bb8a48f3803aab3b804ba/events.json"&gt;a JSON endpoint&lt;/a&gt;.  Instead of creating an actual back-end for this thing, I just spun something up using &lt;a href="https://gist.github.com/steinbring/80157cc5866de53c8cd975a1673f4425"&gt;GitHub Gist&lt;/a&gt;.  Of course, I would recommend using something like &lt;a href="https://blog.jws.app/tag/laravel/"&gt;Laravel&lt;/a&gt; or &lt;a href="https://firebase.google.com/"&gt;Firebase&lt;/a&gt; for an actual back-end. &lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/qBxJrQj?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As you can see, adding a JSON feed instead of an object as a value for "events" is all that is needed.  There are &lt;a href="https://fullcalendar.io/docs/event-source-object"&gt;a lot more options available&lt;/a&gt;, though.  You can even use an &lt;a href="https://fullcalendar.io/docs/icalendar"&gt;iCalendar feed&lt;/a&gt; instead of a &lt;a href="https://fullcalendar.io/docs/events-json-feed"&gt;JSON feed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, what's next?  Next week, there will be a follow-up on how to do the same thing, using &lt;a href="https://blog.jws.app/tag/vue-js/"&gt;vue.js&lt;/a&gt;.  After that, I intend to show how to incorporate &lt;a href="https://dev.to/t/laravel"&gt;Laravel&lt;/a&gt; into the picture.  If you want to follow along, I suggest &lt;a href="https://dev.to/steinbring"&gt;following me on here&lt;/a&gt; and checking out &lt;a href="https://blog.jws.app/"&gt;my other blog&lt;/a&gt;.  Until then, please feel free to leave a comment if you have any questions, comments, etc.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>fullcalendar</category>
      <category>json</category>
      <category>ajax</category>
    </item>
    <item>
      <title>Internet Explorer is officially out of support!</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Wed, 15 Jun 2022 11:38:49 +0000</pubDate>
      <link>https://dev.to/steinbring/internet-explorer-is-officially-out-of-support-2p50</link>
      <guid>https://dev.to/steinbring/internet-explorer-is-officially-out-of-support-2p50</guid>
      <description>&lt;p&gt;As of today, (June 15, 2022) &lt;a href="https://docs.microsoft.com/en-us/lifecycle/announcements/internet-explorer-11-end-of-support"&gt;Microsoft no longer supports Internet Explorer 11&lt;/a&gt; (the final version of IE)!  &lt;a href="https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/"&gt;Internet Explorer mode&lt;/a&gt; still exists in Edge but you no longer need to worry about compatibility with the world's least compliant browser.&lt;/p&gt;

&lt;p&gt;There was a time in my career where I worked for a company that once forbid folks from running anything other than IE6.  If you were caught running FireFox, HR would write you up for it.  Since then, FireFox, Chrome, Safari, and (eventually) Edge have successfully built a following and helped push the internet forward.&lt;/p&gt;

&lt;p&gt;I am excited about the prospect of an IE-free future. :)&lt;/p&gt;

</description>
      <category>internetexplorer</category>
      <category>ie</category>
      <category>ie11</category>
      <category>internetexplorer11</category>
    </item>
    <item>
      <title>How to calculate the distance between two points, using the MapQuest API</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Tue, 14 Jun 2022 11:41:39 +0000</pubDate>
      <link>https://dev.to/steinbring/how-to-calculate-the-distance-between-two-points-using-the-mapquest-api-308m</link>
      <guid>https://dev.to/steinbring/how-to-calculate-the-distance-between-two-points-using-the-mapquest-api-308m</guid>
      <description>&lt;p&gt;Previously, we looked at &lt;a href="https://dev.to/steinbring/how-to-calculate-the-distance-between-two-points-using-math-27gh"&gt;how to calculate the distance between two points using just math&lt;/a&gt;.  The problem with that is that the distance is calculated "as the crow flies".  Calculating the distance between Milwaukee and Chicago is close enough but the distance between Milwaukee and Ludington could be a problem (since Lake Michigan is a thing).&lt;/p&gt;

&lt;p&gt;If we modify the example from last week to &lt;a href="https://codepen.io/steinbring/pen/jOZvEdb"&gt;look at the distance between Ludington and Milwaukee&lt;/a&gt;, you can see what I mean.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/jOZvEdb?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The result comes back as 96.6 miles but if you take the &lt;a href="https://www.lake-express.com/"&gt;ferry from Milwaukee to Muskegon&lt;/a&gt;, it is really 148 miles and if you go around the bottom of the lake, the distance is 333 miles.  The difference is significant.&lt;/p&gt;

&lt;p&gt;Luckily, there are services out there that you can use to do these calculations.  For &lt;a href="https://codepen.io/steinbring/pen/RwQYPmW"&gt;today's demo&lt;/a&gt;, we are going to look at &lt;a href="https://developer.mapquest.com/"&gt;MapQuest&lt;/a&gt; and specifically the &lt;a href="https://developer.mapquest.com/documentation/directions-api/route/get"&gt;the Route end-point&lt;/a&gt; of &lt;a href="https://developer.mapquest.com/documentation/directions-api/"&gt;the Directions API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/RwQYPmW?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As you can see, the API takes an API key, the origin of the trip, and the destination of the trip.  It returns all of the details of the trip but for this example, we only really care about the distance.  For more complex queries, MapQuest also offers a &lt;a href="https://developer.mapquest.com/documentation/directions-api/route-matrix/post"&gt;Route Matrix API&lt;/a&gt;.  That one can go beyond a point-to-point trip and handle many more destinations.&lt;/p&gt;

&lt;p&gt;Have any questions, comments, etc?  Feel free to drop a comment, below.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>maps</category>
      <category>mapquest</category>
    </item>
    <item>
      <title>How to calculate the distance between two points, using math</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Tue, 07 Jun 2022 12:16:51 +0000</pubDate>
      <link>https://dev.to/steinbring/how-to-calculate-the-distance-between-two-points-using-math-27gh</link>
      <guid>https://dev.to/steinbring/how-to-calculate-the-distance-between-two-points-using-math-27gh</guid>
      <description>&lt;p&gt;Roughly a year ago, I wrote a post about &lt;a href="https://blog.jws.app/2021/how-to-sort-a-list-of-locations-by-how-close-they-are-to-you/"&gt;how to sort a list of physical locations by how close they are to you&lt;/a&gt;.  At the time, I was working on &lt;a href="https://blog.jws.app/tag/state-parks-app/"&gt;an app that needed to know how close you were to each of Wisconsin's State Parks&lt;/a&gt;.  On July 26, I am giving &lt;a href="https://that.us/activities/4CYljqsNWFJrs70dvEp6"&gt;an online presentation at That Conference on the topic of "Locating your user in meatspace"&lt;/a&gt; and ahead of that, I wanted to drill down on the topic of how to calculate the distance between two point while only using math to do so.&lt;/p&gt;

&lt;p&gt;So, how do you do that?  You use the Haversine formula.  Now, I am not a great mathematician according to &lt;a href="https://community.esri.com/t5/coordinate-reference-systems-blog/distance-on-a-sphere-the-haversine-formula/ba-p/902128"&gt;Simon Kettle&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The haversine formula is a very accurate way of computing distances between two points on the surface of a sphere using the latitude and longitude of the two points. The haversine formula is a re-formulation of the spherical law of cosines, but the formulation in terms of haversines is more useful for small angles and distances.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;According to &lt;a href="https://community.esri.com/t5/coordinate-reference-systems-blog/distance-on-a-sphere-the-haversine-formula/ba-p/902128"&gt;Kettle&lt;/a&gt;, the word "Haversine" comes from the function: haversine(θ) = sin²(θ/2).  &lt;a href="https://codepen.io/steinbring/pen/jOZpjKQ"&gt;The formula can be used in javascript code like so&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/jOZpjKQ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The output is in kilometers but since 1 kilometer is equal to 0.621371 miles, it should be reasonably easy to &lt;a href="https://codepen.io/steinbring/pen/XWZBvrm"&gt;convert the output to miles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/XWZBvrm?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;So, what do you think?  How are you going to use the haversine formula in your projects?  Feel free to let me know in the comments, below.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>maps</category>
      <category>haversine</category>
    </item>
    <item>
      <title>What are koans and how can they help level up your dev game?</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Thu, 02 Jun 2022 11:49:22 +0000</pubDate>
      <link>https://dev.to/steinbring/what-are-koans-and-how-can-they-help-level-up-your-dev-game-b8g</link>
      <guid>https://dev.to/steinbring/what-are-koans-and-how-can-they-help-level-up-your-dev-game-b8g</guid>
      <description>&lt;p&gt;A koan is a story, dialogue, question, or statement which is used in Zen practice to provoke the “great doubt” and to practice or test a student’s progress in Zen.  In the Zen school of Rinzai, the use of koans (often a paradoxical statement) is used to initiate the internal socratic method in the students, to break down prior deeply held notions that hold them back from Enlightenment.  An example of a koan is the question “What do you call the world?”&lt;/p&gt;

&lt;p&gt;So, what does this have to do with application development?  There are technology-specific koans out there like &lt;a href="http://rubykoans.com/"&gt;Ruby Koans&lt;/a&gt;, &lt;a href="http://blog.bittersweetryan.com/2011/10/introducing-coldfusion-koans-learn.html"&gt;ColdFusion Koans&lt;/a&gt;, &lt;a href="https://github.com/gregmalcolm/python_koans"&gt;Python Koans&lt;/a&gt;, and a number of different versions of &lt;a href="https://github.com/mrdavidlaing/javascript-koans"&gt;JavaScript&lt;/a&gt; &lt;a href="https://github.com/liammclennan/JavaScript-Koans"&gt;Koans&lt;/a&gt;.  The goals of each project is to teach the particular technology through testing.  A test runner like &lt;a href="https://jasmine.github.io/"&gt;Jasmine&lt;/a&gt;, &lt;a href="https://qunitjs.com/"&gt;QUnit&lt;/a&gt;, or &lt;a href="http://mxunit.org/"&gt;MXUnit&lt;/a&gt; is usually used.  With koans, you need to run the tests and see them fail, make the tests pass, and then take a moment to reflect upon the test to see what it is teaching you.  In doing this, the hope is that you will become a better coder.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://blog.jws.app/2022/what-are-koans-and-how-can-they-help-level-up-your-dev-game/"&gt;What are koans and how can they help level up your dev game?&lt;/a&gt; appeared first on &lt;a href="https://blog.jws.app"&gt;Blog.jws&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>coding</category>
      <category>koans</category>
      <category>tdd</category>
    </item>
    <item>
      <title>I built my first Cloudflare worker</title>
      <dc:creator>Joe Steinbring</dc:creator>
      <pubDate>Thu, 28 Oct 2021 12:21:53 +0000</pubDate>
      <link>https://dev.to/steinbring/i-built-my-first-cloudflare-worker-1aa4</link>
      <guid>https://dev.to/steinbring/i-built-my-first-cloudflare-worker-1aa4</guid>
      <description>&lt;p&gt;In the past two years, I have written a few blog posts that explored how to figure out where the user physically is.  Most of these experiments involved &lt;a href="https://blog.jws.app/2020/how-to-get-the-users-street-address-using-navigator-geolocation-and-mapquest/"&gt;navigator.geolocation&lt;/a&gt; but last week's &lt;a href=""&gt;iOS 15, Private Relay, and Geolocation&lt;/a&gt; post brought in the concept of figuring out the person's location based upon their IP address.  After finishing that post, I started to wonder what it would take to simplify things.  Can I reduce the number of API calls to things and make the result more reliable?  In the process, I decided that I would also wrap things up into a central Cloudflare worker.&lt;/p&gt;

&lt;p&gt;So, let's see what the guts of the worker look like.&lt;/p&gt;


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


&lt;p&gt;As you can see above, a lot of the returned data is just &lt;a href="https://dev.to/steinbring/get-a-user-s-ip-address-using-just-javascript-and-an-api-call-24n5"&gt;things that cloudflare knows about you, out of the gate&lt;/a&gt; but in order to get your likely street address, &lt;a href="https://blog.jws.app/2020/how-to-get-the-users-street-address-using-navigator-geolocation-and-mapquest/"&gt;an API call to Mapquest&lt;/a&gt; is still needed.  I also set it up so that you can pass latitude and longitude values in as get variables.  If the user is on an LTE or 5g connection, their location is likely to show up as being in a completely different place.&lt;/p&gt;

&lt;p&gt;So, how do we implement this new API?&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/steinbring/embed/zYdrLJP?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Using the "Use GPS to update position" and "Use IP to update position" buttons, you can toggle between the two modes of detection.  Basically, one passes lat/long coordinates into the API and the other leaves it up to the node script to figure it out.&lt;/p&gt;

&lt;p&gt;In a real-world setting, I would execute the IP-based detection by default and give the user the option to use the more accurate option if they wished to do so.  This is definitely getting integrated into my &lt;a href="https://blog.jws.app/tag/state-parks-app/"&gt;Wisconsin State Parks&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;Have any questions, comments, etc?  Feel free to drop a comment, below.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>geolocation</category>
      <category>cloudflare</category>
      <category>node</category>
    </item>
  </channel>
</rss>
