<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Web-Dev on dev.endevour</title><link>https://devendevour.iankulin.com/tags/web-dev/</link><description>Recent content in Web-Dev on dev.endevour</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Mon, 07 Jul 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://devendevour.iankulin.com/tags/web-dev/index.xml" rel="self" type="application/rss+xml"/><item><title>State of AI tooling (for me)</title><link>https://devendevour.iankulin.com/state-of-ai-tooling-for-me/</link><pubDate>Mon, 07 Jul 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/state-of-ai-tooling-for-me/</guid><description>&lt;p&gt;I&amp;rsquo;ve been meaning to write this for a couple of weeks, so let&amp;rsquo;s get to it - things are moving to fast to reflect too long; which is it&amp;rsquo;s own risk.&lt;/p&gt;
&lt;p&gt;In March, I wrote about &lt;a href="https://devendevour.iankulin.com/where-im-up-to-with-ai-for-coding/"&gt;how I was using AI in coding&lt;/a&gt; , which was Codeium (now Windsurf) in VS Code for completions, and ChatGPT and Claude online for architecture questions and code gen that was more than half a function.&lt;/p&gt;</description></item><item><title>End to end testing - Cypress basics</title><link>https://devendevour.iankulin.com/end-to-end-testing-cypress-basics/</link><pubDate>Mon, 12 May 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/end-to-end-testing-cypress-basics/</guid><description>&lt;p&gt;When you&amp;rsquo;ve made a change to your web-app, do you run it then click around the new bits to check it works? Good start, but instead of doing that yourself, do it in a faster, more comprehensive and automated way with an end-to-end (E2E) testing setup using &lt;a href="https://www.cypress.io/" target="_blank" rel="noopener"&gt;Cypress&lt;/a&gt; . Here&amp;rsquo;s how.&lt;/p&gt;
&lt;h3 id="e2e"&gt;E2E&lt;/h3&gt; &lt;p&gt;End to End testing is testing your app as a user might - by clicking links, entering data, looking at the screen and checking everything is okay, but it&amp;rsquo;s scripted like a unit test and the results are checked with assertions. Like unit testing this allows you to build up a collection of comprehensive tests that easily detect for unexpected behaviours - not just in the results of functions in your app, but in the user experience of the app.&lt;/p&gt;</description></item><item><title>Functional Javascript array methods</title><link>https://devendevour.iankulin.com/functional-javascript-array-methods/</link><pubDate>Mon, 14 Apr 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/functional-javascript-array-methods/</guid><description>&lt;p&gt;I&amp;rsquo;ve been whipping up a little mock-database unit that has a few access functions but actually stores the data as arrays for a demo project for a post I&amp;rsquo;m writing. In the process I wrote this gem:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;export function dbOrdersAdd(order) {
 const orderCopy = { ...order };
 // since id is a stringified number, finding the max is a bit of a mess
 const maxId = orders.reduce((max, o) =&amp;gt; Math.max(max, parseInt(o.id)), 0);
 orderCopy.id = String(maxId + 1);
 orders.push(orderCopy);
 return { ...orderCopy };
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the comment I&amp;rsquo;m claiming the code is a bit of a mess (and from a readability point that&amp;rsquo;s true) but actually I love the elegance of using the &lt;code&gt;reduce()&lt;/code&gt; method here.&lt;/p&gt;</description></item><item><title>Node.js built in test runner</title><link>https://devendevour.iankulin.com/node-js-built-in-test-runner/</link><pubDate>Mon, 17 Mar 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/node-js-built-in-test-runner/</guid><description>&lt;p&gt;For the longest time, I&amp;rsquo;ve been using &lt;a href="https://mochajs.org/" target="_blank" rel="noopener"&gt;Mocha&lt;/a&gt; (test runner) and &lt;a href="https://www.chaijs.com/" target="_blank" rel="noopener"&gt;Chai&lt;/a&gt; (assertion library) for my JS testing. They are reliable old friends.&lt;/p&gt;
&lt;p&gt;One of the effects of the existence of &lt;a href="https://bun.sh/" target="_blank" rel="noopener"&gt;Bun&lt;/a&gt; and &lt;a href="https://deno.com/" target="_blank" rel="noopener"&gt;Deno&lt;/a&gt; has been to spur Node onto adding some new features, so after appearing as an experimental feature in 18, the Node test runner dropped in Node 20.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure if the familiar unit test layout of Mocha and Node is inherited from Jest, or comes from older testing frameworks of which JUnit and NUnit were the first ones I&amp;rsquo;d ever used. Before that I just used to write tests as lumps of assertions in regular code - which worked but wasn&amp;rsquo;t as pleasant to use as a proper unit test setup. Regardless, the system of bundling a few tests together and having them all run and spit out green ticks is not a new one.&lt;/p&gt;</description></item><item><title>Where I'm up to with AI for coding</title><link>https://devendevour.iankulin.com/where-im-up-to-with-ai-for-coding/</link><pubDate>Mon, 03 Mar 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/where-im-up-to-with-ai-for-coding/</guid><description>&lt;p&gt;There&amp;rsquo;s still plenty of controversy about LLMs for coding, and not without reason. But I thought I&amp;rsquo;d run through what I&amp;rsquo;ve tried, and where I&amp;rsquo;ve landed for using AI. Also what the pitfalls are, where it&amp;rsquo;s useful and how it&amp;rsquo;s changed my practice.&lt;/p&gt;
&lt;h3 id="issues"&gt;Issues&lt;/h3&gt; &lt;h5 id="training-data"&gt;Training data&lt;/h5&gt; &lt;p&gt;The training data for large language models generally is problematic. There&amp;rsquo;s no doubt that they have been trained on copyright material. With code it&amp;rsquo;s slightly less murky since there is a high availability of good quality open source data with attached licenses to train models on. No doubt this include code written by people who don&amp;rsquo;t approve of it being used by AI, but I think the popular reading of most open source licenses is that using it for training is fine.&lt;/p&gt;</description></item><item><title>A bit of web-scraping with Cheerio</title><link>https://devendevour.iankulin.com/a-bit-of-web-scraping-with-cheerio/</link><pubDate>Mon, 17 Feb 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/a-bit-of-web-scraping-with-cheerio/</guid><description>&lt;p&gt;I had an idea for a little holiday project that required a list of episodes from &lt;a href="https://therestishistory.supportingcast.fm/" target="_blank" rel="noopener"&gt;The Rest Is History&lt;/a&gt; podcast. On their &amp;lsquo;Episodes&amp;rsquo; page, they have a player, and a list of post entries for the most recent eighteen podcasts. There is a &amp;lsquo;show all&amp;rsquo; button, but it doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2025-01-05-at-8.47.03-am.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The player does contain the full list of episodes (about 600) including a number of duplicates, so I expected if I inspected the network calls that I&amp;rsquo;d see a JSON package arriving with what I wanted. This is what I almost always find these days so I&amp;rsquo;ve had very little call to do any real web scraping - it&amp;rsquo;s normally just a matter of locating the endpoint and perhaps extracting an API key from a header.&lt;/p&gt;</description></item><item><title>Perils of Benchmarking</title><link>https://devendevour.iankulin.com/perils-of-benchmarking/</link><pubDate>Mon, 06 Jan 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/perils-of-benchmarking/</guid><description>&lt;p&gt;I&amp;rsquo;ve been containerising my websites, with their servers to make deployment simple and robust, and to move to a CI/CD workflow. Since an install of a production web server is large, I would be running about ten of these containers, and there&amp;rsquo;s already a good server facing the net and doing the reverse-proxying (NGINX Proxy Manager), I chose to bundle the Busy-Box httpd server with my sites inside the Docker containers.&lt;/p&gt;</description></item><item><title>Moving a domain from Wordpress</title><link>https://devendevour.iankulin.com/moving-a-domain-from-wordpress/</link><pubDate>Mon, 30 Dec 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/moving-a-domain-from-wordpress/</guid><description>&lt;p&gt;I love the convenience of a hosted blog on wordpress.com, but one of the justifications for my &amp;lsquo;investment&amp;rsquo; in homelab hardware and learning time was that I&amp;rsquo;d reduce my spend on hosted platforms by self-hosting them. I&amp;rsquo;ve already quit Evernote and dropped back to the free plan on Dropbox by building systems to replace them for less money and more data sovereignty. And now, the recent &lt;a href="https://techcrunch.com/2024/09/25/wordpress-org-bans-wp-engine-blocks-it-from-accessing-its-resources/" target="_blank" rel="noopener"&gt;Wordpress drama&lt;/a&gt; has made me uneasy about Matt having control of domains I&amp;rsquo;ve got registered with wordpress.&lt;/p&gt;</description></item><item><title>Updating a deployment on fly.io</title><link>https://devendevour.iankulin.com/updating-a-deployment-on-fly-io/</link><pubDate>Mon, 16 Dec 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/updating-a-deployment-on-fly-io/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/flyio_picture.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve had my external UptimeKuma chugging away on &lt;a href="https://fly.io/" target="_blank" rel="noopener"&gt;fly.io&lt;/a&gt; , for free, for months now, and the container image it was based on was a bit out of date, so I wanted to update it. I hadn&amp;rsquo;t looked at fly.io for months, and couldn&amp;rsquo;t really recall what I&amp;rsquo;d done to create it.&lt;/p&gt;
&lt;p&gt;The way this works is that that you create a fly.toml file that sets out the details of your app. From memory I think I used the one from the docs and gave it a unique name, the name of the Docker image, the port, the datacentre location, and the directory for the persisted data. The you run &lt;code&gt;fly deploy&lt;/code&gt; from the directory with the toml file (having already installed the CLI tool and logged in) and you&amp;rsquo;re in business.&lt;/p&gt;</description></item><item><title>Fixing TLS for wget in BusyBox</title><link>https://devendevour.iankulin.com/fixing-tls-for-wget-in-busybox/</link><pubDate>Mon, 25 Nov 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/fixing-tls-for-wget-in-busybox/</guid><description>&lt;p&gt;I&amp;rsquo;ve been containerising my static websites with BusyBox (because it&amp;rsquo;s small), and in &lt;a href="https://devendevour.iankulin.com/fancier-website-in-a-docker-container/"&gt;an earlier post&lt;/a&gt; showed how to even get the container to update parts of the site by reaching out with &lt;code&gt;wget&lt;/code&gt; to download resources from elsewhere and saving them inside the container where we are serving the &amp;lsquo;static&amp;rsquo; site from. I&amp;rsquo;d done this by including a bash script in the container with the &lt;code&gt;wget&lt;/code&gt; in a loop with a &lt;code&gt;sleep&lt;/code&gt;. Then started the script and the httpd server in the CMD line of the &lt;code&gt;dockerfile&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Fancier Website in a Docker Container</title><link>https://devendevour.iankulin.com/fancier-website-in-a-docker-container/</link><pubDate>Mon, 18 Nov 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/fancier-website-in-a-docker-container/</guid><description>&lt;p&gt;The previous post went over how to bundle a static website into a Docker container. That&amp;rsquo;s a neat little trick - keeping the entire website and making it trivial to install on a VPS behind Nginx Proxy Manager. It worked great for most of my little websites.&lt;/p&gt;
&lt;h3 id="but"&gt;But&amp;hellip;&lt;/h3&gt; &lt;p&gt;A couple of my websites had very minor &amp;lsquo;dynamic&amp;rsquo; content. One was pulling down the local temperature from OpenWeather, then exposing a cut-down version of that as a REST endpoint so all my servers could grab it without me being rate-limited by OpenWeather for abusing my free API key. Another one re-hosted an image that changes a couple of times a day from an unreliable service.&lt;/p&gt;</description></item><item><title>Website in a Docker Container</title><link>https://devendevour.iankulin.com/website-in-a-docker-container/</link><pubDate>Mon, 11 Nov 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/website-in-a-docker-container/</guid><description>&lt;p&gt;Having figured out how to use the GitHub package registry, I was a bit inspired by &lt;a href="https://lipanski.com/posts/smallest-docker-image-static-website" target="_blank" rel="noopener"&gt;this blog post&lt;/a&gt; from Florin Lipan to deliver all my little static websites as Docker containers. I&amp;rsquo;m not as focused as he is about making them tiny, but I did steal the idea of using &lt;a href="https://busybox.net/about.html" target="_blank" rel="noopener"&gt;BusyBox&lt;/a&gt; httpd for serving them, resulting in about 4MB containers. That&amp;rsquo;s small enough for me, and since they are all very similar, there&amp;rsquo;s a fair bit of layer reuse going on.&lt;/p&gt;</description></item><item><title>npm ERR! Exit handler never called!</title><link>https://devendevour.iankulin.com/npm-err-exit-handler-never-called/</link><pubDate>Mon, 21 Oct 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/npm-err-exit-handler-never-called/</guid><description>&lt;p&gt;I quite like GitHub scanning all my code and sending me security advisories. Here&amp;rsquo;s today&amp;rsquo;s:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2024-09-27-at-11.31.03-am.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;With these, and my &lt;a href="https://github.com/dependabot" target="_blank" rel="noopener"&gt;dependabot&lt;/a&gt; alerts, fixing them is usually just a matter of pulling down the project, running an &lt;code&gt;npm update&lt;/code&gt;, building any artifacts, then pushing it back up. But today, not so:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2024-09-27-at-11.36.57-am.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;h3 id="package-lockjson"&gt;package-lock.json&lt;/h3&gt; &lt;p&gt;It&amp;rsquo;s probably worth revisiting what the &lt;code&gt;package-lock.json&lt;/code&gt; does. It contains all the versions of any packages you&amp;rsquo;ve imported, and their dependencies. The idea is that this will make the build reproducible. We don&amp;rsquo;t commit the node_modules folder (that actually contains all that package code), but npm can reproduce it exactly by using the version information in the package-lock.json file. Here&amp;rsquo;s a snippet where you can see all those versions:&lt;/p&gt;</description></item><item><title>Code reuse by publishing to NPM</title><link>https://devendevour.iankulin.com/code-reuse-by-publishing-to-npm/</link><pubDate>Mon, 14 Oct 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/code-reuse-by-publishing-to-npm/</guid><description>&lt;p&gt;If you find yourself copying over a source file from one Node project to another because it&amp;rsquo;s a handy utility you wrote and are used to using, you&amp;rsquo;re only doing it half right. A better way to do this is to publish your utility to the &lt;a href="https://www.npmjs.com" target="_blank" rel="noopener"&gt;Node Package Manager&lt;/a&gt; (NPM). That way you can just import your utility where ever you need it, it will live in the &lt;code&gt;node_modules&lt;/code&gt; of any project that uses it, and most importantly, updates are sorted out automatically - because that&amp;rsquo;s what package managers are good at.&lt;/p&gt;</description></item><item><title>Uploading files to a web app with Node</title><link>https://devendevour.iankulin.com/uploading-files-to-a-web-app-with-node/</link><pubDate>Mon, 02 Sep 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/uploading-files-to-a-web-app-with-node/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2024-08-18-at-3.09.38-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;My default approach to web apps at the moment is Node/Express SSR. I needed to have users be able to upload files this week, and as usual there&amp;rsquo;s an express middleware that makes it trivial. This post just steps through using &lt;a href="https://github.com/expressjs/multer" target="_blank" rel="noopener"&gt;multer&lt;/a&gt; to make it simple to enable file uploads on your website.&lt;/p&gt;
&lt;h3 id="express--middleware"&gt;Express &amp;amp; middleware&lt;/h3&gt; &lt;p&gt;Before we look at file uploading, it&amp;rsquo;s worth just explaining how it fits with the other tools we&amp;rsquo;re using:&lt;/p&gt;</description></item><item><title>Authentication basics for Node apps</title><link>https://devendevour.iankulin.com/authentication-basics-for-node-apps/</link><pubDate>Mon, 19 Aug 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/authentication-basics-for-node-apps/</guid><description>&lt;p&gt;&lt;a href="https://unsplash.com/photos/calahorra-tower-torre-de-la-calahorra-in-cordoba-spain-a-fortified-gate-built-during-the-late-12th-century-by-the-almohads-to-protect-the-nearby-roman-bridge-in-the-historic-center-of-cordoba-andalusia-spain-ECsukeqrDoo" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2024-08-10-at-8.59.01-pm.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Pretty much every serious web app needs to include a way for users to log in securely and to be served their content. Since there&amp;rsquo;s a lot of complexity in this, it&amp;rsquo;s highly advisable to use good libraries to support this. In a future post we&amp;rsquo;re going to use those libraries, but first I want to explain what&amp;rsquo;s happening at the lower level and tease out some of the concepts as we build a secure system from the ground up.&lt;/p&gt;</description></item><item><title>Using LLMs for coding</title><link>https://devendevour.iankulin.com/using-llms-for-coding/</link><pubDate>Mon, 01 Jul 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/using-llms-for-coding/</guid><description>&lt;p&gt;&lt;a href="https://madmuseum.org/events/ghost-shell" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/ghost-in-the-shell_07.jpg" alt="Ghost in the Shell
© Manga Entertainment 1996
" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;This post looks at the context for some of my thinking about AI for supporting software development, and where I&amp;rsquo;ve landed on it for the time being.&lt;/p&gt;
&lt;h3 id="the-landscape"&gt;The landscape&lt;/h3&gt; &lt;p&gt;I &lt;a href="https://devendevour.iankulin.com/chatgpts-code-writing/"&gt;briefly wrote about ChatGPT&amp;rsquo;s&lt;/a&gt; coding ability at the end of 2022. The wide availability of this tool marked the beginning of what I think can fairly be described as a revolution. The controversies that have crystalised since have not dampened my amazement of this step forward in what compute can do, especially around natural language processing.&lt;/p&gt;</description></item><item><title>Peek inside a Docker image</title><link>https://devendevour.iankulin.com/peek-inside-a-docker-image/</link><pubDate>Mon, 29 Apr 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/peek-inside-a-docker-image/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2024-04-25-at-10.20.28-am.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A &amp;lsquo;dockerfile&amp;rsquo; contains all the instructions to build a Docker image. Here&amp;rsquo;s my first draft for a project I&amp;rsquo;m working on:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;FROM node:20
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [&amp;#34;node&amp;#34;, &amp;#34;server.js&amp;#34;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;COPY . .&lt;/code&gt; is copying all of the files in my project into the working directory of the image so they can be run. Of course we don&amp;rsquo;t need them all for the app - for example the &lt;code&gt;node_modules&lt;/code&gt; directory will be created when we &lt;code&gt;npm install&lt;/code&gt; so no need to copy that, and I don&amp;rsquo;t need all my dot files in the container.&lt;/p&gt;</description></item><item><title>NGINX Proxy Manager</title><link>https://devendevour.iankulin.com/nginx-proxy-manager/</link><pubDate>Mon, 15 Apr 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/nginx-proxy-manager/</guid><description>&lt;p&gt;I&amp;rsquo;ve mentioned using NGINX as an &lt;a href="https://devendevour.iankulin.com/nginx-in-front-of-a-node-js-app/"&gt;interface between the internet and a service&lt;/a&gt; a while ago. This works by all incoming traffic coming to NGINX, and NGINX determining which service that traffic should go (from the NGINX config files) then acting as a middleman. This functionality is generally referred to as a &amp;lsquo;reverse proxy&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/nginx.png" alt="Terrible drawing of NGINX proxying requests off to different services." class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;This is nice for a few reasons:&lt;/p&gt;</description></item><item><title>Deploying a Node app in Docker</title><link>https://devendevour.iankulin.com/deploying-a-node-app-in-docker/</link><pubDate>Sun, 31 Mar 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/deploying-a-node-app-in-docker/</guid><description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Cargo_ship#/media/File:Cargo_Ship_Puerto_Cortes.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/cargo_ship_puerto_cortes.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;When I wrote the install instructions for mdserver (little Markdown server Node app) on it&amp;rsquo;s &lt;a href="https://github.com/IanKulin/mdserver" target="_blank" rel="noopener"&gt;github page&lt;/a&gt; it was something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have node.js installed and working&lt;/li&gt;
&lt;li&gt;Clone the repo&lt;/li&gt;
&lt;li&gt;Start with &lt;code&gt;npm start&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which is great if you know &lt;a href="https://devendevour.iankulin.com/installing-a-node-app-on-a-server/"&gt;how to do those things&lt;/a&gt; (they are bread and butter to a web dev) but not if you&amp;rsquo;re a self-hoster who just wants a web server that converts markdown to HTML on the fly. For any situation where you just want to use the app, what you probably want is a Docker image of the app.&lt;/p&gt;</description></item><item><title>Certbot - removing a domain</title><link>https://devendevour.iankulin.com/certbot-removing-a-domain/</link><pubDate>Mon, 18 Mar 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/certbot-removing-a-domain/</guid><description>&lt;p&gt;I had a number of domains all running on one host when I first set them up with certbot. One started to be serious, so I moved it to another host and ran certbot there. That all worked perfectly, but of course, the old domain is still part of the original certificate, so when I went to renew it, it came up with some errors.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a few commands that are going to help navigate this situation if you&amp;rsquo;ve found yourself in the same spot:&lt;/p&gt;</description></item><item><title>Quick &amp;amp; Dirty auth with nginx &amp;amp; Node</title><link>https://devendevour.iankulin.com/quick-dirty-auth-with-nginx-node/</link><pubDate>Fri, 23 Feb 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/quick-dirty-auth-with-nginx-node/</guid><description>&lt;p&gt;One of the basic requirements for any serious web app is a proper users/roles/authentication system - but if you&amp;rsquo;re just throwing up a utility of some kind on a public IP for testing, and you don&amp;rsquo;t want it to be abused, then this could be an option. There&amp;rsquo;s a few components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your app. In this demo it&amp;rsquo;s going to be Node, but it could be Go or whatever your server-side poison is. The app is listening for connections on a non-web port (ie not on 80 or 443), I&amp;rsquo;m going to use the traditional 3000.&lt;/li&gt;
&lt;li&gt;A firewall. That port (in my example 3000) must not be accessible from the internet. It has to be blocked by a firewall.&lt;/li&gt;
&lt;li&gt;A web server (I&amp;rsquo;m using nginx) that enforces basic auth.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I briefly discussed web server basic auth earlier - it&amp;rsquo;s a system built into the web server that requires a log in for a route, and authenticates it against the credentials in a password file (usually named &lt;code&gt;.htpasswrd&lt;/code&gt;) and only serves the content if authenticated.&lt;/p&gt;</description></item><item><title>Beginning Node App Security</title><link>https://devendevour.iankulin.com/beginning-node-app-security/</link><pubDate>Fri, 16 Feb 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/beginning-node-app-security/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/sciacqualani_digital_paint_illustration_of_padlock_in_a_cyber_w_6a902b1c-29a3-4f98-9f6b-411d9594550c.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Since I&amp;rsquo;m using Tailscale to painlessly manage all my networking on the homeserver here and my remotes, I&amp;rsquo;ve had the luxury of being a bit casual about the security of my internal apps and self hosted dev tools. I&amp;rsquo;m currently iterating on a web app that requires public access, and is therefore up on a VPS and exposed to all the evils of the open internet.&lt;/p&gt;
&lt;p&gt;I am in no way a security expert, but here&amp;rsquo;s a few of the (reasonably simple) steps I&amp;rsquo;ve taken to secure my node app.&lt;/p&gt;</description></item><item><title>User Sessions &amp;amp; Cookies in Node</title><link>https://devendevour.iankulin.com/user-sessions-cookies-in-node/</link><pubDate>Fri, 09 Feb 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/user-sessions-cookies-in-node/</guid><description>&lt;p&gt;When you are learning app development, you can create all sorts of apps that work for you, but for any serious app, it&amp;rsquo;s going to need to authenticate users and persist sessions across visits. So much so, that as a professional developer, you&amp;rsquo;ll probably build that out first - it becomes a sort of boiler plate you always drop in.&lt;/p&gt;
&lt;p&gt;In this post, focusing on the server side, using node, express, and particularly express-session, I&amp;rsquo;ll try and build up from nothing to a reasonable usable user login system explaining the increasing complexity and reasons for it. To follow along you&amp;rsquo;ll need basic familiarity with node and express.&lt;/p&gt;</description></item><item><title>Web Development Overview</title><link>https://devendevour.iankulin.com/web-development-overview/</link><pubDate>Mon, 05 Feb 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/web-development-overview/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2024-01-27-at-1.00.35-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t often just link to someone else&amp;rsquo;s content, but I was really impressed with &lt;a href="https://www.traversymedia.com/" target="_blank" rel="noopener"&gt;Brad Traversy&lt;/a&gt; &amp;rsquo;s &amp;ldquo;Web Development In 2024 - A Practical Guide&amp;rdquo; video. Apparently he does these every year - it&amp;rsquo;s just a really comprehensive overview of Web Development pitched at beginners.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/8sXRyHI3bLw?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;</description></item><item><title>Fly.io, Uptime Kuma &amp;amp; scraping a status page</title><link>https://devendevour.iankulin.com/fly-io-uptime-kuma-scraping-a-status-page/</link><pubDate>Fri, 02 Feb 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/fly-io-uptime-kuma-scraping-a-status-page/</guid><description>&lt;p&gt;&lt;a href="https://dribbble.com/shots/5657880-Fly-io-Logo" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/c1fef772e2dca5e1ab8c812f465c95a8.png" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been aware since I set up &lt;a href="https://devendevour.iankulin.com/uptime-kuma-nfty/"&gt;Uptime Kuma&lt;/a&gt; for my monitoring, that having an instance on my local network monitoring my VPS websites wasn&amp;rsquo;t ideal. The main reason being that the flakiest part of my infrastructure is my 4G home internet, so if that goes down I have no website monitoring, and even if I did, the notifications couldn&amp;rsquo;t get out.&lt;/p&gt;
&lt;p&gt;Of course, it would also be a simple matter to run an instance on the VPS that I host the sites on, but that has a similar problem in that if the VPS goes down, so does my monitoring of the VPS. What I really need is a third, independent space to run an instance.&lt;/p&gt;</description></item><item><title>How to Have Cooler File Icons in VS Code</title><link>https://devendevour.iankulin.com/how-to-have-cooler-file-icons-in-vs-code/</link><pubDate>Mon, 29 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/how-to-have-cooler-file-icons-in-vs-code/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/aliana8676_31_years_old_woman._she_is_digital_artist__graphic_d_196f8b49-ba40-458c-a8ed-54746fe109e7.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I watch a lot of programming demos on Youtube, and it&amp;rsquo;s been low key bugging me for a while that everyone has cooler little icons in the explorer view of their VS Code than I do. For example, they have the HTML 5 shield logo next to their &lt;code&gt;index.html&lt;/code&gt;, but I have the little fragment tag &amp;lt;&amp;gt;. Really, there was no point spending two hours customising my OhMyZSH! terminal if I&amp;rsquo;m just going to let myself down with disappointing VS Code file icons.&lt;/p&gt;</description></item><item><title>Getting Your Vite React App to Work on Github Pages</title><link>https://devendevour.iankulin.com/getting-your-vite-react-app-to-work-on-github-pages/</link><pubDate>Fri, 26 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/getting-your-vite-react-app-to-work-on-github-pages/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/combined.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;One of the many cool things about GitHub is &lt;a href="https://pages.github.com" target="_blank" rel="noopener"&gt;GitHub Pages&lt;/a&gt; - the free web hosting Microsoft gives you while they vacuum up &lt;a href="https://docs.github.com/en/copilot/overview-of-github-copilot/about-github-copilot-individual" target="_blank" rel="noopener"&gt;your code for CoPilot&lt;/a&gt; training. Each repository you keep there can have pages at &lt;code&gt;&amp;lt;your-github-username&amp;gt;.github.io/&amp;lt;repo-name&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="github"&gt;GitHub&lt;/h3&gt; &lt;p&gt;To enable this, you need to go into the settings for the repository - look down the left for &amp;ldquo;Pages&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-12-31-at-1.58.05-pm.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible to have it based on a complicated GitHub action (where your build step happens on GitHub when you push your code), but the easiest thing is just to have it deployed from a branch. To do this you choose which branch (usually main) and whereabouts in the main branch your HTML is. The choices are in the root of your project, or in the &lt;code&gt;/docs&lt;/code&gt; directory. I&amp;rsquo;ve chosen the &lt;code&gt;/docs&lt;/code&gt; directory in the screenshot above, since my messy React project is in the root.&lt;/p&gt;</description></item><item><title>React Expense Tracker App</title><link>https://devendevour.iankulin.com/react-expense-tracker-app/</link><pubDate>Mon, 22 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/react-expense-tracker-app/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/moneycoachjen_76363_woman_representing_money_2f84bb41-99db-4cb8-bc07-78e759e8b1f9.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m focused on React frontend skills these holidays, and &lt;a href="https://codewithmosh.com/p/ultimate-react-part1" target="_blank" rel="noopener"&gt;working through Mosh&amp;rsquo;s React 18&lt;/a&gt; course. The exercise today (which I think I nailed, although I spent more than the recommended hour on) was a small app to track expenses. Like most of Mosh&amp;rsquo;s exercises it was great because it exercised all the understandings up to that point - so it&amp;rsquo;s a good starting React project. It used Zod for the form validation which is completely new to me, but looks great.&lt;/p&gt;</description></item><item><title>What's unfinished in your Udemy?</title><link>https://devendevour.iankulin.com/whats-unfinished-in-your-udemy/</link><pubDate>Fri, 19 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/whats-unfinished-in-your-udemy/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pauchi0195_unfinished_robotic_bodies_female_scientist_rebel_bio_b9b95c92-d4af-4600-9c5b-e0974f6c2b18.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;If you work or study in tech, I always feel a good getting-to-know-you question is &amp;ldquo;what courses or tutorials did you start, but not finish?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;My Udemy doesn&amp;rsquo;t look &lt;em&gt;too&lt;/em&gt; bad:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-12-29-at-1.30.02-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The ZTM course was good, but I got stuck on an AI API exercise. I think it&amp;rsquo;s a common sticking point for students since Andrei includes a little rant about how it definitely does work - but I downloaded his repo with the solution and it was having the same errors I was and I gave up in frustration. I probably should have just skipped that one.&lt;/p&gt;</description></item><item><title>Copying Objects in JS</title><link>https://devendevour.iankulin.com/copying-objects-in-js/</link><pubDate>Mon, 15 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/copying-objects-in-js/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/nullgrim_three_ominous_mechanical_cyber_demon_sisters_asajj_ven_1eaa87e3-99a8-4c4a-9bc0-ec8fb807caad.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve paid for a month of Mosh to do his &lt;a href="https://codewithmosh.com/p/ultimate-react-part1" target="_blank" rel="noopener"&gt;React 18 course&lt;/a&gt; , and one of the things he makes a big deal about is not to go too deep with nested objects for your state. As soon as you start to update them it becomes apparent why.&lt;/p&gt;
&lt;p&gt;Because of the way state works in React, if we need to update part of an object it has to be deep copied, the changes applied to this copy, then that new copy passed back to React to replace the previous version. So, how we copy objects becomes a matter of particular interest.&lt;/p&gt;</description></item><item><title>CSS for React Components</title><link>https://devendevour.iankulin.com/css-for-react-components/</link><pubDate>Fri, 12 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/css-for-react-components/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-12-27-at-3.30.32-pm.jpg" alt="" class="img-responsive"&gt; 
&lt;em&gt;Subscribe to my UX design course 😉&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you think back to HTML as being a document with headings and paragraphs and other semantic bits, it made a lot of sense to have the styles (expressed as CSS) separate to the document. This allows us to change the styles without touching the document - perhaps the user wanted a dark theme, needed the text bigger for accessibility, or perhaps the document was being consumed in some other way - for example a screen reader - so the styles were superfluous.&lt;/p&gt;</description></item><item><title>React - a To Do Example</title><link>https://devendevour.iankulin.com/react-a-to-do-example/</link><pubDate>Mon, 08 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/react-a-to-do-example/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/crake_react_framework_logo_in_a_stylized_and_minimalist_ink-sta_cd004169-cd3c-4f76-8314-3d841f7233ec.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Since I&amp;rsquo;m on a roll making different versions of the To Do app, this might be a good time to talk about &lt;a href="https://react.dev/" target="_blank" rel="noopener"&gt;React&lt;/a&gt; . React is one of the giants of front end libraries. It&amp;rsquo;s based on a few big ideas - and to work effectively in React you need to wrap your head around these.&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt; &lt;p&gt;Components - when you are developing in React, the starting point of your build is to decompose the user interface in to logical pieces. These components (comprising a mixture of HTML and Javascript) will be the building blocks of your app. In a good composable architecture components are reusable, and that is true for React (there are several sources of components you can pull in). For example, if you created some sort of special slider for your app, it is possible to reuse that quite easily.&lt;/p&gt;</description></item><item><title>htmx - A To Do Example</title><link>https://devendevour.iankulin.com/htmx-a-to-do-example/</link><pubDate>Fri, 05 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/htmx-a-to-do-example/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/0-eawgkaegdkhvqwcg.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;HTMX is an interesting project to me, and I&amp;rsquo;ve used it a bit in my large collection of 70% completed side projects, but haven&amp;rsquo;t really discussed it here. The plan for this post is to talk briefly about what it is exactly, then convert a simple &amp;lsquo;conventional&amp;rsquo; (HTML/CSS/Javascript) app to htmx and think about some the differences.&lt;/p&gt;
&lt;h3 id="htmx"&gt;htmx&lt;/h3&gt; &lt;p&gt;You could (I recommend you do) read the &lt;a href="https://hypermedia.systems/book/contents/" target="_blank" rel="noopener"&gt;book&lt;/a&gt; about the concepts behind &lt;a href="https://htmx.org/" target="_blank" rel="noopener"&gt;htmx&lt;/a&gt; . Carson Gross (the man behind htmx) calls it a book, but its quite the treatise, it could fairly be called a manifesto.&lt;/p&gt;</description></item><item><title>Testing Node.js apps - Mocha, Chai, and Supertest</title><link>https://devendevour.iankulin.com/testing-node-js-apps-mocha-chai-and-supertest/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/testing-node-js-apps-mocha-chai-and-supertest/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/marinashideroff_abstract_monitoring_internet_station_surrounded_9f91ec3e-e8c0-4567-bee6-0315eb2375f0.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Bruno is a great open source Postman/Insomnia replacement, and I&amp;rsquo;ve been using it for basic tests of my node servers using the built in asserts and loving it. This is pretty great, and I gather it&amp;rsquo;s also possible to go beyond this and &lt;a href="https://docs.usebruno.com/testing/introduction.html" target="_blank" rel="noopener"&gt;write tests in JS in Bruno&lt;/a&gt; . I believe it also has the hooks needed to build it into your CI/CD systems.&lt;/p&gt;
&lt;p&gt;Any large project is probably going to benefit from a more comprehensive suit of testing tools, and while I&amp;rsquo;ll still be using Bruno, my serious tests will be managed with these other tools.&lt;/p&gt;</description></item><item><title>Simple SQLite in Express</title><link>https://devendevour.iankulin.com/simple-sqlite-in-express/</link><pubDate>Thu, 28 Dec 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/simple-sqlite-in-express/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/shmbo_an_artificial_intelligence_entitys_head_embodying_the_ess_f348db7a-e7b6-4620-beda-44fdb8e565d3.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t have experience with &lt;a href="https://www.sqlite.org/index.html" target="_blank" rel="noopener"&gt;SQLite&lt;/a&gt; and want to shift one of my apps over from Mongoose since apparently SQLite is &lt;a href="https://www.sqlite.org/whentouse.html" target="_blank" rel="noopener"&gt;much more capable&lt;/a&gt; than I imagined. My usual tactic when trying something new is to try and get a minimal project working on it, so what follows is the simplest possible node/express REST API to demo SQLite.&lt;/p&gt;
&lt;p&gt;The simplest possible Express app is going to look something like this. Of course we would have gone to the terminal with &lt;code&gt;npm i express&lt;/code&gt; first so this could run.&lt;/p&gt;</description></item><item><title>Gogs, Gitea, Forgejo</title><link>https://devendevour.iankulin.com/gogs-gitea-forgejo/</link><pubDate>Mon, 18 Dec 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/gogs-gitea-forgejo/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/img_7071-1.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been really pleased with &lt;a href="https://devendevour.iankulin.com/tags/gogs/"&gt;Gogs&lt;/a&gt; - it&amp;rsquo;s lightweight, was simple to spin up, and has worked perfectly. But then this morning on Mastodon, there&amp;rsquo;s a &lt;a href="https://mastodon.social/@Codeberg@social.anoxinon.de/111471407276450348" target="_blank" rel="noopener"&gt;post from @Codeberg.org&lt;/a&gt; describing a security vulnerability in their Git hosting project Forgejo. This issue also apparently affects Gitea and Gogs - what&amp;rsquo;s up with that?&lt;/p&gt;
&lt;p&gt;I actually already did spend a bit of time comparing Gogs and Gitea before deciding on Gogs, since I&amp;rsquo;d heard of people running Gitea over the past year or so, but only seen that Gogs seemed to be popular with self-hosters in a Lemmy post I&amp;rsquo;d read. My first impression was that Gitea was more focused on CI/CD and seemed to have a more complicated install process.&lt;/p&gt;</description></item><item><title>Concurrency and channels in Go</title><link>https://devendevour.iankulin.com/concurrency-and-channels-in-go/</link><pubDate>Tue, 12 Dec 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/concurrency-and-channels-in-go/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/portal-logo.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;In the long ago times, I&amp;rsquo;d done several years of commercial programming before I ever had to worry about dealing with multiple things happening at the same time. Perhaps because of the rarity of this problem, doing it in traditional languages was not always elegant.&lt;/p&gt;
&lt;p&gt;In the modern world of everything happening on the network, and systems being build out of micro-services and APIs, the beginning programmer probably has to deal with this stuff in Programming 102. Luckily, modern languages have these considerations built in, and one language with a particular reputation for that is Go.&lt;/p&gt;</description></item><item><title>Date formatting in Go is quirky</title><link>https://devendevour.iankulin.com/date-formatting-in-go-is-quirky/</link><pubDate>Sat, 09 Dec 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/date-formatting-in-go-is-quirky/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/the_og_jay_go_programming_language_gopher_avatar._the_environme_3dc4f7dc-43b2-459e-8b76-57d9771eb9f7.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;When I&amp;rsquo;m working in an unfamiliar language, I find its quicker to just ask ChatGPT to write samples of anything I need than to look it up. For instance, last night I needed to format a date in Go, and rather than Google that and pick one of the results and scroll past the ads to read something, I just asked ChatGPT to give me a code example of formatting a date I gave it to DDMMYYYY.&lt;/p&gt;</description></item><item><title>Adding Front Matter To mdserver</title><link>https://devendevour.iankulin.com/adding-front-matter-to-mdserver/</link><pubDate>Fri, 24 Nov 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/adding-front-matter-to-mdserver/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/brobinhook_sketch_design_of_a_modern_landing_page_for_a_webdev__79beff03-b181-4195-90b9-ff9c41b9f138.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The very first issue I opened on &lt;a href="https://devendevour.iankulin.com/displaying-markdown-as-html/"&gt;mdserver&lt;/a&gt; - my server project that serves HTML from markdown files - was that the title of the page (which shows in the browser tab, and is used for browser bookmarks) needed to be set &lt;em&gt;inside&lt;/em&gt; the markdown file, rather than generated from the file name. I didn&amp;rsquo;t invent this idea - I&amp;rsquo;ve seen this sort of metadata in the top of Jekyll and Hugo markdown. Here&amp;rsquo;s an example from the &lt;a href="https://jekyllrb.com/docs/front-matter/" target="_blank" rel="noopener"&gt;Jekyll website&lt;/a&gt; :&lt;/p&gt;</description></item><item><title>Bruno asserts</title><link>https://devendevour.iankulin.com/bruno-asserts/</link><pubDate>Sat, 11 Nov 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/bruno-asserts/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-10-22-at-12.11.09-pm.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I mentioned &lt;a href="https://www.usebruno.com/" target="_blank" rel="noopener"&gt;Bruno&lt;/a&gt; the other day. Although it&amp;rsquo;s still very much under development, it is shaping up as a great Postman/Insomnia replacement.&lt;/p&gt;
&lt;p&gt;One of the aspects I&amp;rsquo;ve been using today is asserts. As part of a request, you can add some asserts - so when you&amp;rsquo;re hitting an endpoint it will check what status should it be returning, or given the data you&amp;rsquo;re passing in, what should be in the response body.&lt;/p&gt;</description></item><item><title>Displaying markdown as HTML</title><link>https://devendevour.iankulin.com/displaying-markdown-as-html/</link><pubDate>Wed, 08 Nov 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/displaying-markdown-as-html/</guid><description>&lt;p&gt;In the spirit of over-complicating things, when I wanted to collect all the links to the services on my homelab into one place, I decided I needed to write them in markdown, and have them converted on the fly into HTML by a server. Then when I couldn&amp;rsquo;t find exactly what I was after (&lt;a href="http://harpjs.com/" target="_blank" rel="noopener"&gt;Harp&lt;/a&gt; was closest) of course, I decided to write it.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/distracted.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;h3 id="markdown"&gt;Markdown&lt;/h3&gt; &lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Markdown" target="_blank" rel="noopener"&gt;Markdown&lt;/a&gt; has definitely been having it&amp;rsquo;s moment over the last couple of years. It&amp;rsquo;s a simple open format mark-up language that is quite readable in it&amp;rsquo;s source form. Although it&amp;rsquo;s now very fashionable as an input for static site generators, most people will have run in to it when adding simple formatting to forum comments or on instant messaging platforms.&lt;/p&gt;</description></item><item><title>We need to talk about Bruno</title><link>https://devendevour.iankulin.com/we-need-to-talk-about-bruno/</link><pubDate>Fri, 27 Oct 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/we-need-to-talk-about-bruno/</guid><description>&lt;p&gt;&lt;a href="https://www.usebruno.com/" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-10-01-at-6.01.17-pm.png" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve &lt;a href="https://devendevour.iankulin.com/how-to-deploy-a-node-js-app/"&gt;mentioned before&lt;/a&gt; that I was using Insomnia as a tool to check my REST APIs as I was developing them, and that I was avoiding Postman (which I guess is more widely used since it&amp;rsquo;s worth &lt;a href="https://techcrunch.com/2021/08/18/api-platform-postman-valued-at-5-6-billion-in-225-million-fundraise/" target="_blank" rel="noopener"&gt;USD5.6 billion&lt;/a&gt; ) because&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The only reason I&amp;rsquo;m using Insomnia instead of Postman is that when I tried Postman, it straight away wanted some of my data to make it work. Insomnia hasn&amp;rsquo;t forced me to do that yet.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>New Project Routine</title><link>https://devendevour.iankulin.com/new-project-routine/</link><pubDate>Sat, 21 Oct 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/new-project-routine/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/koda702_create_a_detailed_and_visually_engaging_collage_highlig_23cd7276-3e92-46ca-a055-086e4ff35417.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I have a sort of muscle memory for starting little web projects now. I seem to have landed on node/express SSR apps with HTMX sprinkles. So it goes a bit like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a working directory - all lower case with a simple, but unlikely to be duplicated by me, name.&lt;/li&gt;
&lt;li&gt;Open the directory in vscode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm init&lt;/code&gt; in the directory to create the &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;create a &lt;code&gt;public&lt;/code&gt; sub directory, and drop &lt;a href="https://htmx.org/docs/#installing" target="_blank" rel="noopener"&gt;&lt;code&gt;htmx.min.js&lt;/code&gt;&lt;/a&gt; in there, and create a &lt;code&gt;styles.css&lt;/code&gt; there. I&amp;rsquo;m always conflicted about what to do about this htmx dependency. I&amp;rsquo;d rather host it rather than use their CDN because &lt;a href="https://blog.wesleyac.com/posts/why-not-javascript-cdn" target="_blank" rel="noopener"&gt;reasons&lt;/a&gt; . But I also feel bad about committing it on Github. I could .gitignore it, but then when I clone the project on the production server I&amp;rsquo;d need to add another step to download it. HTMX is only 44K, and Microsoft can afford the bandwidth, so for the moment I commit them, but I need a better solution for the future.&lt;/li&gt;
&lt;li&gt;using the git tools in vscode, add &lt;code&gt;.DS_Store&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; (which also creates it), then edit it to also ignore &lt;code&gt;node_modules&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install express&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install ejs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;create a server.js, and add the &lt;a href="https://nodejs.org/en/docs/guides/getting-started-guide" target="_blank" rel="noopener"&gt;hello world&lt;/a&gt; code&lt;/li&gt;
&lt;li&gt;create a &lt;code&gt;readme.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;commit these files as &amp;ldquo;initial&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Create the repo on github with the same name - no readme and no licence. I do it this way for a couple of reasons - I want to find out at this point if I&amp;rsquo;ve already used this repo name, and I want it to give me the cut and paste commands to push the repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-09-25-at-9.55.46-am.png" alt="" class="img-responsive"&gt; &lt;/p&gt;</description></item><item><title>Simple API endpoint in Go</title><link>https://devendevour.iankulin.com/simple-api-endpoint-in-go/</link><pubDate>Wed, 27 Sep 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/simple-api-endpoint-in-go/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/gopher.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like a small, quick, low load endpoint on all my nodes and VM&amp;rsquo;s that exposes a text keyword indicating if that machine is okay for RAM and disk space. I&amp;rsquo;m currently using &lt;a href="https://devendevour.iankulin.com/tags/uptime-kuma/"&gt;Uptime Kuma&lt;/a&gt; to monitor if these machines are pingable, but I&amp;rsquo;d love a tiny bit more information from them so I&amp;rsquo;d get a &lt;a href="https://devendevour.iankulin.com/uptime-kuma-nfty/"&gt;Ntfy&lt;/a&gt; buzz on my phone if a machine is in trouble.&lt;/p&gt;
&lt;p&gt;I mentioned a couple of weeks ago that the benefit of doing it in C rather than Node.js was probably not worth the trouble, but then being a fickle developer, decided to write it in Go.&lt;/p&gt;</description></item><item><title>Use VS Code to work on remote files</title><link>https://devendevour.iankulin.com/use-vs-code-to-work-on-remote-files/</link><pubDate>Thu, 21 Sep 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/use-vs-code-to-work-on-remote-files/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/dreamshaper_v7_a_cavewoman_sitting_in_a_cave_typing_on_a_small_0.jpg" alt="Cavewoman typing on a MacBook" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve got a script, or some code to work on, and it&amp;rsquo;s on a VM somewhere, you can always &lt;code&gt;ssh&lt;/code&gt; in and use &lt;code&gt;nano&lt;/code&gt; or &lt;a href="https://devendevour.iankulin.com/bloody-vim/"&gt;&lt;code&gt;vim&lt;/code&gt;&lt;/a&gt; to make your edits. Like a caveman. With an archaic editor, no intellisense, and no spell checking.&lt;/p&gt;
&lt;p&gt;Or&amp;hellip;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-08-13-at-3.50.15-pm.png" alt="VS Code connected to a remote server over SSH" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;This magic - of editing a files on a remote server over SSH is achieved by using a Microsoft plugin for VS Code - &amp;ldquo;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh" target="_blank" rel="noopener"&gt;Remote - SSH&lt;/a&gt; &amp;rdquo;&lt;/p&gt;</description></item><item><title>Lightweight Web Servers</title><link>https://devendevour.iankulin.com/lightweight-web-servers/</link><pubDate>Fri, 15 Sep 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/lightweight-web-servers/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/dreamshaper_v7_a_web_server_floating_away_because_it_is_so_lig_0.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-08-02-at-9.09.48-pm-2.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been using the excellent &lt;a href="https://github.com/louislam/uptime-kuma" target="_blank" rel="noopener"&gt;Uptime Kuma&lt;/a&gt; for my monitoring, but a couple of recent incidents - an external USB mount disappeared on a remote machine, an NVME drive filled up on a different node and stopped backups working because of a configuration error - have made me start to think about more robust monitoring.&lt;/p&gt;
&lt;p&gt;The are many great tools for this - &lt;a href="https://www.nagios.org/" target="_blank" rel="noopener"&gt;Nagios&lt;/a&gt; , &lt;a href="https://prometheus.io/" target="_blank" rel="noopener"&gt;Prometheus&lt;/a&gt; etc. but they are pretty substantial time investments for the excellent power. They can save time series data and display them beautifully. However, all I really want is to add some extra ability to Uptime Kuma.&lt;/p&gt;</description></item><item><title>Cookies, Sessions &amp;amp; Tokens</title><link>https://devendevour.iankulin.com/cookies-sessions-tokens/</link><pubDate>Tue, 12 Sep 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/cookies-sessions-tokens/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/brunofach_flat_screen_illustration_of_a_background_with_cookies_0a1c174a-afdd-43a1-b9f6-ceab96b5aabd.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m up to the point in a web app where it needs to come off my lan and into the hands of a couple of users for alpha feedback. Before that happens, I have to add some sort of login/authentication system since it I want to use real, sensitive data. There&amp;rsquo;s lots of detailed blog posts and videos of how to implement this in an Express app with passport, but what I was missing was the big picture of what actually needs to happen.&lt;/p&gt;</description></item><item><title>Sorting out Node package dependencies when cloning old repos</title><link>https://devendevour.iankulin.com/sorting-out-node-package-dependencies-when-cloning-old-repos/</link><pubDate>Wed, 06 Sep 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/sorting-out-node-package-dependencies-when-cloning-old-repos/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/tomins_russian_dolls_inside_out._vector_style_for_storyboard._a57e3973-3942-47ad-9f07-813694c9cecb.jpg" alt="Russian dolls" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;If you clone an old node project and &lt;code&gt;npm install&lt;/code&gt; it, you&amp;rsquo;ll most likely get a bunch of errors and warning messages. If you just decide to yolo it and run the project, you&amp;rsquo;ll get a bunch more.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been doing this exact thing. I want to add some auth to my app, and I&amp;rsquo;ve been following &lt;a href="https://github.com/WebDevSimplified" target="_blank" rel="noopener"&gt;WebDevSimplified&lt;/a&gt; &amp;rsquo;s &lt;a href="https://www.youtube.com/watch?v=-RCnNyD0L-s" target="_blank" rel="noopener"&gt;video&lt;/a&gt; about using &lt;a href="https://www.passportjs.org/packages/passport-npm/" target="_blank" rel="noopener"&gt;passport&lt;/a&gt; . I was building into my app without really understanding what I was doing, ran into problems and decided just to clone his repo and integrate the code into my app. The repo is four years old.&lt;/p&gt;</description></item><item><title>Hide 'Problems' for a file in VS Code</title><link>https://devendevour.iankulin.com/hide-problems-for-a-file-in-vs-code/</link><pubDate>Fri, 25 Aug 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/hide-problems-for-a-file-in-vs-code/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/apollon_young_man_touching_a_transparent_wall_hiding_code_for_a_524e38cd-fa31-45a3-ab96-dc9b9ed25caa.jpg" alt="Two white bread guys clicking away on a screen wall" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m interested in trying out &lt;a href="https://picocss.com/" target="_blank" rel="noopener"&gt;Pico CSS&lt;/a&gt; - a lightweight CSS library, but when I tossed it into my project, the linter found and reported 29 problems. One of my processes is to just keep that problems tab clear as I work, so I&amp;rsquo;d like that to go away.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-07-20-at-6.54.06-am.jpg" alt="Screenshot of VS Code showing 29 problems detected." class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible, but only by &amp;rsquo;excluding&amp;rsquo; the file from your project - it won&amp;rsquo;t show up in the file view either. That&amp;rsquo;s fine with me, I never want to deal with the file so we&amp;rsquo;ll do that, although it might confuse me in seven years if I come back to this project, so I&amp;rsquo;ll drop a link in my .git_ignore as a clue for future me (excluding the file in VS Code doesn&amp;rsquo;t affect git finding it).&lt;/p&gt;</description></item><item><title>Installing a Node app on a server</title><link>https://devendevour.iankulin.com/installing-a-node-app-on-a-server/</link><pubDate>Tue, 22 Aug 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/installing-a-node-app-on-a-server/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/clu_create_an_image_where_a_cute_little_girl_stands_in_a_whimsi_45944303-8475-48ed-9b8d-d291b525138d.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Before I write a fancy Ansible playbook to automatically set up the Nginx/Node combo on my web servers, it might be worth going through how to deploy a Node app so it can run on a server without you being logged in.&lt;/p&gt;
&lt;p&gt;Until now, I&amp;rsquo;ve been running my tests on my laptop, or in a server logged in as myself - sometimes detaching from tmux. But we need a bit more professional set up than that. The process will look something like this:&lt;/p&gt;</description></item><item><title>nginx in Front of a node.js app</title><link>https://devendevour.iankulin.com/nginx-in-front-of-a-node-js-app/</link><pubDate>Fri, 04 Aug 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/nginx-in-front-of-a-node-js-app/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/jonaslittorin_strictly_digital_content_web_server_technology_we_fad86a29-71f0-439c-9900-2134fea30897.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;NGINX is a great webserver and reverse proxy - as in it can hand off requests to other web-servers. That&amp;rsquo;s the situation I want to have set up on my VPS. I want NGINX to handle incoming requests - some of them will just be sorted out by returning static HTML, others (like the weather api I&amp;rsquo;ve been playing with) need to be handed off to other services to respond to.&lt;/p&gt;</description></item><item><title>Unlearning Relational DB</title><link>https://devendevour.iankulin.com/unlearning-relational-db/</link><pubDate>Sun, 09 Jul 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/unlearning-relational-db/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pawann_seamless_computers_data_storage_databases_processors_on_28c2c788-6e8e-4dfd-a58f-8a468dd647e0.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Some of my first university programming was writing &lt;a href="https://en.wikipedia.org/wiki/CICS" target="_blank" rel="noopener"&gt;CICS&lt;/a&gt; COBOL transactions against IBM&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/IBM_Db2" target="_blank" rel="noopener"&gt;DB2&lt;/a&gt; relational database. My commercial work after uni was mostly written in Clipper which was a sort of compiled version of &lt;a href="https://en.wikipedia.org/wiki/DBase" target="_blank" rel="noopener"&gt;dBase&lt;/a&gt; and used the same data file format. The minimal web work I did in the before times relied on &lt;a href="https://en.wikipedia.org/wiki/MySQL" target="_blank" rel="noopener"&gt;MySQL&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;All of which is to say, I&amp;rsquo;m very comfortable designing relational database schema, and I understand what&amp;rsquo;s going on at the disk level when they are being accessed and written to.&lt;/p&gt;</description></item><item><title>How to deploy a Node.js app</title><link>https://devendevour.iankulin.com/how-to-deploy-a-node-js-app/</link><pubDate>Wed, 05 Jul 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/how-to-deploy-a-node-js-app/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/naresh_create_a_github_account_and_a_new_repository._install_gi_c8bce4b2-201f-422b-815c-bb6286fb000a.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;This is one of those things that is simple once you know it. I had my &lt;a href="https://devendevour.iankulin.com/using-node-js-to-return-a-static-file/"&gt;tiny Node service working&lt;/a&gt; on my MacBook, but how do I run it on the server?&lt;/p&gt;
&lt;h3 id="native-or-container"&gt;Native or Container&lt;/h3&gt; &lt;p&gt;Obviously I need Node.js installed on the server, should I have it in a Docker container, or native on the machine. There&amp;rsquo;s no clear answer here - in a container set up with Docker Compose might be more in line with my ideology of treating machines as disposable, but a native install is simpler, and I probably want to make life simpler at this stage when I&amp;rsquo;m learning everything.&lt;/p&gt;</description></item><item><title>Using Node.js to return a static file</title><link>https://devendevour.iankulin.com/using-node-js-to-return-a-static-file/</link><pubDate>Sun, 02 Jul 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/using-node-js-to-return-a-static-file/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/rajeshtva_node.js_609056a9-3b73-46f5-bc4f-c1f110e3a367.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;As mentioned in the &lt;a href="https://devendevour.iankulin.com/complicating-the-temperature-api/"&gt;previous post&lt;/a&gt; , stage one is just to return the same static text file, but from the Node server, rather than NGINX. That&amp;rsquo;s non-trivial to a rank beginner since I need to figure out 1) how to serve a static file from Node, and 2) how to configure NGINX to hand off calls to the API to Node. This post will look at both of those, but it&amp;rsquo;s first probably worth just setting out what each of the puzzle pieces are.&lt;/p&gt;</description></item><item><title>Complicating the Temperature API</title><link>https://devendevour.iankulin.com/complicating-the-temperature-api/</link><pubDate>Wed, 28 Jun 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/complicating-the-temperature-api/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/gandalfthebeard_personal_dashboard_with_share_prices_photograph_bda71695-3d15-4521-9df1-8170f5906d8b.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been slammed with other work, so my web dev learning has fallen well behind. Luckily, the YouTube procrastination algorithm noticed this and suggested I watch a video from &lt;a href="https://www.youtube.com/@codewithcon" target="_blank" rel="noopener"&gt;CodeWithCon&lt;/a&gt; titled &lt;a href="https://www.youtube.com/watch?v=KNa-wMpry00&amp;amp;list=PLkJHe6eU_tzeoe7vKUEa4MrS74CpVEwdI&amp;amp;index=3&amp;amp;t=305s" target="_blank" rel="noopener"&gt;Learn Backend in 10 MINUTES&lt;/a&gt; .&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/KNa-wMpry00?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;Since I was watching a video of a guy learning to land a C152 at St Baths (a skill I do &lt;em&gt;not&lt;/em&gt; need) at the time, it was hard to argue with myself that I didn&amp;rsquo;t have ten minutes to learn all of backend programming.&lt;/p&gt;</description></item><item><title>Installing SSL Certificates with Nginx on Docker</title><link>https://devendevour.iankulin.com/installing-ssl-certificates-with-nginx-on-docker/</link><pubDate>Sat, 29 Apr 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/installing-ssl-certificates-with-nginx-on-docker/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/starliu_building_trust_with_ai_challenges_and_solutions_a519169f-8b94-4b34-88d9-e2e635bc5996.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;ve successfully got Nginx running in a Docker container, AND got your &lt;a href="https://devendevour.iankulin.com/adding-a-domain-name-to-a-vps/"&gt;domain correctly pointing&lt;/a&gt; at your nascent website, you&amp;rsquo;re then going to want to set it up for encrypted, and therefore trusted, browsing with SSL.&lt;/p&gt;
&lt;h3 id="certificates"&gt;Certificates&lt;/h3&gt; &lt;p&gt;A couple of posts ago, I &lt;a href="https://devendevour.iankulin.com/adding-a-domain-name-to-a-vps/"&gt;mentioned&lt;/a&gt; that it was simpler to let Porkbun be the authoritative nameserver for a domain. Part of the reason for that is that if we do that, Porkbun had a button you can press which connects to LetsEncrypt and generates the certificates for you. This usually takes an hour or so, then you&amp;rsquo;ll be able to download the bundle from that same page.&lt;/p&gt;</description></item><item><title>Your own Aussie server on BinaryLane</title><link>https://devendevour.iankulin.com/your-own-aussie-server-on-binarylane/</link><pubDate>Sun, 05 Feb 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/your-own-aussie-server-on-binarylane/</guid><description>&lt;p&gt;Listening to podcasts, I&amp;rsquo;ve been jealous of US developers who seem to have masses of $5/month VPS (Virtual Private Server) options. When I looked for similar Australian offerings a few months ago, they all seem to start at around $35 which is outside of my &amp;lsquo;have a play with something&amp;rsquo; budget range.&lt;/p&gt;
&lt;p&gt;I could of course use one of the international options, but one of the main apps on my app ideas list needs to be hosted in Australia and work under Australian data privacy rules. That might be the case for Digital Ocean (or other US companies) if you select an AU server, but I&amp;rsquo;m not a lawyer. For the imaginary clients of my imaginary app, me being able to say that the hosting is with an Australian company in Australia would be a plus.&lt;/p&gt;</description></item><item><title>Expired Packages Part II</title><link>https://devendevour.iankulin.com/expired-packages-part-ii/</link><pubDate>Tue, 31 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/expired-packages-part-ii/</guid><description>&lt;p&gt;Following on from the previous post&amp;hellip;&lt;/p&gt;
&lt;p&gt;I went the nuclear route - deleted the node_modules folder, package-lock.json and installed the packages from packages.json. I still had some errors, but the react app at least ran correctly. Also, the messages are a bit more intelligible, and all of them cascade from this one.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# npm audit report

nth-check &amp;lt;2.0.1
Severity: high
Inefficient Regular Expression Complexity in nth-check - https://github.com/advisories/GHSA-rp65-9cf3-cjxr
fix available via `npm audit fix --force`
Will install react-scripts@2.1.3, which is a breaking change
node_modules/svgo/node_modules/nth-check
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From my, admittedly ignorant, viewpoint, there&amp;rsquo;s a couple of weird things going on here.&lt;/p&gt;</description></item><item><title>Expired packages</title><link>https://devendevour.iankulin.com/expired-packages/</link><pubDate>Mon, 30 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/expired-packages/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_a_large_pile_of_garbage_containg_binary_code_slowly_rott_55771f9e-3781-42e7-90f0-e6943b12ae8e-1.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;At several points in the &lt;a href="https://www.udemy.com/course/the-complete-web-developer-zero-to-mastery/" target="_blank" rel="noopener"&gt;Complete Web Developer&lt;/a&gt; course, deprecated packages have been used, with the slide before the video explaining what&amp;rsquo;s happening, and giving a work around, or sometimes - as is the case for the bit I&amp;rsquo;m just starting - exhorting the benefits of dropping you into a non-working mess and having you figure it out yourself.&lt;/p&gt;
&lt;p&gt;While this argument can be reasonably made - that figuring things out on your own is a valuable skill - it&amp;rsquo;s also a useful fig leaf to cover up the fact that they haven&amp;rsquo;t bothered to fix the course to make it work out of the box.&lt;/p&gt;</description></item><item><title>CodePen</title><link>https://devendevour.iankulin.com/codepen/</link><pubDate>Sun, 29 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/codepen/</guid><description>&lt;p&gt;I think I&amp;rsquo;ve written about CodePen before, its a site that allows users to quickly put together HTML, CSS &amp;amp; JS and see the results as they edit. Users &amp;lsquo;pens&amp;rsquo; are public and can be tagged, so it also serves as a repository of examples.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible to host incredibly complex artefacts, such as this &lt;a href="https://codepen.io/ricardoolivaalonso/pen/RwBZMGB" target="_blank" rel="noopener"&gt;3D Sony Walkman&lt;/a&gt; , but what I mostly use it for is to work out simple things - like how to &lt;a href="https://codepen.io/IanKulin/pen/wvxrZxW" target="_blank" rel="noopener"&gt;collapse a row of text into a column&lt;/a&gt; with a media query.&lt;/p&gt;</description></item><item><title>Using the Community</title><link>https://devendevour.iankulin.com/using-the-community/</link><pubDate>Fri, 27 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/using-the-community/</guid><description>&lt;p&gt;You can&amp;rsquo;t always successfully google problems when you&amp;rsquo;re starting out - usually because you don&amp;rsquo;t know the correct terminology for the issue or solution. Often you might still get a newbie StackOverflow hit, but when there&amp;rsquo;s not even that, you need a human to help out.&lt;/p&gt;
&lt;p&gt;One of the things &lt;a href="https://zerotomastery.io/" target="_blank" rel="noopener"&gt;ZTM&lt;/a&gt; do with their courses is to have a Discord based community, then set tasks to encourage it&amp;rsquo;s use - for example one of the exercises I&amp;rsquo;ve already had was to go there and answer a question. Earlier ones were to introduce yourself and to find a partner to work with - both of which would have forced anyone not used to Discord to figure it out.&lt;/p&gt;</description></item><item><title>Openlayers &amp;amp; Vite</title><link>https://devendevour.iankulin.com/openlayers-vite/</link><pubDate>Thu, 26 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/openlayers-vite/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_drawing_of_a_nymph_who_is_looking_through_a_hole_in_a_br_173a47fc-4d46-481f-ae16-7d93381c8296.jpg" alt="drawing of a nymph who is looking through a hole in a brick wall to a beautiful garden - MidJourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;In Randy Pausch&amp;rsquo;s &lt;a href="https://www.youtube.com/watch?v=ji5_MqicxSo" target="_blank" rel="noopener"&gt;last lecture&lt;/a&gt; he talks about the benefit of brick walls in our lives - they tell us how much we really want something. Software development is full of these brick walls - things we want to do, but there&amp;rsquo;s a barrier to achieving it. Will we persevere and accomplish the thing, give up, or some other compromise.&lt;/p&gt;</description></item><item><title>APIs - http &amp;amp; https Mixed Content error</title><link>https://devendevour.iankulin.com/apis-http-https-mixed-content-error/</link><pubDate>Tue, 24 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/apis-http-https-mixed-content-error/</guid><description>&lt;p&gt;&amp;lt;img src=&amp;quot;/images/screen-shot-2023-01-16-at-4.45.53-pm.jpg alt=&amp;ldquo;Mixed Content: The page at &amp;lsquo;&lt;URL&gt;&amp;rsquo; was loaded over HTTPS, but requested an insecure resource '&lt;/p&gt;
&lt;p&gt;Ran into a little bump today - I was calling a &lt;a href="http://open-notify.org/Open-Notify-API/ISS-Location-Now/" target="_blank" rel="noopener"&gt;cool API&lt;/a&gt; that gives the current location of the International Space Station. In a classic case of &amp;ldquo;it worked on my machine&amp;rdquo; it worked perfectly in the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer" target="_blank" rel="noopener"&gt;Live server&lt;/a&gt; in VS Code on my laptop, but when I pushed it up to my GitHub space, it didn&amp;rsquo;t work - throwing the error:&lt;/p&gt;</description></item><item><title>React code is not HTML</title><link>https://devendevour.iankulin.com/react-code-is-not-html/</link><pubDate>Sun, 22 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/react-code-is-not-html/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_the_react_atom_logo_fighting_with_some_html_4b0d18eb-b17f-471f-a42c-a99e160b1231-copy.jpg" alt="The React atom logo fighting with some HTML - midjourney, edited" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I was looking at this ugly code in a React app:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;div style={{overflow: &amp;#39;scroll&amp;#39;, border: &amp;#39;1px solid black&amp;#39;, height: &amp;#39;600px&amp;#39; }}&amp;gt;
 { props.children }
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Since I don&amp;rsquo;t need any of those CSS properties to change at any stage, I could just convert it to pure HTML/CSS right? Well no:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-01-09-at-4.26.54-pm.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The newbie trap I&amp;rsquo;ve fallen for here is that although that &lt;code&gt;&amp;lt;div style= tag&lt;/code&gt; looks like HTML, it&amp;rsquo;s actually not. It&amp;rsquo;s not a template that will be filled out in the build step, it&amp;rsquo;s React code that will be used to mutate the virtual DOM.&lt;/p&gt;</description></item><item><title>De-structuring objects in JS</title><link>https://devendevour.iankulin.com/de-structuring-objects-in-js/</link><pubDate>Fri, 20 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/de-structuring-objects-in-js/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_robot_repair_shop_wth_several_humanoid_robots_in_state_o_c5ef7630-fb2a-4dec-acd5-dfb9b9f478ac.jpg" alt="robot repair shop wth several humanoid robots in state of disrepair, cinematic lighting, dust in the air - midjourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve worked through my first React tutorial app, and obviously that&amp;rsquo;s a lot - I&amp;rsquo;m struct by how messy mixing HTML, JS and React is.&lt;/p&gt;
&lt;p&gt;One language feature that&amp;rsquo;s being used quite a bit, and that is apparently a JS ability I&amp;rsquo;d never seen is &amp;lsquo;destructuring&amp;rsquo; object properties. It&amp;rsquo;s very cool and obviously useful. It&amp;rsquo;s a way of extracting just the properties you need from an object and then using them without accesing them via the object. An example will make it clearer.&lt;/p&gt;</description></item><item><title>Digital Color Meter</title><link>https://devendevour.iankulin.com/digital-color-meter/</link><pubDate>Wed, 18 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/digital-color-meter/</guid><description>&lt;p&gt;For the Calculator project, I needed to know the exact RGB values for the colours on the iOS calculator buttons so I could reproduce them. Assuming a tool for reading colours from the screen exisited, I googled it, and was surprised to find this exact tool is already installed by default on MacOS.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s called Digital Color Meter and just shows the RGB values for anything on the screen under the cursor.&lt;/p&gt;</description></item><item><title>Calculator</title><link>https://devendevour.iankulin.com/calculator-2/</link><pubDate>Mon, 16 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/calculator-2/</guid><description>&lt;p&gt;I&amp;rsquo;ve been doing a bit of driving during the holidays, which means a lot of podcast listening. An episode of &lt;a href="https://topenddevs.com/podcasts/javascript-jabber/episodes/splatty-doo-and-other-javascript-features-you-should-avoid-jsj-543" target="_blank" rel="noopener"&gt;JavaScript Jabber about JS features you should never use&lt;/a&gt; sparked my interest in &lt;code&gt;[eval()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)&lt;/code&gt;. &lt;code&gt;eval()&lt;/code&gt; takes whatever you pass it in a string and executes it in the JS engine. This is a crazy concept if you&amp;rsquo;ve come from complied languages, and has obvious security implications. As with dynamic typing, I&amp;rsquo;m trying to force myself out of my comfort zone to embrace JS&amp;rsquo;s unique talents so I was keen to try &lt;code&gt;eval()&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>CWD - 185 - Problem solving</title><link>https://devendevour.iankulin.com/cwd-185-problem-solving/</link><pubDate>Sat, 14 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/cwd-185-problem-solving/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_c-3po_from_star_wars_on_tatooine_playing_tic-tac-toe_on__66c1149e-de97-45d4-9863-18181aa54cf7.jpg" alt="C-3PO from Star Wars on Tatooine, playing Tic-tac-toe on the side of a crashed spaceship - MidJourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/* 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;Question 1: Clean the room function: given an input of [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20], 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;make a function that organizes these into individual array that is ordered. For example 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;answer(ArrayFromAbove) should return: [[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591]. 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ctrFunction1&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;inputArray&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// copy the array since we&amp;#39;re mutating it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [...&lt;span style="color:#a6e22e"&gt;inputArray&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;sort&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;] &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// this property does not exist, so add it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// object now contains arrays for each number, but the ones with a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// single element need degloved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;property&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;property&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;property&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;property&lt;/span&gt;][&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// now turn back to array 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Object.&lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;numberObject&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;591&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;392&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;391&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transformedArray1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ctrFunction1&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;array1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;transformedArray1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// [1, 1, 1, 1], [2, 2, &amp;#39;2&amp;#39;], 4, 5, 10, [20, 20], 391, 392, 591]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="line-10"&gt;Line 10&lt;/h4&gt; &lt;p&gt;When I&amp;rsquo;m looking at a function, I&amp;rsquo;d prefer not to also have to hold global state in my head - so I&amp;rsquo;m all for functional programming as far as that goes. I&amp;rsquo;m less concerned about side effects, so I wouldn&amp;rsquo;t always bother to copy a parameter like this, but the argument is stronger for an array than an object since in other languages an array might be a value type.&lt;/p&gt;</description></item><item><title>Types of Concern</title><link>https://devendevour.iankulin.com/types-of-concern/</link><pubDate>Fri, 13 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/types-of-concern/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_medieval_manuscript_drawing_of_a_peasant_holding_a_macbo_534a8a13-44b2-44cc-8916-5e246609e39d.jpg" alt="medieval manuscript drawing of a peasant holding a MacBook - midjourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I am still struggling with the dynamic typing of JS. I guess the benefit of such an approach is needing less characters - which makes sense in a scripting language like bash, but in real programming it opens us up to a whole class of avoidable errors.&lt;/p&gt;
&lt;p&gt;To program defensively in JS would mean loading the start of function with a series of type checks. I don&amp;rsquo;t see much of that in other people&amp;rsquo;s code, so I assume we just, don&amp;rsquo;t?&lt;/p&gt;</description></item><item><title>Lost in Translation</title><link>https://devendevour.iankulin.com/lost-in-translation/</link><pubDate>Wed, 11 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/lost-in-translation/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_two_female_robots_having_a_confusing_conversation_2d32f035-3a1e-4e9f-a335-f7c395190925.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re in a pretty good place now (compared to a few years ago) in terms of being able to rely on JavaScript behaving the same on different platforms. There&amp;rsquo;s still some differences (mostly in when things are implemented) but overall, not to bad once you decide to no longer support Internet Explorer.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript" target="_blank" rel="noopener"&gt;In times past, it was a lot more painful&lt;/a&gt; . A few of approaches to deal with this arose. One is to let a library, such as &lt;a href="https://jquery.com/" target="_blank" rel="noopener"&gt;jQuery&lt;/a&gt; or a &lt;a href="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills" target="_blank" rel="noopener"&gt;polyfill&lt;/a&gt; deal with it, and the other is use a translation utility such as Babel to down convert (transpile) your modern JavaScript to something that will run in more browsers.&lt;/p&gt;</description></item><item><title>Functions in JavaScript</title><link>https://devendevour.iankulin.com/functions-in-javascript/</link><pubDate>Mon, 09 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/functions-in-javascript/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_factory_with_robot_workers_on_an_assembly_line_making_bo_dadc6d24-8873-48f2-97aa-df5508e6e625-1.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;As with other languages, functions are a little lumps of code with their own scope. They can optionally take some arguments, and optionally return a value.&lt;/p&gt;
&lt;p&gt;In JavaScript they often have names, can be passed around as types and have a condensed form suitable for functional programming.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;function addNums(a, b) {
 return a+b;
}

console.log(addNums(3,4)) // 7
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="scope"&gt;Scope&lt;/h4&gt; &lt;p&gt;Arguments are passed in by value so they have local scope only in the function body.&lt;/p&gt;</description></item><item><title>CodePen.io</title><link>https://devendevour.iankulin.com/codepen-io/</link><pubDate>Thu, 05 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/codepen-io/</guid><description>&lt;p&gt;I quite often leave a link to a GitHub repo to share my source in these posts, and on a few recent ones, a link to a live version of a page on my github.io. In a recent installment of &lt;a href="https://www.udemy.com/course/the-complete-web-developer-zero-to-mastery/" target="_blank" rel="noopener"&gt;CWD&lt;/a&gt; , Andrei shared some previous students&amp;rsquo; solutions, and some were hosted on CodePen.io which I hadn&amp;rsquo;t seen before.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-12-28-at-10.20.02-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a cute concept, you can enter HTML, CSS &amp;amp; JS and see a live view of the page below. It looks super extensible - there&amp;rsquo;s mentions of SCSS, Typescript and preprocessors for JS in the settings.&lt;/p&gt;</description></item><item><title>Step Ahead</title><link>https://devendevour.iankulin.com/one-step/</link><pubDate>Wed, 04 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/one-step/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_giant_girl_leaping_for_joy_in_the_forest_childrens_book__eadb2294-124d-46e0-a0ca-f94a1a9305ea.jpg" alt="giant girl leaping for joy in the forest children&amp;rsquo;s book - midjourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I was a bit pleased with myself when I started the next content element in the Complete Web Developer course to find that one and a half of the extensions I&amp;rsquo;d made to the tutorial app for my own fun were specified as the next task.&lt;/p&gt;
&lt;p&gt;In my previous post, I&amp;rsquo;d talked about using a class to denote if an item was completed, and using a style to indicate this by crossing it out. What I haven&amp;rsquo;t discussed was that I&amp;rsquo;d captured right click events on the list items to make this delete them. I wasn&amp;rsquo;t entirely happy with that for a couple of reasons:&lt;/p&gt;</description></item><item><title>Web Reference</title><link>https://devendevour.iankulin.com/web-reference/</link><pubDate>Tue, 03 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/web-reference/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_1950s_man_and_woman_sitting_back_to_back_both_reading_la_2e94f56b-03c4-4b85-90ef-409f825e77ed.jpg" alt="1950&amp;rsquo;s man and woman sitting back to back both reading large books outside by swimming pool - midjourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_1950s_man_and_woman_sitting_back_to_back_both_reading_la_f12252b9-78dd-4ad1-bd76-bd85654cdaa1.jpg" alt="1950&amp;rsquo;s man and woman sitting back to back both reading large books outside by swimming pool - midjourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;There is no shortage of places to reference material to help when developing web apps, including a gazillion tutorials and blog posts (like mine) of various quality, and more importantly - based on the state of play at the time they were written, which could be any time in the last twenty years. I keep bumping up against this - great, clear explanations addressing whatever I was googling, but which turn out to use out of date bits.&lt;/p&gt;</description></item><item><title>Document Object Model - ToDo</title><link>https://devendevour.iankulin.com/document-object-model-todo/</link><pubDate>Mon, 02 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/document-object-model-todo/</guid><description>&lt;p&gt;I&amp;rsquo;m up to Section 12 of the Complete Web Developer course &amp;ldquo;DOM Manipulation&amp;rdquo; and it feels like we&amp;rsquo;re finally at the stage of pulling everything (HTML, CSS &amp;amp; JavaScript) together to make minimal web apps. Since the course is light on building challenges, I&amp;rsquo;ve set myself one - to make a simple todo list (the classic step up from &amp;ldquo;hello world&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;The Document Object Model is an entity representing the HTML with attached CSS for a page. The magic is that we can access this in JavaScript, and therefore change it, including hooking into events on it - such as a user pressing a button.&lt;/p&gt;</description></item><item><title>Are you okay JavaScript arrays?</title><link>https://devendevour.iankulin.com/are-you-okay-javascript-arrays/</link><pubDate>Sat, 31 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/are-you-okay-javascript-arrays/</guid><description>&lt;p&gt;As a visitor from sensible type-safe land, this makes me uncomfortable:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-12-23-at-8.52.06-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;As I keep learning, I&amp;rsquo;m interested to find out if JavaScript objects turn out to just be arrays. To get from here to there, you&amp;rsquo;d just need to be able to use some sort of self[2] notation to access properties from inside the functions.&lt;/p&gt;</description></item><item><title>Curse of Backwards Compatibility</title><link>https://devendevour.iankulin.com/curse-of-backwards-compatibility/</link><pubDate>Thu, 29 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/curse-of-backwards-compatibility/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/young-woman-looking-back-over-her-shoulder-impressionist-painting.jpg" alt="young woman looking back over her shoulder, Impressionist painting - Stable diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I was listening to a JavaScript podcast today (&lt;a href="https://www.youtube.com/watch?v=O0fvMJcca3A" target="_blank" rel="noopener"&gt;JavaScript Jabber&lt;/a&gt; ) and in one of the discussions a point was made about how HTML, CSS and JavaScript have all had to maintain considerable legacy behaviors that compile-able languages do not have to. For instance, when Swift underwent some substantial changes from Swift 2 to Swift 3 - some code broke for developers and needed reworking because things had changed or been removed. Nothing broke for users - they could either still use their previously compiled applications, or they were delivered new ones from the app store.&lt;/p&gt;</description></item><item><title>Running Javascript in VS Code</title><link>https://devendevour.iankulin.com/running-javascript-in-vs-code/</link><pubDate>Tue, 27 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/running-javascript-in-vs-code/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-12-21-at-11.08.17-am.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been using the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer" target="_blank" rel="noopener"&gt;Live Server&lt;/a&gt; plugin to see HTML &amp;amp; CSS updated as I edit, and that will also be useful when I start using Javascript for web development, but as you can see above, I&amp;rsquo;m not quite up to that. It seemed there should be a way to run JS in VS Code, and it turns out it&amp;rsquo;s easy.&lt;/p&gt;
&lt;p&gt;You just need something installed that can run Javascript. Node.js is the obvious choice, and you&amp;rsquo;re going to need it later in your development journey. Just i&lt;a href="https://nodejs.org/en/download/" target="_blank" rel="noopener"&gt;nstall Node.js&lt;/a&gt; then the first time you try to run some JS in VS code, it will ask you what to use, select Node and you&amp;rsquo;re in business.&lt;/p&gt;</description></item><item><title>99 CSS Layout challenge</title><link>https://devendevour.iankulin.com/99-css-layout-challenge/</link><pubDate>Fri, 23 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/99-css-layout-challenge/</guid><description>&lt;p&gt;In the &lt;a href="https://zerotomastery.io/" target="_blank" rel="noopener"&gt;Zero To Mastery&lt;/a&gt; &lt;a href="https://www.udemy.com/course/the-complete-web-developer-zero-to-mastery/" target="_blank" rel="noopener"&gt;Complete Web Developer&lt;/a&gt; course, I&amp;rsquo;m up to the first practical challenge - to use CSS to layout a reasonably standard looking web page using flex-box and grid to make it responsive.&lt;/p&gt;
&lt;p&gt;Frustratingly, both for writing this, and while I was trying to build the page, I&amp;rsquo;m unable to screenshot the example of the page I was supposed to be building, and instead had to keep opening the video and seeking the two second flash of the completed project, and eventually being reduced to photographing my laptop screen like a boomer relative sending me a meme:&lt;/p&gt;</description></item><item><title>HTML 001</title><link>https://devendevour.iankulin.com/html-001/</link><pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/html-001/</guid><description>&lt;p&gt;A HTML file is a text file that can be displayed in a web browser. It is &lt;em&gt;marked up&lt;/em&gt; in the sense that &lt;em&gt;tags&lt;/em&gt; are applied to the text to signify the purpose of that text in the structure of the document. For example:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;h1&amp;gt;Greetings&amp;lt;/h1&amp;gt;
Hello Earthlings
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag tells the browser that &lt;code&gt;Greetings&lt;/code&gt; is a heading. The heading tag is &lt;em&gt;paired&lt;/em&gt;. There&amp;rsquo;s an opening tag &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; and closing tag &lt;code&gt;&amp;lt;/h1&amp;gt;&lt;/code&gt; that let the browser know where the heading starts and ends. Most tags are paired, but there are some &lt;em&gt;unpaired&lt;/em&gt; tags such as &lt;br&gt; which inserts a line break.&lt;/p&gt;</description></item><item><title>CSS for Beginners</title><link>https://devendevour.iankulin.com/css-for-beginners/</link><pubDate>Thu, 15 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/css-for-beginners/</guid><description>&lt;p&gt;I mentioned a couple of days ago that the ZTM webdev course was skipping forwards too quick and that it would need to be supplemented. For CSS, I think the supplement for me is going to be this &lt;a href="https://www.youtube.com/playlist?list=PL0Zuz27SZ-6Mx9fd9elt80G1bPcySmWit" target="_blank" rel="noopener"&gt;series&lt;/a&gt; from Dave Gray.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/0W6qz0-aDaM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;</description></item><item><title>Who is Emmet?</title><link>https://devendevour.iankulin.com/who-is-emmet/</link><pubDate>Wed, 14 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/who-is-emmet/</guid><description>&lt;p&gt;&lt;a href="https://www.piqsels.com/en/public-domain-photo-ircsa" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/css-hacks.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;I knew there was some magical way of entering all the the &lt;HTML&gt; boilerplate in Visual Studio Code as I&amp;rsquo;d seen it happen in several videos, and assumed is was some sort of macro expansion thing in the editor. Fast forward a few blog post readings and youtube viewings and I keep seeing tangential references to someone called Emmet. Turns out they&amp;rsquo;re the same thing, and it&amp;rsquo;s pretty cool.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not a new idea to have functionality in code editors to insert snippets of code. &lt;a href="https://docs.emmet.io/" target="_blank" rel="noopener"&gt;Emmet&lt;/a&gt; goes a bit further than that - and like many tools made by programmers for programmers it goes way to technical to the point where you need to memorise ridiculous amounts of combos to to some awesome stuff (I&amp;rsquo;m looking at you whoever made it possible to use vi commands in VS Code). Nevertheless, Emmet is extremely handy even at my n00b level.&lt;/p&gt;</description></item><item><title>ZTM - Complete Web Developer</title><link>https://devendevour.iankulin.com/ztm-complete-web-developer/</link><pubDate>Tue, 13 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/ztm-complete-web-developer/</guid><description>&lt;p&gt;&lt;a href="https://zerotomastery.io/courses/coding-bootcamp/" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-12-11-at-8.31.15-pm.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;I started my first Udemy a few days ago. I was watching one of those &amp;ldquo;&lt;a href="https://www.youtube.com/watch?v=cYNVVspXUdA" target="_blank" rel="noopener"&gt;How I&amp;rsquo;d learn to code if I started over&lt;/a&gt; &amp;rdquo; YouTubes, mainly because I&amp;rsquo;d like to know enough JavaScript to write little REST API&amp;rsquo;s on Node.js, but also because I&amp;rsquo;m starting to think web development makes more sense for a couple of the applications I&amp;rsquo;ve got on my (ever growing) list of app ideas.&lt;/p&gt;</description></item></channel></rss>