<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on dev.endevour</title><link>https://devendevour.iankulin.com/tags/posts/</link><description>Recent content in Posts on dev.endevour</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Sat, 10 Jan 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://devendevour.iankulin.com/tags/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>VS Code Dev Containers</title><link>https://devendevour.iankulin.com/vs-code-dev-containers/</link><pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/vs-code-dev-containers/</guid><description>&lt;h3 id="remote-ssh"&gt;Remote-SSH&lt;/h3&gt; &lt;p&gt;One of the things I&amp;rsquo;ve done a bit in Visual Studio Code is using it&amp;rsquo;s ability to work on a different machine over SSH. I have a couple of LXCs on a server set up for different languages - one for C++ and another for Rust. They are things I don&amp;rsquo;t work in often, and I didn&amp;rsquo;t want to set them up on my laptop, but thought I might want them again sometime in the future.&lt;/p&gt;</description></item><item><title>Getting Ghostty to Work on Synology</title><link>https://devendevour.iankulin.com/getting-ghostty-to-work-on-synology/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/getting-ghostty-to-work-on-synology/</guid><description>&lt;p&gt;Ghostty is a terminal application that I don&amp;rsquo;t really &lt;em&gt;need&lt;/em&gt; (it&amp;rsquo;s &lt;a href="https://ghostty.org/docs/about" target="_blank" rel="noopener"&gt;listed features&lt;/a&gt; either already exist in the MacOS terminal, or seem so esoteric or marginal that I can&amp;rsquo;t imagine any real benefit from them in my normal use), but I &lt;em&gt;wanted&lt;/em&gt; to be one of the cool kids, so I thought I&amp;rsquo;d give it a try.&lt;/p&gt;
&lt;p&gt;After fiddling around with the themes for a bit I renamed it to &amp;rsquo;term-ghosty.app&amp;rsquo; so I&amp;rsquo;d remember to use it (ie when I pop up spotlight and type &amp;rsquo;term&amp;rsquo; it will come up) and got on with my day. Ten minutes later I&amp;rsquo;d run into a problem.&lt;/p&gt;</description></item><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>Writing a Browser Extension</title><link>https://devendevour.iankulin.com/writing-a-browser-extension/</link><pubDate>Sun, 22 Jun 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/writing-a-browser-extension/</guid><description>&lt;p&gt;Web pages are mostly just a collection of HTML, CSS, and JavaScript, so if we had some way of adding some of these into a web page, perhaps from our browser we could add new behaviour to a web page, right?&lt;/p&gt;
&lt;p&gt;Yes; users have long used tools like Greasemonkey (or similar userscript managers) to inject scripts into pages. Better still, modern browsers expose JavaScript APIs that let us interact directly with the browser itself. Enter: browser extensions.&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>Express router for better code organisation</title><link>https://devendevour.iankulin.com/express-router-for-better-code-organisation/</link><pubDate>Mon, 28 Apr 2025 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/express-router-for-better-code-organisation/</guid><description>&lt;p&gt;A Node/Express app I&amp;rsquo;m working on has been sprouting routes so much that the &lt;code&gt;server.js&lt;/code&gt; file has swollen to 800 lines - way past my 200-250 comfort zone, so it&amp;rsquo;s time to organise the routes into their own files. That seems like a good topic for a beginner blog post, so let&amp;rsquo;s dive in.&lt;/p&gt;
&lt;p&gt;Imagine we&amp;rsquo;ve written this little Node/Express app.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import express from &amp;#34;express&amp;#34;;
import {
 dbCustomersGet,
 dbCustomersGetById,
 dbCustomersDelete,
 dbOrdersGet,
 dbOrdersGetById,
 dbOrdersGetByCustomerId,
 dbOrdersDelete,
} from &amp;#34;./db.js&amp;#34;;

const app = express();
app.set(&amp;#34;view engine&amp;#34;, &amp;#34;ejs&amp;#34;);
const port = 3002;

app.use(express.urlencoded({ extended: true }));

app.get(&amp;#34;/&amp;#34;, (req, res) =&amp;gt; {
 res.redirect(&amp;#34;/customers&amp;#34;);
});

app.get(&amp;#34;/customers&amp;#34;, (req, res) =&amp;gt; {
 const customers = dbCustomersGet();
 res.render(&amp;#34;customers&amp;#34;, { customers });
});

app.get(&amp;#34;/customers/:id&amp;#34;, (req, res) =&amp;gt; {
 const customer = dbCustomersGetById(req.params.id);
 const orders = dbOrdersGetByCustomerId(req.params.id);
 res.render(&amp;#34;customer&amp;#34;, { customer, orders });
});

app.get(&amp;#34;/customers/:id/delete&amp;#34;, (req, res) =&amp;gt; {
 dbCustomersDelete(req.params.id);
 res.redirect(&amp;#34;/customers&amp;#34;);
});

app.get(&amp;#34;/orders&amp;#34;, (req, res) =&amp;gt; {
 const orders = dbOrdersGet();
 res.render(&amp;#34;orders&amp;#34;, { orders });
});

app.get(&amp;#34;/orders/:id&amp;#34;, (req, res) =&amp;gt; {
 const order = dbOrdersGetById(req.params.id);
 const customer = dbCustomersGetById(order.customerId);
 res.render(&amp;#34;order&amp;#34;, { order, customer });
});

app.get(&amp;#34;/orders/:id/delete&amp;#34;, (req, res) =&amp;gt; {
 dbOrdersDelete(req.params.id);
 res.redirect(&amp;#34;/orders&amp;#34;);
});

app.listen(port, () =&amp;gt; {
 console.log(`Listening on http://127.0.0.1:${port}`);
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Although concocted, this would seem familiar to anyone who&amp;rsquo;s built a CRUD business 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>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>Clear explanation of how transformer AI works</title><link>https://devendevour.iankulin.com/clear-explanation-of-how-transformer-ai-works/</link><pubDate>Mon, 28 Oct 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/clear-explanation-of-how-transformer-ai-works/</guid><description>&lt;p&gt;If you&amp;rsquo;re interested in how generative AI works, check out &lt;a href="https://ishananand.com/" target="_blank" rel="noopener"&gt;Ishan Anand&lt;/a&gt; &amp;rsquo;s Youtube series &amp;ldquo;&lt;a href="https://www.youtube.com/@Spreadsheetsareallyouneed" target="_blank" rel="noopener"&gt;Spreadsheets are all you need&lt;/a&gt; &amp;rdquo;. He steps through the basics using an Excel spreadsheet that encompasses most of GPT-2. Just doing that is an impressive (and hilarious) feat, but he also has a knack for teaching, so you&amp;rsquo;ll come away with a good understanding of AI and how some of it&amp;rsquo;s limitations manifest.&lt;/p&gt;
&lt;p&gt;Ishan is selling a course, which I guess these are the first three lessons of, and I got a lot out of them. It&amp;rsquo;s also possible to &lt;a href="https://github.com/ianand/spreadsheets-are-all-you-need/releases/tag/v0.6.1" target="_blank" rel="noopener"&gt;download the spreadsheet&lt;/a&gt; he uses in the course to play with.&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>LLM coding question comparison using Ollama</title><link>https://devendevour.iankulin.com/llm-coding-question-comparison-using-ollama/</link><pubDate>Mon, 29 Jul 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/llm-coding-question-comparison-using-ollama/</guid><description>&lt;p&gt;Now Ollama has made it simple enough for anyone who can use a terminal to run large language models locally, naturally I&amp;rsquo;ve gone overboard downloading too many to play with. I&amp;rsquo;m increasingly feeling they definitely have a place in the devops/coding arsenal of tools, but which model is best?&lt;/p&gt;
&lt;p&gt;If you go on HuggingFace to look at a new model you&amp;rsquo;re interested, they often have great comparisons like this.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://huggingface.co/deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/performance.png" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;</description></item><item><title>dockerfile - CMD vs ENTRYPOINT</title><link>https://devendevour.iankulin.com/dockerfile-cmd-vs-entrypoint/</link><pubDate>Mon, 22 Jul 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/dockerfile-cmd-vs-entrypoint/</guid><description>&lt;p&gt;There are two entries we often have at the end of a &lt;code&gt;dockerfile&lt;/code&gt; (which is the file that tells Docker how an image is to be built).&lt;/p&gt;
&lt;p&gt;They are similar in that when the container is launched from an image, these commands will be executed. For example, both of the dockerfiles below will print &amp;ldquo;Hello World&amp;rdquo; when run.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;doc-&lt;/code&gt;entry:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;FROM debian:stable-slim
ENTRYPOINT [&amp;#34;echo&amp;#34;, &amp;#34;Hello World from ENTRYPOINT&amp;#34;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;doc-cmd&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;FROM debian:stable-slim
CMD [&amp;#34;echo&amp;#34;, &amp;#34;Hello World&amp;#34;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2024-07-03-at-1.45.26-pm.png" alt="" class="img-responsive"&gt; &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>Virtual Hosts on "Static Web Server"</title><link>https://devendevour.iankulin.com/virtual-hosts-on-static-web-server/</link><pubDate>Mon, 22 Apr 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/virtual-hosts-on-static-web-server/</guid><description>&lt;p&gt;I&amp;rsquo;ve been running &lt;a href="https://devendevour.iankulin.com/nginx-proxy-manager/"&gt;NGINX Proxy Manager&lt;/a&gt; (NPM) in my homelab for a bit, and I&amp;rsquo;ve been meaning to clean up the VPS that runs most of my websites and public facing servers, so I&amp;rsquo;m considering running NGINX Proxy Manager on that VPS. While NGINX Proxy Manager wraps up the configs in a beautiful GUI, in the process you lose some of NGINXs capabilities. In particular there&amp;rsquo;s no GUI way to serve static virtual hosts from NGINX Proxy Manager.&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>Hosting Your Own Docker Registry</title><link>https://devendevour.iankulin.com/hosting-your-own-docker-registry/</link><pubDate>Mon, 25 Mar 2024 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/hosting-your-own-docker-registry/</guid><description>&lt;p&gt;&lt;a href="https://unsplash.com/photos/architectural-photography-of-cargo-containers-stack-hP4ZiN1_kdk?utm_content=creditShareLink&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/tri-eptaroka-mardiana-hp4zin1_kdk-unsplash.jpg" alt="Photo by Tri Eptaroka Mardianam on Unsplash
" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;The Docker &lt;a href="https://docs.docker.com/subscription/core-subscription/details/" target="_blank" rel="noopener"&gt;Personal (ie free tier) plan&lt;/a&gt; currently allows one private repository, but even if you want to pay for the next level where you can have unlimited repositories, you may still want to host your own private registry - it&amp;rsquo;s going to be quicker inside your network, and you won&amp;rsquo;t run up against Docker&amp;rsquo;s pull/push limits if you are hammering it with your CI/CD system.&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>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>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>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>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>Git - pushing to two remotes</title><link>https://devendevour.iankulin.com/git-pushing-to-two-remotes/</link><pubDate>Fri, 15 Dec 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/git-pushing-to-two-remotes/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/tanjian1998_an_ai_humanoid_pushing_a_shopping_cart_with_that_ha_5eceff04-704f-403d-af6d-46fd9ba57909.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I am loving running a local Gogs instance - it&amp;rsquo;s nice pushing my git repos to a totally private hub that I know is backed up with all my other self-hosted infrastructure.&lt;/p&gt;
&lt;p&gt;Of course, there&amp;rsquo;s good reasons to have code in GitHub as well - my build-in-public philosophy, the vague possibility that some of it might be useful to someone, my contribution to our future AI overlords, and when I need to make some code linkable - for example from one of these posts. And of course there&amp;rsquo;s this bit of social-engineering which I assume was inspired by the bathroom decor in &lt;a href="https://i.pinimg.com/originals/94/23/85/9423854153f55938c454a061ad5462fe.gif" target="_blank" rel="noopener"&gt;Veronica Mars&lt;/a&gt; .&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>New Self-Hosted Service Workflow</title><link>https://devendevour.iankulin.com/new-self-hosted-service-workflow/</link><pubDate>Sun, 03 Dec 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/new-self-hosted-service-workflow/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/es047_illustration_of_a_workflow_with_only_four_text_boxes_with_b026526e-30b7-45c7-9491-080adc1594ce.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve developed a bit of a workflow for setting up a new service of some type on the homelab. Installing it is the obvious thing, but I also have a few quality of life things I do to make it a full production-quality part of my installation. I thought it might be helpful to run through those things using a recent example of adding &lt;a href="https://www.audiobookshelf.org/" target="_blank" rel="noopener"&gt;audiobookshelf&lt;/a&gt; .&lt;/p&gt;
&lt;h3 id="audiobookshelf"&gt;audiobookshelf&lt;/h3&gt; &lt;p&gt;&lt;a href="https://www.audiobookshelf.org/" target="_blank" rel="noopener"&gt;audiobookshelf&lt;/a&gt; is a web based system for viewing, playing, downloading and/or generally managing your audio books. I&amp;rsquo;ve been an &lt;a href="https://www.audible.com.au/" target="_blank" rel="noopener"&gt;Audible&lt;/a&gt; user/subscriber, but recently got grumpy at them about something - I think I had paused my subscription, and my downloaded books were still available on my phone. I was halfway through one, upgraded the app, and then wasn&amp;rsquo;t able to play the book without re-subscribing. That might not be exactly right, but it was some type of frustrating carry on like that.&lt;/p&gt;</description></item><item><title>ViewTube</title><link>https://devendevour.iankulin.com/viewtube/</link><pubDate>Mon, 27 Nov 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/viewtube/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2023-11-18-at-5.17.47-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Whenever I encounter one of those &amp;ldquo;What are you self-hosting?&amp;rdquo; threads, I know I&amp;rsquo;m about to waste an hour looking at, and often trying out, software I probably don&amp;rsquo;t really need, and that was the case with &lt;a href="https://lemmy.world/post/8385160" target="_blank" rel="noopener"&gt;this post&lt;/a&gt; on the &lt;a href="https://lemmy.world/c/selfhost@lemmy.ml" target="_blank" rel="noopener"&gt;lemmy.world Selfhosted&lt;/a&gt; community.&lt;/p&gt;
&lt;p&gt;The basic idea of ViewTube is that it&amp;rsquo;s a self-hosted front end for YouTube, which just happens to strip out all the advertising and tracking. You can create your own local accounts which allows you to subscribe to channels and which keeps your progress so you don&amp;rsquo;t start over if you go back to a video - although I couldn&amp;rsquo;t see a history list. Forgetting your history might be a feature in an app designed to prevent tracking.&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>Basic VPS disk speed</title><link>https://devendevour.iankulin.com/basic-vps-disk-speed/</link><pubDate>Sat, 09 Sep 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/basic-vps-disk-speed/</guid><description>&lt;p&gt;I couldn&amp;rsquo;t help but measure some VPS disk speeds while I was busting out the &lt;code&gt;fio&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/vps.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Binary Lane only claims &amp;ldquo;pure SSD drives&amp;rdquo; but seems pretty great. The difference between Digital Ocean SSD and NVME is disappointing. Obviously you&amp;rsquo;re sharing a drive with other users, so perhaps this depends on what else is going on.&lt;/p&gt;</description></item><item><title>Nginx config on Debian/Ubuntu</title><link>https://devendevour.iankulin.com/nginx-config-on-debian-ubuntu/</link><pubDate>Wed, 16 Aug 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/nginx-config-on-debian-ubuntu/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/ea49e0c3-f1d2-4060-83df-18b2cd52e734_damian_he_him_they_linux_tree-directory_structure_in_egyptian_hieroglyphs_-hd.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A quick look at the arrangements around the config settings for nginx. This is based on what I can see in Debian and Ubuntu, but likely it will be most &lt;code&gt;apt&lt;/code&gt; flavoured distros. Others may well be different, I know CentOS is.&lt;/p&gt;
&lt;h3 id="context"&gt;Context&lt;/h3&gt; &lt;p&gt;If the way the configs for nginx are arranged seems a little complicated, it&amp;rsquo;s helpful to keep in mind there&amp;rsquo;s a couple of challenges that are being addressed with that complexity.&lt;/p&gt;</description></item><item><title>Where to go after Reddit</title><link>https://devendevour.iankulin.com/where-to-go-after-reddit/</link><pubDate>Tue, 01 Aug 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/where-to-go-after-reddit/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/rpg_40_diaspora_of_reddit_users_searching_for_new_homes_in_a_d_0.jpg" alt="Diaspora of Reddit users searching for new homes in a dystopian landscape of abandoned technology" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A big chunk of my mindless doomscrolling used to go to Reddit, but also, Reddit posts from the various communities were frequently the useful results when googling error messages. I lurked in many a sub-reddit, but only posted in a couple - usually r/self-hosted or r/Homelab.&lt;/p&gt;
&lt;p&gt;The problematic treatment of the communities in the leadup to their IPO has been well publicised, and the short blackout by some subreddits seemed to have zero effect on the company&amp;rsquo;s approach to it&amp;rsquo;s users (which is in fact what they have to sell). Those subreddits, and many others are still working, but (and perhaps I&amp;rsquo;m imagining this) seem somehow thinner. Additionally, I feel like it&amp;rsquo;s a fragile arrangement - the company has shown how they will deal with their communities, so depending on them in the long term does not seem wise, or even, somehow, ethical - like I&amp;rsquo;m crossing a picket line.&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>HDD Swap on A1278 MacBook Pro</title><link>https://devendevour.iankulin.com/hdd-swap-on-a1278-macbook-pro/</link><pubDate>Wed, 10 May 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/hdd-swap-on-a1278-macbook-pro/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/dexxx3d_computer_repair_shop__a_lot_of_computer_laptop_for_repa_7ee46d83-216e-4f67-81af-ee3c7037e6e7.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;My MacBook died, I guess about three years ago. It was randomly difficult for a week or so, but then just behaving as if it had no hard drive at all. It&amp;rsquo;s been in a drawer ever since waiting for me to replace the hard drive and see if I could sell it, which I never quite got to.&lt;/p&gt;
&lt;p&gt;I mentioned a while ago that I&amp;rsquo;d &lt;a href="https://devendevour.iankulin.com/linux-on-hp-mini-110/"&gt;borrowed an old Atom powered HP Mini 110&lt;/a&gt; to play with a Linux desktop machine, partly for fun &amp;amp; learning, and partly for a first-class SPICE experience (also fun). Meanwhile I&amp;rsquo;ve got an old but still sexy Intel MacBook Pro sitting in a drawer - that doesn&amp;rsquo;t make sense!&lt;/p&gt;</description></item><item><title>Outside Temperature From an API in a Shell Script</title><link>https://devendevour.iankulin.com/outside-temperature-from-an-api-in-a-shell-script/</link><pubDate>Wed, 03 May 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/outside-temperature-from-an-api-in-a-shell-script/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/challengereality_a_highly_detailed_ultra_high_resolution_hologr_1509798a-548d-4528-bcc7-cb1f2bb30a0e.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m interested in &lt;a href="https://devendevour.iankulin.com/linux-shell-script-for-temperature-logging/"&gt;collecting some internal temperature data&lt;/a&gt; from my servers to look at the effect of adding an NMVe drive. Last week we had a couple of warm days immediately followed by a couple of cool ones. I imagine a 20° ambient temperature change could effect the server temperatures, so I thought it would be good to add that to my temperature logs.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t have a weather station or other automated system for collecting the temperature, but there are several commercial sources for this data which, while probably not as good as a sensor in the server room, will be fine for our purposes.&lt;/p&gt;</description></item><item><title>Linux on HP Mini 110</title><link>https://devendevour.iankulin.com/linux-on-hp-mini-110/</link><pubDate>Mon, 17 Apr 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/linux-on-hp-mini-110/</guid><description>&lt;p&gt;I&amp;rsquo;ve been furthering my Linux education by playing with some desktop distros in VMs, but it&amp;rsquo;s not a great experience accessing them through the Proxmox web GUI. The alternative to this is to use a good &lt;a href="https://en.wikipedia.org/wiki/Simple_Protocol_for_Independent_Computing_Environments" target="_blank" rel="noopener"&gt;SPICE&lt;/a&gt; client on the remote desktop, but there is &lt;a href="https://forum.proxmox.com/threads/access-vm-thru-spice-on-osx.66727/" target="_blank" rel="noopener"&gt;not a simple good solution&lt;/a&gt; for this for MacOS.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been playing with the idea of picking up an old i3/i5 Thinkpad - these are around the AUD130 mark on eBay, to run a Linux distro with the main idea being to use it to SPICE into my VMs.&lt;/p&gt;</description></item><item><title>rsync / Synology / @eaDir</title><link>https://devendevour.iankulin.com/rsync-synology-eadir/</link><pubDate>Tue, 28 Mar 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/rsync-synology-eadir/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/extendedattributes_31636167.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The reason I&amp;rsquo;ve been figuring out rsync is to setup my backup strategy. Eventually this will partly be managed with scheduled tasks (ie cron jobs) running rsync. I wanted the SSH in and try this out, since I didn&amp;rsquo;t know some basic things like the mount points of the shares.&lt;/p&gt;
&lt;h3 id="mount-points"&gt;Mount points&lt;/h3&gt; &lt;p&gt;My first issue was to find the paths to all my data. This turned out not to be a drama. Each of the volumes you create when the NAS is set up are just in the root directory. This includes any USB drives plugged in.&lt;/p&gt;</description></item><item><title>SSH with Keys to Synology</title><link>https://devendevour.iankulin.com/ssh-with-keys-to-synology/</link><pubDate>Mon, 27 Mar 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/ssh-with-keys-to-synology/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/hddlockedup_50825865.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The Synology operating system DSM (I&amp;rsquo;m on DSM 7.1.1) is Linux, but its highly customised for the purpose of making running a complicated Linux NAS doable for less technical users.&lt;/p&gt;
&lt;p&gt;Due to that, some things that are routine in a regular distro, require a few more steps to jump through to get them to work. SSH-ing in to a Synology with keys is one of those things.&lt;/p&gt;
&lt;h3 id="should-you"&gt;Should you?&lt;/h3&gt; &lt;p&gt;Before you do start fiddling around, it&amp;rsquo;s probably worth mentioning that almost all the things you might want to do on the Synology can be accomplished through their web interface, or by installing a &amp;lsquo;package&amp;rsquo; from the &lt;em&gt;Package Center&lt;/em&gt;. For example, if you need to run a cron job, that&amp;rsquo;s done through the &lt;em&gt;Control Panel&lt;/em&gt; &amp;lsquo;&lt;em&gt;Task Scheduler&lt;/em&gt;&amp;rsquo;. If you need TailScale installed to easily access it over Wireguard, there&amp;rsquo;s a TailScale package. In general it&amp;rsquo;s probably easier and safer to do things their way.&lt;/p&gt;</description></item><item><title>Nostalgia</title><link>https://devendevour.iankulin.com/nostalgia/</link><pubDate>Tue, 14 Mar 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/nostalgia/</guid><description>&lt;p&gt;I&amp;rsquo;m not super interested in FreeDOS, but did enjoy this video from Jim Hall since I lived through all this, and was working in IT (well, &amp;lsquo;data processing&amp;rsquo; actually) during the introduction of the IBM PC.&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/3E5Hog5OnIM?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;My first DOS was 2.11, but spent a lot more time on 3.12, and later 4.01. Windows wasn&amp;rsquo;t really ready for anyone until 3.1 which is when I dived in there. I seem to remember purchasing a PC with a whole megabyte of RAM in anticipation!&lt;/p&gt;</description></item><item><title>NAS Storage Calculations</title><link>https://devendevour.iankulin.com/nas-storage-calculations/</link><pubDate>Sat, 11 Mar 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/nas-storage-calculations/</guid><description>&lt;p&gt;I&amp;rsquo;ve been really happy with my two bay Synology NAS - a DS216j. The Synology&amp;rsquo;s seem to have great reputation for just pushing on. Mine is loaded up with two 8TB Seagate Barracudas in RAID 1 leaving me with a one drive failure redundancy.&lt;/p&gt;
&lt;p&gt;I guess a more hard-core host-er than me would be building their own array and using Unraid or ZFS or something. I&amp;rsquo;m pretty comfortable with the Synology off the shelf system; it&amp;rsquo;s a good match for my (low) level of expertise, and more robust than my previous storage system of a USB external drive.&lt;/p&gt;</description></item><item><title>Could it be a permissions problem?</title><link>https://devendevour.iankulin.com/could-it-be-a-permissions-problem/</link><pubDate>Sun, 05 Mar 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/could-it-be-a-permissions-problem/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/padlock.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Unix, and therefore Linux, was built from the ground up as a multi-user system. Thanks to this, great security is baked in, for example every file has permission attributes for it&amp;rsquo;s owner, the group the owner is a member of, and then everyone. For example, it might be a good idea if I can read, write and execute my own files, but the other members of my group can just read them, and any other user on the system has none of those rights.&lt;/p&gt;</description></item><item><title>Classes in JavaScript</title><link>https://devendevour.iankulin.com/classes-in-javascript/</link><pubDate>Sat, 07 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/classes-in-javascript/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_futuristic_machine_making_copies_of_people_f1076d37-add2-4592-952b-ac8ac30c7a5c.jpg" alt="futuristic machine making copies of people - midjourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;First lesson with classes today. First of all I was pleased to see they exists since we&amp;rsquo;ve just been plucking objects out of thing air like:&lt;code&gt;}&lt;/code&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;const userIan = {name: &amp;#39;Ian&amp;#39;, language: &amp;#39;Indonesian&amp;#39;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;but with classes we can declare a class and instantiate an object of it:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;class User {
 constructor(name, language) {
 this.name = name;
 this.language = language;
 }
}

const ian = new User(&amp;#39;Ian&amp;#39;, &amp;#39;Indonesian&amp;#39;);
console.log(ian.name);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;rsquo;s (at least) single inheritance:&lt;/p&gt;</description></item><item><title>Things I love about Swift after a week of JavaScript</title><link>https://devendevour.iankulin.com/things-i-love-about-swift-after-a-week-of-javascript/</link><pubDate>Fri, 06 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/things-i-love-about-swift-after-a-week-of-javascript/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/swift-logo-punching-the-javascript-logo.jpg" alt="Swift logo punching the JavaScript logo - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;So, a week into JavaScript, what am I missing? The techie in me wants to say things like Automatic Reference Counting, but actually, at my junior level, I don&amp;rsquo;t run into memory management issues on the day-to-day, so what really do I miss?&lt;/p&gt;
&lt;h4 id="determinism"&gt;Determinism&lt;/h4&gt; &lt;p&gt;When I build an iOS app, it&amp;rsquo;s frozen in time. The functions inside are always going to stay the same. There might be a future version of iOS that won&amp;rsquo;t run it, but as long as it runs, any pure functions inside it will return the same value. The process of compiling it locks that in. Likewise, any libraries that are complied with it.&lt;/p&gt;</description></item><item><title>Second Guessing</title><link>https://devendevour.iankulin.com/second-guessing/</link><pubDate>Thu, 05 Jan 2023 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/second-guessing/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/pucker_young_women_identical_twins_enjoying_the_beach_unreal_en_89773710-ae61-42d7-bede-d74ef60dafd3.jpg" alt="young women identical twins enjoying the beach unreal engine - midjourney" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;In the last post, I was pleased with myself for accidentally anticipating an improvement to a tutorial project which turned out to be the next task, today I&amp;rsquo;m pleased with myself for discussing the pros and cons of &lt;code&gt;onclick=&lt;/code&gt; vs &lt;code&gt;addEventListener()&lt;/code&gt; then having that same discussion turn up in the next tutorial. I take it as an indication that I am correctly immersing myself in the subject.&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 002 - Tags for structure</title><link>https://devendevour.iankulin.com/html-002-tags-for-structure/</link><pubDate>Wed, 21 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/html-002-tags-for-structure/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/young-woman-at-a-computer-writing-html-impressionistic.jpg" alt="Young woman at a computer writing html, Impressionistic - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I briefly mentioned &lt;a href="https://devendevour.iankulin.com/html-001/"&gt;earlier&lt;/a&gt; that our HTML tags should flag WHAT this part of the document is rather than how to display it (we&amp;rsquo;ll look at how to use CSS for making the content look how we want later). This idea is called semantic HTML. This post will look at some of the tags (often called &lt;a href="https://www.w3schools.com/html/html5_semantic_elements.asp" target="_blank" rel="noopener"&gt;semantic tags&lt;/a&gt; ) we use to convey knowledge of what part of each document an element is.&lt;/p&gt;</description></item><item><title>Visual Studio Code</title><link>https://devendevour.iankulin.com/visual-studio-code-2/</link><pubDate>Mon, 12 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/visual-studio-code-2/</guid><description>&lt;p&gt;I&amp;rsquo;ve gone over to the dark side a little. As I think about the sort of apps I want to make, I realise I am going to need to be able to do back-end web development. My apps are going to need a secure REST api to a database. I guess that means node.js. I&amp;rsquo;m also conscious that my ticket app needs to run on android, and a short cut around all of that might be to make the whole thing a web app from the start, but with the premium experience on iOS.&lt;/p&gt;</description></item><item><title>Clean code</title><link>https://devendevour.iankulin.com/clean-code/</link><pubDate>Fri, 09 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/clean-code/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/young-woman-cleaning-a-computer-painting.jpg" alt="young woman cleaning a computer, painting - stable diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been listening to the &lt;a href="https://www.youtube.com/watch?v=YVrHPCZnC50" target="_blank" rel="noopener"&gt;latest episode of the Empower Apps&lt;/a&gt; podcast, this one with &lt;a href="https://twitter.com/Jilsco9" target="_blank" rel="noopener"&gt;Jill Scott&lt;/a&gt; talking about &amp;ldquo;Humane&amp;rdquo; development - in the sense of being humane to whoever (probably you) is going to be reading this code in the future. It helped me clarify my thoughts about a couple of things.&lt;/p&gt;
&lt;p&gt;None of these ideas are particularly new or groundbreaking, and although I think of them as my personal style, they are very common, and in Swift could be regarded as part of the culture. Some of these concepts support each other, some represent a trade off between two opposing ideas that require us to make a choice.&lt;/p&gt;</description></item><item><title>SwiftUI provides</title><link>https://devendevour.iankulin.com/swiftui-provides/</link><pubDate>Wed, 07 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/swiftui-provides/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/img_3476.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A few hours after I speculated about pausing work on the tickets app because outputting the tickets was too far out of my expertise, a helpful instance of the &lt;a href="https://en.wikipedia.org/wiki/Frequency_illusion" target="_blank" rel="noopener"&gt;Baader–Meinhof phenomenon&lt;/a&gt; threw up some help in the form of this tweet from &lt;a href="https://twitter.com/flowritescode" target="_blank" rel="noopener"&gt;@FloWritesCode&lt;/a&gt; . It turns out this was an addition in iOS16 announced at WWDC that makes this straightforward.&lt;/p&gt;
&lt;p&gt;As soon as I googled around about it I also found good solutions that wrapped the old code to provide similar functionality. So that&amp;rsquo;s a lesson for me about not assuming something&amp;rsquo;s hard before I&amp;rsquo;ve spent some time investigating it. I took that lesson and applied it to rendering to a PDF, and of course, @twostraws &lt;a href="https://www.hackingwithswift.com/quick-start/swiftui/how-to-render-a-swiftui-view-to-a-pdf" target="_blank" rel="noopener"&gt;has a code example&lt;/a&gt; for that from three days ago!&lt;/p&gt;</description></item><item><title>Committed</title><link>https://devendevour.iankulin.com/committed/</link><pubDate>Tue, 06 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/committed/</guid><description>&lt;p&gt;I quite like logging into GitHub and seeing my commit history as the graph with the green dots. Once I get up to a year it would be a great thing to have on a T-Shirt.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-12-03-at-7.36.29-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d expect to be seeing the busy weekends, but Tuesday nights seem to be oddly productive. It could just be a start of the week energy thing - I have some other community obligations on a couple of Monday nights a month.&lt;/p&gt;</description></item><item><title>Ticket to ride</title><link>https://devendevour.iankulin.com/ticket-to-ride/</link><pubDate>Mon, 05 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/ticket-to-ride/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/superman-crashing-into-a-train-cartoon-2.jpg" alt="superman crashing into a train, cartoon - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A &lt;a href="https://devendevour.iankulin.com/project-based-learning/"&gt;couple of days ago&lt;/a&gt; I was lauding the learning benefits of writing your own projects over completing tutorial projects - since your own projects push your boundaries further. Of course, its also the case that the project requirements might so completely exceed your current ability that it grinds to a halt. That&amp;rsquo;s the case with my &lt;a href="https://devendevour.iankulin.com/tickets-on-myself/"&gt;behaviour ticket app&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;The part of the app for collecting the data is pretty much done and how I imagined it, but the output needs to be pretty tickets that can be printed on paper. I managed to write the ticket data to a CSV file and export that to the files app with a .fileExporter, but really what I wanted is to have one of those share screens where you can chose to AirDrop, Print etc, and for the tickets to have been rendered to a PDF or series of images to be shared. That will have to wait. I&amp;rsquo;m just up to a bit in the #100Days about writing images so I&amp;rsquo;ll push on with that for a bit and come back to my app.&lt;/p&gt;</description></item><item><title>Pi Server</title><link>https://devendevour.iankulin.com/pi-server/</link><pubDate>Sun, 04 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/pi-server/</guid><description>&lt;p&gt;I have a a couple of Raspberry Pi&amp;rsquo;s on my home network. One is a radio interface on the &lt;a href="https://www.allstarlink.org/" target="_blank" rel="noopener"&gt;AllStar network&lt;/a&gt; , and the other is just a toy server - I can&amp;rsquo;t actually recall why I bought it. Both of them are Model 3B&amp;rsquo;s - I&amp;rsquo;d love a 4, but they are scarce and expensive.&lt;/p&gt;
&lt;p&gt;This doesn&amp;rsquo;t have much to do with Swift, although it&amp;rsquo;s possible to run &lt;a href="https://lickability.com/blog/swift-on-raspberry-pi/" target="_blank" rel="noopener"&gt;Swift on a Pi&lt;/a&gt; , or even &lt;a href="https://medium.com/@jhheider/installing-vapor-and-swift-on-the-raspberry-pi-45a6c7baef35" target="_blank" rel="noopener"&gt;Vapor&lt;/a&gt; . Mine is set up as a generic web server that I use as the back end for my tiny projects. It runs &lt;a href="https://nodejs.org/en/about/" target="_blank" rel="noopener"&gt;Node.js&lt;/a&gt; , &lt;a href="https://www.apache.org/" target="_blank" rel="noopener"&gt;apache&lt;/a&gt; and &lt;a href="https://www.lighttpd.net/" target="_blank" rel="noopener"&gt;lighttpd&lt;/a&gt; webservers, &lt;a href="https://www.php.net/" target="_blank" rel="noopener"&gt;PHP&lt;/a&gt; , &lt;a href="https://www.mysql.com/" target="_blank" rel="noopener"&gt;MySQL&lt;/a&gt; , &lt;a href="https://www.sqlite.org/index.html" target="_blank" rel="noopener"&gt;SQLite&lt;/a&gt; , and, when I get to that stage of my programmming, &lt;a href="https://pimylifeup.com/raspberry-pi-postgresql/" target="_blank" rel="noopener"&gt;Postgres&lt;/a&gt; . I could do all that on my MacBook, but it&amp;rsquo;s somehow more fun on the Pi.&lt;/p&gt;</description></item><item><title>Towards MVVM</title><link>https://devendevour.iankulin.com/towards-mvvm/</link><pubDate>Sat, 03 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/towards-mvvm/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/young-woman-swimming-in-spaghetti-by-hokusai-.jpg" alt="young woman swimming in spaghetti, by Hokusai - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;On one of the more mediocre &lt;a href="https://firesideswift.fireside.fm/96" target="_blank" rel="noopener"&gt;episodes of Fireside Swift&lt;/a&gt; , McSwiftface and Zach talk about the &lt;a href="https://en.wikipedia.org/wiki/SOLID" target="_blank" rel="noopener"&gt;SOLID principles&lt;/a&gt; of class design, although I don&amp;rsquo;t hold the principles as the article of religious fervour that many interviewers apparently do, they are a useful touchstone for considering class quality. OOP had been in swing (in a commercial way) for a few years by then - I was writing in Delphi and C++. The spaghetti code era was a long way behind us and the idea of separation of responsibilities was well established.&lt;/p&gt;</description></item><item><title>Deep Linking</title><link>https://devendevour.iankulin.com/deep-linking/</link><pubDate>Fri, 02 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/deep-linking/</guid><description>&lt;p&gt;I was listening to an &lt;a href="https://firesideswift.fireside.fm/100" target="_blank" rel="noopener"&gt;old episode of Fireside Swift&lt;/a&gt; today discussing NFC tags. I have a bundle of this tags in a drawer here somewhere - I thought it would be cool to tap one as I came home to turn off the CCTV and some other home automation things. But it turns out my phone (an SE2) has the capability for this, but only inside an app - not just from anywhere, whereas the proper phones can just tap anytime, and if the NFC payload is set up correctly, follow a URL, including by &amp;ldquo;deep linking&amp;rdquo; into an app.&lt;/p&gt;</description></item><item><title>Project Based Learning</title><link>https://devendevour.iankulin.com/project-based-learning/</link><pubDate>Thu, 01 Dec 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/project-based-learning/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/young-woman-holding-a-phone-outside-near-a-lake-painting.jpg" alt="young woman holding a phone outside near a lake, painting - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A couple of times in conversations on &lt;a href="https://firesideswift.fireside.fm/" target="_blank" rel="noopener"&gt;Fireside Swift&lt;/a&gt; and &lt;a href="https://podcasts.apple.com/au/podcast/swift-over-coffee/id1435076502" target="_blank" rel="noopener"&gt;Swift Over Coffee&lt;/a&gt; the presenters have talked about the danger of just doing more and more tutorials to learn programming, and the benefit, in contrast, of building your own real app. Although I am very much still benefiting from the 100DaysOfSwiftUI I have been seeing some of the upside of working on a real app in the last day and a half.&lt;/p&gt;</description></item><item><title>Tickets on Myself</title><link>https://devendevour.iankulin.com/tickets-on-myself/</link><pubDate>Sun, 27 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/tickets-on-myself/</guid><description>&lt;p&gt;Way back on Day 47 I wrote a little habit tracking app. It was the challenge at the end of a JSON tutorial, so the persistence is done by writing the JSON to UserDefaults as a string. Basic as it is, it&amp;rsquo;s installed on my phone and I check it a couple of times a day, and haven&amp;rsquo;t missed a day of coding, or the weekly bin day since. It&amp;rsquo;s strangely motivating.&lt;/p&gt;</description></item><item><title>Something weird 'append</title><link>https://devendevour.iankulin.com/something-weird-about-append/</link><pubDate>Mon, 21 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/something-weird-about-append/</guid><description>&lt;p&gt;I&amp;rsquo;m noodling around making sure I understand how Core Data works. Thought I&amp;rsquo;d start with a master/detail app with an array of structs, then replicate it in a Core Data implementation. I&amp;rsquo;m using an array of this struct for my data:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;struct Garden {
 var id = UUID()
 var name = &amp;#34;&amp;#34;
 var address = &amp;#34;&amp;#34;
 var plants: [Plant] = []
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And I thought this code to load up some sample data was pretty sweet.&lt;/p&gt;</description></item><item><title>Tough Day</title><link>https://devendevour.iankulin.com/tough-day/</link><pubDate>Sun, 20 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/tough-day/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/bad-day-at-sea-uspaceken.jpg" alt="" class="img-responsive"&gt; 
&lt;em&gt;&lt;a href="https://www.reddit.com/r/Art/comments/7i7crd/bad_day_at_sea_ii_30_x_40_oil/" target="_blank" rel="noopener"&gt;Bad Day at Sea - reddit u/SpaceKen&lt;/a&gt; &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Day 61 of &lt;a href="https://www.hackingwithswift.com/100/swiftui/61" target="_blank" rel="noopener"&gt;#100DaysOfSwiftUI&lt;/a&gt; is a tough day. It&amp;rsquo;s the first real big test of Core Data understanding, and I&amp;rsquo;m finding I didn&amp;rsquo;t actually understand how the code for Core Data works. For the first time, I&amp;rsquo;m thinking of going back and redoing the days leading up to it.&lt;/p&gt;
&lt;p&gt;To try and get it straight in my mind, here&amp;rsquo;s how I think Core Data works:&lt;/p&gt;</description></item><item><title>iOS Dev Twitter</title><link>https://devendevour.iankulin.com/ios-dev-twitter/</link><pubDate>Fri, 18 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/ios-dev-twitter/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/twitter-logo-bird-bleeding.jpg" alt="Twitter logo bird bleeding - stable diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;One of &lt;a href="https://www.youtube.com/c/SeanAllen/videos" target="_blank" rel="noopener"&gt;Sean Allen&amp;rsquo;s&lt;/a&gt; many pieces of excellent advice was to follow a few Swift/iOS dev people on Twitter. I took that advice, and it is now a source of joy to flick through every couple of days and get a feel for what&amp;rsquo;s happening, and to discover new things. It&amp;rsquo;s how I learned &lt;a href="https://iosdevweekly.com/" target="_blank" rel="noopener"&gt;iOS Dev Weekly&lt;/a&gt; existed, and discovered &lt;a href="https://designcode.io/instructor/meng" target="_blank" rel="noopener"&gt;Meng To&lt;/a&gt; , and put faces/ideas to Swift and iOS people that&amp;rsquo;s I&amp;rsquo;d heard mentioned or interviewed in podcasts such as &lt;a href="https://ericasadun.com/" target="_blank" rel="noopener"&gt;Erica Sadun&lt;/a&gt; and &lt;a href="https://sarunw.com/" target="_blank" rel="noopener"&gt;Sarun W.&lt;/a&gt; &lt;/p&gt;</description></item><item><title>FriendFace Feedback</title><link>https://devendevour.iankulin.com/friendface-feedback/</link><pubDate>Tue, 15 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/friendface-feedback/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-11-12-at-4.38.24-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;After each app, I use my HackingWithSwift+ membership to view Paul&amp;rsquo;s version of the app as a way to judge my performance. Yesterday&amp;rsquo;s app was &amp;ldquo;&lt;a href="https://www.hackingwithswift.com/guide/ios-swiftui/5/3/challenge" target="_blank" rel="noopener"&gt;FriendFace&lt;/a&gt; &amp;rdquo; - download some JSON of a number of people (including their friends) and display it.&lt;/p&gt;
&lt;h4 id="uuid"&gt;UUID&lt;/h4&gt; &lt;p&gt;In my struct, I&amp;rsquo;d just specified the User.id as a string, Paul uses UUID - this makes no difference to the app as it stands, but is much better if we ever needed to add users.&lt;/p&gt;</description></item><item><title>Profile Photo Rabbit Hole</title><link>https://devendevour.iankulin.com/profile-photo-rabbit-hole/</link><pubDate>Sun, 13 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/profile-photo-rabbit-hole/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/down-the-rabbit-hole-childrens-book-illustration.jpg" alt="down the rabbit hole, children&amp;rsquo;s book illustration - stable diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m on &lt;a href="https://www.hackingwithswift.com/guide/ios-swiftui/5/3/challenge" target="_blank" rel="noopener"&gt;day 60 of #100Days&lt;/a&gt; , and have just wasted most of an evening&amp;rsquo;s coding time going down a rabit hole I didn&amp;rsquo;t need to. The app for this challenge is called &amp;ldquo;FriendFace&amp;rdquo; and is pretty straightforward: download a heap of JSON which is an array of users. Show it in a list that can be clicked through to see the details of that user.&lt;/p&gt;</description></item><item><title>Project 12 Feedback</title><link>https://devendevour.iankulin.com/project-12-feedback/</link><pubDate>Fri, 11 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/project-12-feedback/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/tataed.jpg" alt="adel and taylor swift with ed sheeran, watercolor painting - stable diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;As usual, I watch Paul&amp;rsquo;s solution video, and compare it to mine.&lt;/p&gt;
&lt;h4 id="task-1"&gt;Task 1&lt;/h4&gt; &lt;p&gt;This was passing in the predicate as a String. I passed the whole thing, but as I figured out along the way, Paul meant just the operator word. He also added some buttons to test it better, which I didn&amp;rsquo;t think of till Task 3 - it would have saved me some simulator runs.&lt;/p&gt;</description></item><item><title>You Can Take Big Steps When You Feel Safe</title><link>https://devendevour.iankulin.com/you-can-take-big-steps-when-you-feel-safe/</link><pubDate>Wed, 09 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/you-can-take-big-steps-when-you-feel-safe/</guid><description>&lt;p&gt;&lt;a href="https://www.deviantart.com/jhonair/art/Forest-of-giantess-604262747" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/forest-of-giantess-jhonair.png" alt="" title="Forest-of-giantess By JhonAir" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.hackingwithswift.com/100/swiftui/58" target="_blank" rel="noopener"&gt;Day 58&lt;/a&gt; of &lt;a href="https://www.hackingwithswift.com/100/swiftui" target="_blank" rel="noopener"&gt;#100Days&lt;/a&gt; feels like complex topics are being dropped in pretty fast. We tackle one:many data relationships and how to set them up in CoreData, using CoreData constraints and setting a merge policy to manage conflicts, and even the underscore to access the actual property inside a wrapped property struct (needed for dynamic filtering in a view).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve &lt;a href="https://devendevour.iankulin.com/top-four-reasons-why-twostraws-is-a-good-teacher/"&gt;mentioned before&lt;/a&gt; that I think Paul Hudson is an excellent teacher, and an example of this is that even though this was a day with a lot of challenging material, I&amp;rsquo;m not worried. I followed the discussion and tried the code, and more importantly I&amp;rsquo;m anticipating these new skills will be practiced in the next app, and probably shortly after I&amp;rsquo;ll be writing an app using them.&lt;/p&gt;</description></item><item><title>CoreData and the Preview</title><link>https://devendevour.iankulin.com/coredata-and-the-preview/</link><pubDate>Fri, 04 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/coredata-and-the-preview/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/looking-through-a-keyhole-to-a-room-diagram-colorful.jpg" alt="looking through a keyhole to a room, diagram, colorful - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve noticed Paul is inclined to ignore the preview and run his code in the simulator to check its operation. That&amp;rsquo;s valid, but it seems quicker, and reassuring, to see it in the preview as I type.&lt;/p&gt;
&lt;p&gt;This led to a small problem with &lt;a href="https://www.hackingwithswift.com/books/ios-swiftui/how-to-combine-core-data-and-swiftui" target="_blank" rel="noopener"&gt;Day 53&lt;/a&gt; that uses CoreData. When I added a student in the preview, it looked like this, and was immediately followed with a crash report.&lt;/p&gt;</description></item><item><title>Top Four Reasons why @TwoStraws is a Good Teacher</title><link>https://devendevour.iankulin.com/top-four-reasons-why-twostraws-is-a-good-teacher/</link><pubDate>Tue, 01 Nov 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/top-four-reasons-why-twostraws-is-a-good-teacher/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-10-29-at-1.28.59-pm.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;h4 id="good-questions"&gt;Good Questions&lt;/h4&gt; &lt;p&gt;At various points in the &lt;a href="https://www.hackingwithswift.com/100/swiftui" target="_blank" rel="noopener"&gt;100 Days of SwiftUI&lt;/a&gt; course, you get asked sets of questions to check you&amp;rsquo;ve understood the preceding material. They&amp;rsquo;re usually presented as two different statements, one of which is true, and the other false. It&amp;rsquo;s actually a really good technique - the student feels like they&amp;rsquo;ve got a couple of opportunities to figure it out, plus they are forced to read both statements and think about them. Paul does a similar thing in the Unwrapped app - there, the questions are often presented as &amp;ldquo;Is this valid Swift code&amp;rdquo; and the user needs to scan through it all looking for mistakes. It&amp;rsquo;s checking your understanding, and making you a thoughtful debugger!&lt;/p&gt;</description></item><item><title>Git - make all the commits into a single commit</title><link>https://devendevour.iankulin.com/git-make-all-the-commits-into-a-single-commit/</link><pubDate>Sat, 29 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/git-make-all-the-commits-into-a-single-commit/</guid><description>&lt;p&gt;When I&amp;rsquo;m following a tutorial app, I generally pause and type up the code as I go, and make local commits with appropriate messages. This is almost completely unnecessary, but it seems like a good habit and doesn&amp;rsquo;t cost me anything - I just tick the box for creating the git when I start the project, then it&amp;rsquo;s a couple of keystrokes (option-command-C) and I&amp;rsquo;m done.&lt;/p&gt;
&lt;p&gt;Most of the apps have a follow-along portion, then some challenges which involve minor changes to the app. When I get to the challenges I like to throw it up on Github - it&amp;rsquo;s conceivable it could help someone one day, or at the least, I&amp;rsquo;m helping to train &lt;a href="https://github.com/features/copilot" target="_blank" rel="noopener"&gt;Microsoft&amp;rsquo;s AI&lt;/a&gt; to write shitty beginner code in exchange for free git server access.&lt;/p&gt;</description></item><item><title>Day 47 - Habits App</title><link>https://devendevour.iankulin.com/day-47-habits-app/</link><pubDate>Thu, 27 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/day-47-habits-app/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/tgirl-3.jpg" alt="pretty! woman holding a bag of trash, Artstation - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been mucking around with the Habits app too long - it&amp;rsquo;s started to look like procrastination. It already meets the &lt;a href="https://www.hackingwithswift.com/100/swiftui/47" target="_blank" rel="noopener"&gt;specification&lt;/a&gt; , so I&amp;rsquo;m calling it an MVP and moving on.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/IanKulin/Habitual" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/github-mark-32px.png" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/img_3110.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;This is the first app of mine I&amp;rsquo;ve loaded onto my phone and started using, and there are a couple of things I&amp;rsquo;d like to do with it. It currently just lets you specify how many days between an activity repeating - so if you say you should go to the gym every second day, and you complete that activity on Monday, &amp;ldquo;Gym&amp;rdquo; will make it&amp;rsquo;s way to the top of the list on Wednesday. While it&amp;rsquo;s waiting in the list for Wednesday to come around, it will show the &amp;ldquo;Due&amp;rdquo; time as being exactly 48 hours after you last pressed &amp;ldquo;done&amp;rdquo; on it. But if the habit you want is to go to the gym after work at 6:00pm that&amp;rsquo;s when you want it to be due. I&amp;rsquo;d like that.&lt;/p&gt;</description></item><item><title>Updating stored JSON due to a struct change</title><link>https://devendevour.iankulin.com/updating-stored-json-due-to-a-struct-change/</link><pubDate>Tue, 25 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/updating-stored-json-due-to-a-struct-change/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/jason-modern-art.jpg" alt="Jason Modern Art - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I mentioned yesterday &amp;ldquo;&lt;em&gt;I could use a renamed old version of my struct to load the existing data, and convert it across to the new model.&lt;/em&gt;&amp;rdquo;. Since I&amp;rsquo;ve been testing the app on my phone, and using plausible data, it was going to be painful enough to lose it that I thought I should go through those steps.&lt;/p&gt;
&lt;p&gt;First, I make a copy of the old struct, and renamed it with the app version number that used it. No need to bring all the computed properties into this struct, just the bits that get encoded into the JSON.&lt;/p&gt;</description></item><item><title>List Apps</title><link>https://devendevour.iankulin.com/list-apps/</link><pubDate>Thu, 20 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/list-apps/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/girl-making-a-list-at-a-desk-graphic-novel.jpg" alt="girl making a list at a desk, graphic novel - Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;When I was first programming professionally, it wasn&amp;rsquo;t long before I noticed that there were patterns to the sort of bread-and-butter things I was writing most times - the majority of the small business applications I wrote tracked several entities; for each entity there needed to be add/edit/delete screens, there would be some business rules around those things, and some reports and search functionality.&lt;/p&gt;</description></item><item><title>When it Works</title><link>https://devendevour.iankulin.com/when-it-works/</link><pubDate>Mon, 17 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/when-it-works/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-10-15-at-10.43.18-am.jpg" alt="Screenshot of swiftui code and the iphone simulator with a roughly drawn face" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The little joy of something working. It&amp;rsquo;s one of the things that makes coding enjoyable. Like a good video game you have an overarching goal, but on the way you need to solve a large number of problems of variable complexity, and you get a little bit of dopamine for each one.&lt;/p&gt;
&lt;p&gt;I think in every language I&amp;rsquo;ve ever learned, as soon as I know how to draw something on the screen, I start to get the urge to create a simple drawing application. When I was starting on Visual C++ and the MFC (Microsoft Foundation Classes) the &lt;a href="https://www.amazon.com/Beginning-Visual-C-Ivor-Horton/dp/1861000081" target="_blank" rel="noopener"&gt;book&lt;/a&gt; I used to get started built a drawing application as an example. It hooks into the benefit of being able to quickly see the evidence you&amp;rsquo;ve achieved something.&lt;/p&gt;</description></item><item><title>Musings on Data</title><link>https://devendevour.iankulin.com/musings-on-data/</link><pubDate>Sun, 16 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/musings-on-data/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/thinking-about-data-drawing.jpg" alt="Thinking about data - drawing. Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been feeling my enthusiasm for the online courses I started waning a little, additionally, I have enough progress under my belt that I could actually start working on some of the projects in my &amp;ldquo;App Ideas&amp;rdquo; notebook. I&amp;rsquo;m not sure if starting on them is a smart idea, or just a way of procrastinating. One thing most of those apps have in common, and that I haven&amp;rsquo;t substantively learned yet is persisting data. Their data requirements vary from a sort of specialised todo list only required on that device, to relational data that needs to be live synced across devices including macOS and needs to support rolling back transactions to resolve conflicts.&lt;/p&gt;</description></item><item><title>Using AI to Generate Icons</title><link>https://devendevour.iankulin.com/using-ai-to-generate-icons/</link><pubDate>Tue, 11 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/using-ai-to-generate-icons/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/macos-icon-scissors-floating-over-code2.jpg" alt="Open macbook with design image showing - created by Stable Diffusion" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Since I have minimal design skills, I went back to &lt;a href="https://www.fiverr.com/" target="_blank" rel="noopener"&gt;Fiverr&lt;/a&gt; (the digital gig economy platform) to get some icons done for CodeTrimmer - explaining that I wanted something like a &amp;ldquo;pair of scissors floating over some computer code&amp;rdquo;. At the same time I&amp;rsquo;ve been playing with &lt;a href="https://github.com/divamgupta/diffusionbee-stable-diffusion-ui" target="_blank" rel="noopener"&gt;DiffusionBee&lt;/a&gt; - a free Apple silicon version of the &lt;a href="https://stability.ai/blog/stable-diffusion-public-release" target="_blank" rel="noopener"&gt;Stable Diffusion&lt;/a&gt; artifical intellligence that generates images from text prompts. The image above was created on an M1 Macbook using DiffusionBee.&lt;/p&gt;</description></item><item><title>Color Picker (website)</title><link>https://devendevour.iankulin.com/color-picker-website/</link><pubDate>Tue, 04 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/color-picker-website/</guid><description>&lt;p&gt;I&amp;rsquo;ve started work on trying to recreate a &lt;a href="https://devendevour.iankulin.com/design-help/"&gt;UI provided by a designer&lt;/a&gt; , and in the process needed to identify some colours from a PNG image. I found this great website for this exact purpose.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-09-30-at-4.36.17-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The site is ImageColorPicker. To use it, you &amp;ldquo;upload&amp;rdquo; your image (actually the image is not going anywhere - it&amp;rsquo;s all done in-browser). Then click on any area you want to identify the colour of.&lt;/p&gt;</description></item><item><title>Design Help</title><link>https://devendevour.iankulin.com/design-help/</link><pubDate>Mon, 03 Oct 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/design-help/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-09-29-at-5.50.43-pm-1.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I think I mentioned when I&amp;rsquo;d completed the &lt;a href="https://devendevour.iankulin.com/times-tables-day-35-challenge/"&gt;TimesTable app&lt;/a&gt; , that I was not happy with the design. It&amp;rsquo;s ugly, I don&amp;rsquo;t like the way the feedback about a wrong answer is shown at the same time as the next question, the number of questions setting would be rarely changed and looks uncomfortable where it is, I&amp;rsquo;m not sure the purpose of the picker for which times table would be clear, and it&amp;rsquo;s not appealing to children.&lt;/p&gt;</description></item><item><title>Calculator</title><link>https://devendevour.iankulin.com/calculator/</link><pubDate>Thu, 29 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/calculator/</guid><description>&lt;p&gt;The app I&amp;rsquo;m working on currently (for multiplication tables practice) has a number type keypad and display a bit like a calculator - but for entering the answers. It&amp;rsquo;s been quite fun to think through all the little problems to make it work how you&amp;rsquo;d expect, so I was quite interested to watch an iOS Academy video where Afraz Siddiqui builds a partially finished SwiftUI version of the iOS Calculator app.&lt;/p&gt;</description></item><item><title>Gitting up to date</title><link>https://devendevour.iankulin.com/gitting-up-to-date/</link><pubDate>Tue, 27 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/gitting-up-to-date/</guid><description>&lt;p&gt;I&amp;rsquo;ve started the habit of branching my code for each feature or batches of features. This is not really needed, I&amp;rsquo;ve developing solo, and the code on &lt;code&gt;main&lt;/code&gt; is not in production. I could just go on committing, but part of my process is about becoming competent with git.&lt;/p&gt;
&lt;p&gt;There are a couple of git commands (&lt;code&gt;merge&lt;/code&gt; and &lt;code&gt;rebase&lt;/code&gt;) that mush code between branches together in different ways. The video below (from &lt;a href="https://www.udemy.com/user/manuel-lorenz/" target="_blank" rel="noopener"&gt;Manuel Lorenz&lt;/a&gt; at &lt;a href="https://academind.com/" target="_blank" rel="noopener"&gt;Academind&lt;/a&gt; ) is a particularly clear look at these two commands.&lt;/p&gt;</description></item><item><title>iOS Academy</title><link>https://devendevour.iankulin.com/ios-academy-2/</link><pubDate>Mon, 26 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/ios-academy-2/</guid><description>&lt;p&gt;A YouTube channel worth subscribing to is &lt;a href="https://www.linkedin.com/in/afrazsiddiqui" target="_blank" rel="noopener"&gt;Afraz Siddiqui&amp;rsquo;s&lt;/a&gt; &lt;a href="https://www.youtube.com/c/iOSAcademy/videos" target="_blank" rel="noopener"&gt;iOS Academy&lt;/a&gt; . He does a great videos on iOS development. My favouriets might be the shorter focussed ones, like this one on the new SwiftUI chart views.&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/KVz_I10R-wA?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>Animation Feedback</title><link>https://devendevour.iankulin.com/animation-feedback/</link><pubDate>Sat, 24 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/animation-feedback/</guid><description>&lt;p&gt;I had a look at Paul&amp;rsquo;s version of the challenge to animate the Guess The Flags app, and like me he&amp;rsquo;d hit on altering the &lt;em&gt;amount&lt;/em&gt; of each animation depending on if it was the clicked on flag, but he&amp;rsquo;d done it with a lot less code - using the ternary operator in each of the modifiers - versus my approach of filling in an Int array for each of the effects and altering them depending on the user selection.&lt;/p&gt;</description></item><item><title>Gists for embedding code</title><link>https://devendevour.iankulin.com/gists-for-embedding-code/</link><pubDate>Fri, 23 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/gists-for-embedding-code/</guid><description>&lt;p&gt;So, I might have found a slightly better method for sharing code in posts that I complained about the &lt;a href="https://devendevour.iankulin.com/wordpress-code-blocks/"&gt;other day&lt;/a&gt; . GitHub has a thing called &lt;a href="https://gist.github.com/" target="_blank" rel="noopener"&gt;Gists&lt;/a&gt; . It&amp;rsquo;s like a tiny repository you can paste a code snippet into (or upload a source file). Once that&amp;rsquo;s done, you can just paste the URL of the Gist into &lt;a href="https://wordpress.com/support/gist/" target="_blank" rel="noopener"&gt;Wordpress&lt;/a&gt; - it recognises it and does this:&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-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ForEach(&lt;span style="color:#ae81ff"&gt;0.&lt;/span&gt;.&amp;lt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) { number &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Button {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// flag was tapped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; flagTapped(number)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } label: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FlagView(flagOf: countries[number])
&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; .rotation3DEffect(.degrees(flagSpinAmount[number]),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; axis: (x: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, y: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, z: &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; .opacity(flagOpacity[number])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .scaleEffect(flagScale[number])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .animation(.&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;, value: flagSpinAmount)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I came across this being used on a &lt;a href="https://blog.rosay.io/create-a-camera-app-with-swiftui-60876fcb9118" target="_blank" rel="noopener"&gt;blog post&lt;/a&gt; (about using the camera in apps) from &lt;a href="https://rosay.io/" target="_blank" rel="noopener"&gt;Gaspard Rosay&lt;/a&gt; .&lt;/p&gt;</description></item><item><title>Wordpress Code Blocks</title><link>https://devendevour.iankulin.com/wordpress-code-blocks/</link><pubDate>Wed, 21 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/wordpress-code-blocks/</guid><description>&lt;p&gt;Non-iOS post warning :- )&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not really happy with the way I&amp;rsquo;m sharing code in these posts. I started off with the regular Wordpress code blocks:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; func isPossible(word: String) -&amp;gt; Bool {
 var tempWord = rootWord
 for letter in word {
 if let pos = tempWord.firstIndex(of: letter) {
 tempWord.remove(at: pos)
 } else {
 return false
 }
 }
 return true
 }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These seem a bit large to me, but it comes with a font size choice, which I like setting to &amp;ldquo;Tiny&amp;rdquo;:&lt;/p&gt;</description></item><item><title>How to upgrade XCode and Swift</title><link>https://devendevour.iankulin.com/how-to-upgrade-xcode-and-swift/</link><pubDate>Sun, 18 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/how-to-upgrade-xcode-and-swift/</guid><description>&lt;p&gt;With the September release of XCode 14 and Swift 5.7 it was time for my first update - I looked in &amp;ldquo;About&amp;rdquo; for an update link but there wasn&amp;rsquo;t one - so if you&amp;rsquo;re as dense as me, the tip is to head to the &lt;a href="https://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=2ahUKEwjN8OGn85r6AhXlWHwKHf85DzAQFnoECBUQAQ&amp;amp;url=https%3A%2F%2Fapps.apple.com%2Fus%2Fapp%2Fxcode%2Fid497799835%3Fmt%3D12&amp;amp;usg=AOvVaw2fEvMbfRtGhB4SPHYB54NX" target="_blank" rel="noopener"&gt;Mac App Store&lt;/a&gt; and have a look at the Updates page.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-09-17-at-8.53.34-am.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Your current XCode version can, of course be found in the &lt;em&gt;XCode | About&lt;/em&gt; dialogue. Mine was on 13.4.1. There&amp;rsquo;s a couple of ways of finding the Swift version - If you&amp;rsquo;ve got an XCode project open, click on the .xcodeproj in the explorer,and have a look in &lt;em&gt;Build Settings&lt;/em&gt; for &lt;em&gt;Swift Compiler - Language&lt;/em&gt; for the major version.&lt;/p&gt;</description></item><item><title>How to download a file from GitHub</title><link>https://devendevour.iankulin.com/how-to-download-a-file-from-github/</link><pubDate>Sat, 17 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/how-to-download-a-file-from-github/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-09-13-at-9.12.31-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A quick tip - since it was not immediately obvious to me. If you need to download a file from GitHub (as opposed to cloning it etc), look for the &amp;ldquo;Raw&amp;rdquo; button - that&amp;rsquo;s a link to the file, then right click and do whatever your browser needs to download a web resource.&lt;/p&gt;</description></item><item><title>Project 4 Challenges</title><link>https://devendevour.iankulin.com/project-4-challenges/</link><pubDate>Fri, 16 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/project-4-challenges/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-09-13-at-7.22.43-pm.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve completed the Project 4 challenges (source) of the 100 Days of SwiftUI, no biggie - the increase in difficulty between each step of Paul&amp;rsquo;s bootcamp is small enough that it&amp;rsquo;s never too stressful, but large enough you feel like you&amp;rsquo;re progressing all the time.&lt;/p&gt;
&lt;p&gt;Since I&amp;rsquo;ve paid to be a member of Hacking with Swift, one of the perks is to see Paul&amp;rsquo;s video solutions. I&amp;rsquo;ve not worries about it before, but I should - looking at them and comparing to my efforts is probably good feedback. So here&amp;rsquo;s the differences in our answers to the challenges.&lt;/p&gt;</description></item><item><title>Machine Learning</title><link>https://devendevour.iankulin.com/machine-learning/</link><pubDate>Thu, 15 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/machine-learning/</guid><description>&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/coreml" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/rendered2x-1638462885.png" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;A few years ago when I still used a Tom-Tom for car navigation, I was a little freaked out when it started offering suggestions on where to go to when I started the car - guessing, usually correctly, where I wanted to go. Like - how did it know I was leaving school for band practice two towns over?&lt;/p&gt;
&lt;p&gt;Clearly, is must have been collecting data on times/days and departure locations to learn some of my habits. It felt quite invasive, but I thought it must have been on-device since I had the wifi turned off in the unit.&lt;/p&gt;</description></item><item><title>Before SwiftUI</title><link>https://devendevour.iankulin.com/before-swiftui/</link><pubDate>Wed, 14 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/before-swiftui/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-09-10-at-9.28.24-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m on Day 26 of 100 Days, and didn&amp;rsquo;t grok the dates on my first read through, so I&amp;rsquo;ve read a couple of other explanations and sat down with a coffee and thought I&amp;rsquo;d see what YouTube had for me on the subject. I seen a few great &lt;a href="https://www.youtube.com/c/iOSAcademy/videos" target="_blank" rel="noopener"&gt;iOS Academy&lt;/a&gt; videos, so &lt;a href="https://www.youtube.com/watch?v=HSFTzcYzuEQ" target="_blank" rel="noopener"&gt;this one&lt;/a&gt; seemed like a good choice.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t seen enough to say if it is a good or great explanation of dates, calendars and date components in Swift yet, but man, getting to the stage of writing useful code when using storyboards and UIKit takes a while! It&amp;rsquo;s literally 3:42 in to the video before there&amp;rsquo;s enough infrastructure done for &amp;ldquo;hello world&amp;rdquo;.&lt;/p&gt;</description></item><item><title>Rock, Paper Scissors (2)</title><link>https://devendevour.iankulin.com/rock-paper-scissors-2/</link><pubDate>Tue, 13 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/rock-paper-scissors-2/</guid><description>&lt;p&gt;When I was forced by a deadline into delivering this project, I noted in its &lt;a href="https://devendevour.iankulin.com/rock-paper-scissors-1/"&gt;post&lt;/a&gt; that there was a number of improvements to make:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;The rock paper scissors could be some better data structure than an array and some ints.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;I don’t love the try to win, try to lose aspect, but the client specified it&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Having the didUserWin and didComputerWin funcs is a cop out – that should probably be a single function returning a win/lose/draw type&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;I also am unhappy with nesting them in the view namespace to use my #consts&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;duplicating the last part of the view but making the elements .hidden() to keep the same spacing seems like a kludge&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;when I added the link to the Hacking With SwiftUI page with the app brief just now, I noticed I haven’t done the scoring the way it was asked for&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s the progress&lt;/p&gt;</description></item><item><title>Swift enums</title><link>https://devendevour.iankulin.com/swift-enums/</link><pubDate>Mon, 12 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/swift-enums/</guid><description>&lt;p&gt;I&amp;rsquo;ve started on the refactoring for &lt;a href="https://devendevour.iankulin.com/rock-paper-scissors-1/"&gt;Rock, paper, scissors&lt;/a&gt; . One of the things I didn&amp;rsquo;t like was using Ints to signal which shape (I&amp;rsquo;m calling the rock, or paper, or scissors hand shape a &lt;em&gt;shape&lt;/em&gt;) was being handed around. The Int I was using was also the index into an array of the emoji&amp;rsquo;s - so if I did an off-by-one I was risking an out of bounds on the array.&lt;/p&gt;</description></item><item><title>.git stuffed</title><link>https://devendevour.iankulin.com/git-stuffed/</link><pubDate>Sun, 11 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/git-stuffed/</guid><description>&lt;p&gt;I&amp;rsquo;m in a bit of a swing with my git process. I usually develop locally committing as needed, then when I reach some sort of first milestone, create an empty repo on GitHub the push up to it by:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;git remote add origin git@github.com:IanKulin/RockPaper.git
git branch -M main
git push -u origin main
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;or, I start on GitHub, create a new repo with a readme.md in it, and then use the -f (force) flag when I push to it and override the contents. I think forgetting about this might have been the source of tonight&amp;rsquo;s problems with &amp;ldquo;unrelated histories&amp;rdquo;.&lt;/p&gt;</description></item><item><title>Rock, Paper, Scissors (1)</title><link>https://devendevour.iankulin.com/rock-paper-scissors-1/</link><pubDate>Sat, 10 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/rock-paper-scissors-1/</guid><description>&lt;p&gt;As I mentioned yesterday, I needed to make some progress to blog about, and I had a half working version of a Rock, Paper, Scissors for &lt;a href="https://www.hackingwithswift.com/100/swiftui/25" target="_blank" rel="noopener"&gt;Day 25&lt;/a&gt; so I pushed myself to get that working.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s lots in the code below I don&amp;rsquo;t love.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The rock paper scissors could be some better data structure than an array and some ints.&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t love the try to win, try to lose aspect, but the client specified it&lt;/li&gt;
&lt;li&gt;Having the didUserWin and didComputerWin funcs is a cop out - that should probably be a single function returning a win/lose/draw type&lt;/li&gt;
&lt;li&gt;I also am unhappy with nesting them in the view namespace to use my #consts&lt;/li&gt;
&lt;li&gt;duplicating the last part of the view but making the elements .hidden() to keep the same spacing seems like a kludge&lt;/li&gt;
&lt;li&gt;when I added the link to the Hacking With SwiftUI page with the app brief just now, I noticed I haven&amp;rsquo;t done the scoring the way it was asked for&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://github.com/IanKulin/RockPaper/commit/b1497cccf2dc8af953b946458af797dc5ad12dc9?diff=unified#diff-223dd39ecc4f631b084c99b065a71ea40dc2deba8e36e7f5f939802e60c80186" target="_blank" rel="noopener"&gt;source on github&lt;/a&gt; &lt;/p&gt;</description></item><item><title>A deadline is a good thing</title><link>https://devendevour.iankulin.com/a-deadline-is-a-good-thing/</link><pubDate>Fri, 09 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/a-deadline-is-a-good-thing/</guid><description>&lt;p&gt;I usually have a few days of blog posts written in advance so I can schedule one to come out each day, and not sweat if I&amp;rsquo;m caught up in real life. There&amp;rsquo;s no real reason why I should have that strict publishing schedule, but it is part of my internal discipline to ensure that, at least on average I&amp;rsquo;m making some sort of report-able progress or effort each day.&lt;/p&gt;</description></item><item><title>Learn to Code</title><link>https://devendevour.iankulin.com/learn-to-code/</link><pubDate>Thu, 08 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/learn-to-code/</guid><description>&lt;p&gt;This blog exists for a couple of reasons - firstly Paul Hudson insisted on posting progress in the 100 days of SwiftUI on social media, and secondly, when I try to explain something, I&amp;rsquo;m forced to understand it clearly - so I know this is a good learning technique.&lt;/p&gt;
&lt;p&gt;This video from &lt;a href="https://fireship.io/" target="_blank" rel="noopener"&gt;Fireship&lt;/a&gt; says this idea is called the &lt;a href="https://www.lifehack.org/862931/feynman-technique" target="_blank" rel="noopener"&gt;Feynman Technique&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/NtfbWkxJTHw?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>.self in ForEach</title><link>https://devendevour.iankulin.com/self-in-foreach/</link><pubDate>Wed, 07 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/self-in-foreach/</guid><description>&lt;p&gt;I&amp;rsquo;m on Day 25 of Hacking With SwiftUI, and &lt;a href="https://www.hackingwithswift.com/guide/ios-swiftui/2/2/key-points" target="_blank" rel="noopener"&gt;Paul is making a point&lt;/a&gt; about how SwiftUI can loop over an array to build a view. He starts with this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;let agents = [&amp;#34;Cyril&amp;#34;, &amp;#34;Lana&amp;#34;, &amp;#34;Pam&amp;#34;, &amp;#34;Sterling&amp;#34;]
VStack {
 ForEach(0..&amp;lt;agents.count) {
 Text(agents[$0])
 }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But then proposes an alternative:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;let agents = [&amp;#34;Cyril&amp;#34;, &amp;#34;Lana&amp;#34;, &amp;#34;Pam&amp;#34;, &amp;#34;Sterling&amp;#34;]
VStack {
 ForEach(agents, id: \.self) {
 Text($0)
 }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;He explains the use of \.self here by saying&lt;/p&gt;</description></item><item><title>I git it*</title><link>https://devendevour.iankulin.com/i-git-it/</link><pubDate>Tue, 06 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/i-git-it/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/6y8jpj5f4el91.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;This meme&amp;rsquo;s been trending in the &lt;a href="https://old.reddit.com/r/ProgrammerHumor/comments/x3udcz/is_it_really_that_much_easy_because_in_the/" target="_blank" rel="noopener"&gt;r/ProgrammerHumor subreddit&lt;/a&gt; , and although &amp;ldquo;to do literally anything&amp;rdquo; is a stretch, my git / github workflow is pretty routine now using the &lt;a href="https://xkcd.com/1597/" target="_blank" rel="noopener"&gt;relevant xkcd&lt;/a&gt; method, but actually with quite a bit of understanding from the first half of the excellent &lt;a href="https://git-scm.com/book/en/v2" target="_blank" rel="noopener"&gt;Pro Git book&lt;/a&gt; . I highly recommend it.&lt;/p&gt;
&lt;p&gt;I had in my &lt;a href="https://devendevour.wordpress.com/goals/" target="_blank" rel="noopener"&gt;goals&lt;/a&gt; to set up XCode for push (I think I probably just need to generate a token on GitHub and save it in xcode), so I will do that for completion, but I&amp;rsquo;m also enjoying my &lt;a href="https://devendevour.iankulin.com/oh-my-zsh/"&gt;pimped out terminal&lt;/a&gt; so I&amp;rsquo;m pretty much a git cli guy now.&lt;/p&gt;</description></item><item><title>Project 3</title><link>https://devendevour.iankulin.com/project-3/</link><pubDate>Mon, 05 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/project-3/</guid><description>&lt;p&gt;This one&amp;rsquo;s not really a project, just a couple of little updates to earlier work, and a code snippet.&lt;/p&gt;
&lt;h4 id="challenge-1"&gt;Challenge 1&lt;/h4&gt; &lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Go back to project 1 and use a conditional modifier to change the total amount text view to red if the user selects a 0% tip.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first one is pretty simple - a ternary condition to make the total red if the tip is set to zero.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-09-02-at-5.10.56-pm.png" alt="" class="img-responsive"&gt; &lt;/p&gt;</description></item><item><title>Sean != Erica</title><link>https://devendevour.iankulin.com/sean-erica/</link><pubDate>Sun, 04 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/sean-erica/</guid><description>&lt;p&gt;When Swift was newer, there was a bunch of podcasts about it - in early episodes of &lt;a href="https://podcasts.apple.com/au/podcast/fireside-swift/id1269435221" target="_blank" rel="noopener"&gt;Fireside Swift&lt;/a&gt; the existence of a Swift Podcast Network is often mentioned, but now it&amp;rsquo;s more of an established language there&amp;rsquo;s a bit less current content to listen to, and what there is, is less focused on learning Swift and more about what&amp;rsquo;s happening in the community.&lt;/p&gt;
&lt;p&gt;Being firmly in the camp of needing to learn more about the language, I&amp;rsquo;ve listen to a number of older podcasts, or even current ones (such as Fireside) but their older episodes. It is sort of an odd experience traveling on several slightly out of sync timelines, but quite a joy to see what happens to predictions - like the occasion when &lt;a href="https://twitter.com/twostraws" target="_blank" rel="noopener"&gt;Paul Hudson&lt;/a&gt; predicts that an &amp;ldquo;Xcode lite&amp;rdquo; on iPad is unlikely to be able to write apps until a more swift like framework for developing interfaces exists.&lt;/p&gt;</description></item><item><title>Day 23 - Views and Modifiers - Part 4</title><link>https://devendevour.iankulin.com/day-23-views-and-modifiers-part-4/</link><pubDate>Sat, 03 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/day-23-views-and-modifiers-part-4/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/psm_v10_d562_the_hindoo_earth-3.jpg" alt="This image has an empty alt attribute; its file name is psm_v10_d562_the_hindoo_earth-3.jpg" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Then the last trick for for decomposing the views, is to remember we can pass values when we init a struct. So something like this:&lt;/p&gt;
&lt;p&gt;struct ContentView: View {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var body: some View {
 VStack{
 GreenPaddedText(text: &amp;quot;Hello&amp;quot;)
 GreenPaddedText(text: &amp;quot;world&amp;quot;)
 }
}


struct GreenPaddedText: View {
 var text: String

 var body: some View {
 Text(text)
 .foregroundColor(.green)
 .padding()
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;</description></item><item><title>Day 23 - Views and Modifiers - Part 3</title><link>https://devendevour.iankulin.com/day-23-views-and-modifiers-part-3/</link><pubDate>Fri, 02 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/day-23-views-and-modifiers-part-3/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/psm_v10_d562_the_hindoo_earth-3.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The next part of day 23 started to make my brain hurt a bit. It&amp;rsquo;s easy to imagine that when presenting a complex screen - perhaps some data from a source as a mixture of images and text loaded from a database into a scroll-able view, that the view may start to get complex. Then it becomes good practice to decompose the views to make the code clearer, less error prone, and to avoid any unnecessary repetition.&lt;/p&gt;</description></item><item><title>Day 23 - Views and Modifiers - Part 2</title><link>https://devendevour.iankulin.com/day-23-views-and-modifiers-part-2/</link><pubDate>Thu, 01 Sep 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/day-23-views-and-modifiers-part-2/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/psm_v10_d562_the_hindoo_earth-2.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Although &amp;ldquo;immutable&amp;rdquo; the view structs can contain some control statements such as if/then and for loops. So this is quite legal, and useful.&lt;/p&gt;
&lt;p&gt;struct ContentView: View {
@State private var likesGreen = true&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var body: some View {
 if likesGreen {
 Text(&amp;quot;Hello World&amp;quot;)
 .background(.green)
 }
 else
 {
 Text(&amp;quot;Hello World&amp;quot;)
 .background(.blue)
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;But Paul cautions against this, saying:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.hackingwithswift.com/books/ios-swiftui/conditional-modifiers" target="_blank" rel="noopener"&gt;You can often use regular if conditions to return different views based on some state, but this actually creates more work for SwiftUI – rather than seeing one Button being used with different colors, it now sees two different Button views, and when we flip the Boolean condition it will destroy one to create the other rather than just recolor what it has.&lt;/a&gt; &lt;/p&gt;</description></item><item><title>Day 23 - Views and Modifiers - Part 1</title><link>https://devendevour.iankulin.com/day-23-views-and-modifiers-part-1/</link><pubDate>Wed, 31 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/day-23-views-and-modifiers-part-1/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/psm_v10_d562_the_hindoo_earth-1.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I found this one of the trickier days, so I&amp;rsquo;ll write it out to clear up my thinking.&lt;/p&gt;
&lt;p&gt;To draw to to screen in SwiftUI, we don&amp;rsquo;t call a command to draw on a canvas or window. Rather, a &lt;em&gt;view&lt;/em&gt; is defined as an immutable struct of type some View. Here&amp;rsquo;s the simple one from the default Xcode project.&lt;/p&gt;
&lt;p&gt;struct ContentView: View {
var body: some View {
Text(&amp;ldquo;Hello, world!&amp;rdquo;)
.padding()
}
}&lt;/p&gt;</description></item><item><title>Project 2 - Guess the Flag</title><link>https://devendevour.iankulin.com/project-2-guess-the-flag/</link><pubDate>Wed, 31 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/project-2-guess-the-flag/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-08-23-at-8.26.59-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Another 100 Days project - the second tutorial one. This was once again a &amp;ldquo;V&amp;rdquo; design pattern (put everything in the view) and as I kept growing it, especially in the challenges, I had a growing sense of unease.&lt;/p&gt;
&lt;p&gt;New things for me was how image assets work - identifying them with strings is convenient, but I&amp;rsquo;m hoping there&amp;rsquo;s safer system later using enums or something to avoid runtime surprises. Also the alert dialog box system. I was wondering how this was going to work in a declarative framework. I do not really approve of modal dialogs in mobile UI&amp;rsquo;s but I guess they have their place. I appreciated the gradients and frosted glass effects -super simple to implement, and if done thoughtfully, pretty.&lt;/p&gt;</description></item><item><title>Download a Directory from a GitHub Repo</title><link>https://devendevour.iankulin.com/download-a-directory-from-a-github-repo/</link><pubDate>Tue, 30 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/download-a-directory-from-a-github-repo/</guid><description>&lt;p&gt;For &lt;a href="https://www.hackingwithswift.com/books/ios-swiftui/guess-the-flag-introduction" target="_blank" rel="noopener"&gt;Challenge 2&lt;/a&gt; in the 100 days, I needed to download a directory of flag images from Paul&amp;rsquo;s GitHub. He has all the projects as sub-directories of a single &amp;ldquo;Hacking With Swift&amp;rdquo; repo. I didn&amp;rsquo;t need to whole thing, just the directory with the images.&lt;/p&gt;
&lt;p&gt;Strangely, git does not have any simple way of doing this. Neither does GitHub - I assumed the web interface would have a &amp;ldquo;download as zip&amp;rdquo; option as it does for tags.&lt;/p&gt;</description></item><item><title>Challenge 1</title><link>https://devendevour.iankulin.com/challenge-1/</link><pubDate>Mon, 29 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/challenge-1/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-08-22-at-8.54.26-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m up to Challenge 1 of 100 Days of SwiftUI (&lt;a href="https://www.hackingwithswift.com/100/swiftui/19" target="_blank" rel="noopener"&gt;Day 19&lt;/a&gt; ) which is to make your own simple (no MVVM) version of the app built in the previous three days. It&amp;rsquo;s about as simple as can be whilst still feeling like a real app. Something I hadn&amp;rsquo;t done before was limiting the keyboard to numbers or adding a toolbar to close it, so that was nice.&lt;/p&gt;
&lt;p&gt;Something that&amp;rsquo;s not nice, is that when you touch into the text field to change the number, it&amp;rsquo;s not selected ready to type over (the way they always are in browser url fields) so you need to backspace over the previous entry. That&amp;rsquo;s the sort of anoying behaviour I don&amp;rsquo;t like. It seems (after some googling) there&amp;rsquo;s no straightforward way of addressing this in SwiftUI, with the best solution involving importing a package. I will come back to that because it is bugging me.&lt;/p&gt;</description></item><item><title>$==Commitment</title><link>https://devendevour.iankulin.com/commitment/</link><pubDate>Sun, 28 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/commitment/</guid><description>&lt;p&gt;&lt;a href="https://www.hackingwithswift.com/100/swiftui" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-08-21-at-9.47.54-am.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Paul Hudson&amp;rsquo;s 100 Days of Swift UI course is free - the videos are on YouTube, all the reading and tasks are available on his website for free. Although I assumed he made his living from the prodigious number of Swift books he&amp;rsquo;s written, he doesn&amp;rsquo;t push them in the course (except for his free book &lt;a href="https://www.hackingwithswift.com/quick-start/swiftui" target="_blank" rel="noopener"&gt;Swift UI by Example&lt;/a&gt; ).&lt;/p&gt;
&lt;p&gt;He&amp;rsquo;s so unpushy, I didn&amp;rsquo;t realise till a few days ago that you could pay to become a &lt;a href="https://www.hackingwithswift.com/plus" target="_blank" rel="noopener"&gt;&amp;ldquo;subscriber&amp;rdquo; to Hacking with Swift&lt;/a&gt; . Really, he&amp;rsquo;s too nice.&lt;/p&gt;</description></item><item><title>Int.times()</title><link>https://devendevour.iankulin.com/int-times/</link><pubDate>Sat, 27 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/int-times/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/shockwave_coaster_sfot.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;When writing &lt;a href="https://devendevour.iankulin.com/the-_-underscore/"&gt;yesterday&amp;rsquo;s post&lt;/a&gt; about iterating through a range or collection and using the underscore to throw away the item, I had in the back of my mind that there should be a more straightforward way of doing something a number of times.&lt;/p&gt;
&lt;p&gt;Just to re-iterate (lol), here&amp;rsquo;s the issue. If we want to print &amp;ldquo;Here&amp;rsquo;s the thing&amp;rdquo; three times, in Swift the simplest we can do is:&lt;/p&gt;
&lt;p&gt;for _ in 1&amp;hellip;3 {
print(&amp;ldquo;Here&amp;rsquo;s the thing&amp;rdquo;)
}&lt;/p&gt;</description></item><item><title>The _ Underscore</title><link>https://devendevour.iankulin.com/the-_-underscore/</link><pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/the-_-underscore/</guid><description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/The_Undertaker" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/undertaker_with_fire.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve learned (so far) an underscore can be used for a couple of things in Swift, both of them loosely translating to &amp;ldquo;doesn&amp;rsquo;t really matter&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The first is in a parameter name for a function. Swift has a very cool feature I haven&amp;rsquo;t seen before where an argument can have a different internal and external name. As usual, this will make more sense in code. Imagine this:&lt;/p&gt;
&lt;p&gt;func sumNumbers(firstNumber: Int, secondNumber: Int) -&amp;gt; Int {
return firstNumber + secondNumber
}&lt;/p&gt;</description></item><item><title>Uwrap App</title><link>https://devendevour.iankulin.com/uwrap-app/</link><pubDate>Thu, 25 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/uwrap-app/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/img_2549.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Part of the &lt;a href="https://twitter.com/twostraws" target="_blank" rel="noopener"&gt;@twostraws&lt;/a&gt; programmatic universe is his Swift learning app, &lt;a href="https://apps.apple.com/us/app/unwrap/id1440611372" target="_blank" rel="noopener"&gt;Unwrap&lt;/a&gt; that I&amp;rsquo;ve included in my learning &lt;a href="https://devendevour.wordpress.com/goals/" target="_blank" rel="noopener"&gt;goals&lt;/a&gt; . It presents little snippets of learning with a 60 second video, and in a written version, then tests the user to check their understanding. It is slightly gamified - you get points for answers, but it&amp;rsquo;s not clear to me how that works beyond the satisfying haptics when your score runs up at the end of a section.&lt;/p&gt;</description></item><item><title>Codewars / reduce</title><link>https://devendevour.iankulin.com/codewars-reduce/</link><pubDate>Wed, 24 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/codewars-reduce/</guid><description>&lt;p&gt;&lt;a href="https://www.codewars.com/" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/1_0plbhkaulwnsx4u2mqyn2w.png" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.codewars.com/" target="_blank" rel="noopener"&gt;codewars.com&lt;/a&gt; is a &amp;ldquo;coding practice&amp;rdquo; website. You chose a language and a skill level, then it offers up a task (or &lt;em&gt;kata&lt;/em&gt;) for you to write a suitable function. The first one it gave me was seemed too hard, so I changed my level to beginner and skipped to the next one. This was my task:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; Given an array of integers, find the one that appears an odd number of times.
 
 There will always be only one integer that appears an odd number of times.
 
 Examples
 [7] should return 7, because it occurs 1 time (which is odd).
 [0] should return 0, because it occurs 1 time (which is odd).
 [1,1,2] should return 2, because it occurs 1 time (which is odd).
 [0,1,0,1,0] should return 0, because it occurs 3 times (which is odd).
 [1,2,2,3,3,3,4,3,3,3,2,2,1] should return 4, because it appears 1 time (which is odd).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I know there&amp;rsquo;s a cool &amp;ldquo;Set&amp;rdquo; container type in Swift, so my plan was to iterate through the array, then for each number if there&amp;rsquo;s no entry in the set, then add one, but if there is, remove it. That way whatever is left in the set at the end must be in the original array an odd number of times. I was pretty pleased with myself. Here&amp;rsquo;s the code I Playground&amp;rsquo;d up:&lt;/p&gt;</description></item><item><title>Sometimes the Gold is in the Comments</title><link>https://devendevour.iankulin.com/sometimes-the-gold-is-in-the-comments/</link><pubDate>Tue, 23 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/sometimes-the-gold-is-in-the-comments/</guid><description>&lt;p&gt;I&amp;rsquo;m still not 100% clear on @ObservedObject v @StateObject. So when YouTube offered up this video, in which Paul promises during the intro that I&amp;rsquo;ll understand the data bindings by the end, I thought it would be the video for me.&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/stSB04C4iS4?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;I guess I should really have twigged that I&amp;rsquo;d never heard of @ObjectBinding, but I pushed on to the 12 minute mark when he imports the &lt;em&gt;Combine&lt;/em&gt; framework. Hang on, what&amp;rsquo;s that?&lt;/p&gt;</description></item><item><title>Playgrounds are good</title><link>https://devendevour.iankulin.com/playgrounds-are-good/</link><pubDate>Mon, 22 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/playgrounds-are-good/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/img_2778.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A couple of times (&lt;a href="https://devendevour.iankulin.com/protocols/"&gt;Protocols&lt;/a&gt; &amp;amp; &lt;a href="https://devendevour.iankulin.com/named-loops/"&gt;Named Loops&lt;/a&gt; ) in the past few days I&amp;rsquo;ve needed to write and run a couple of tiny C or C++ snippets, and I&amp;rsquo;ve acutely felt the lack of Swift Playgrounds for it. It occurred to me that Playgrounds has been instrumental in my enjoyment of learning Swift - it&amp;rsquo;s just a bit magic to grab the closest device and noodle out an idea or to make sure I&amp;rsquo;ve understood a new concept.&lt;/p&gt;</description></item><item><title>Named Loops</title><link>https://devendevour.iankulin.com/named-loops/</link><pubDate>Sun, 21 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/named-loops/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/img_2768.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;Here’s a neat thing I haven’t seen before. Other languages I’ve worked in haven’t had a neat way to break out of a set of nested loops to a particular loop. It’s not an issue that comes up a lot, but when it has I’ve solved it by creating a continue flag and having that as the first condition of each loop.&lt;/p&gt;
&lt;p&gt;To explain, say if we had these two loops (in C):&lt;/p&gt;</description></item><item><title>Checkpoint 9</title><link>https://devendevour.iankulin.com/checkpoint-9/</link><pubDate>Sat, 20 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/checkpoint-9/</guid><description>&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/-JmAbcISEmY?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;/*
Your challenge is this: write a function that accepts an
optional array of integers, and returns one randomly.
If the array is missing or empty, return a random number
in the range 1 through 100.&lt;/p&gt;
&lt;p&gt;If that sounds easy, it’s because I haven’t explained
the catch yet: I want you to write your function in a
single line of code. No, that doesn’t mean you should
just write lots of code then remove all the line breaks
– you should be able to write this whole thing in one
line of code.&lt;/p&gt;</description></item><item><title>Visual Studio Code</title><link>https://devendevour.iankulin.com/visual-studio-code/</link><pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/visual-studio-code/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/visual_studio_code_1.35_icon.svg_.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve noticed &lt;a href="https://code.visualstudio.com/" target="_blank" rel="noopener"&gt;Visual Studio Code&lt;/a&gt; in a few videos, and admired what a clean interface it had, and was impressed how opening a terminal window was automatically in the directory you were working in.&lt;/p&gt;
&lt;p&gt;I had a need to write some html/css, and some C++ in the last couple of days, so that seemed like a great excuse to give it a try. I&amp;rsquo;d have to say my opinion of it has only gone up. Clearly, it is right at home with HTML and CSS - code completion and syntax colouring all working nicely. I followed TechWithTim&amp;rsquo;s suggestion to install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer" target="_blank" rel="noopener"&gt;Live Server extension&lt;/a&gt; - which was a completely painless experience.&lt;/p&gt;</description></item><item><title>CSS Intro</title><link>https://devendevour.iankulin.com/css-intro/</link><pubDate>Thu, 18 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/css-intro/</guid><description>&lt;p&gt;When I wrote my last commercial HTML (in 1996 lol) I&amp;rsquo;m pretty sure there was no CSS. It was the land of textured backgrounds, blinking scrolling text, &amp;ldquo;under construction&amp;rdquo; gifs, and links to &lt;a href="https://en.wikipedia.org/wiki/Gopher_%5c%28protocol%5c%29" target="_blank" rel="noopener"&gt;gopher&lt;/a&gt; URLs were not uncommon. So this is an area I need to update my skills a little just to carry on a coherent conversation in the developer world.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve bumped into a couple of &lt;a href="https://www.techwithtim.net/" target="_blank" rel="noopener"&gt;Tech With Tim&lt;/a&gt; &lt;a href="https://www.youtube.com/c/TechWithTim/videos" target="_blank" rel="noopener"&gt;videos&lt;/a&gt; recently, and I really liked his CSS intro for &amp;ldquo;Non-web developers&amp;rdquo;.&lt;/p&gt;</description></item><item><title>Checkpoint 8</title><link>https://devendevour.iankulin.com/checkpoint-8/</link><pubDate>Wed, 17 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/checkpoint-8/</guid><description>&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/Ga800-Qgft4?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;/*
Your challenge is this: make a protocol that describes a
building, adding various properties and methods, then
create two structs, House and Office, that conform to it.&lt;/p&gt;
&lt;p&gt;Your protocol should require the following:
A property storing how many rooms it has.
A property storing the cost as an integer
(e.g. 500,000 for a building costing $500,000.)
A property storing the name of the estate agent
responsible for selling the building.
A method for printing the sales summary of the building,
describing what it is along with its other properties.&lt;/p&gt;</description></item><item><title>Checkpoint 7</title><link>https://devendevour.iankulin.com/checkpoint-7/</link><pubDate>Mon, 15 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/checkpoint-7/</guid><description>&lt;p&gt;&lt;a href="https://www.hackingwithswift.com/quick-start/beginners/checkpoint-7" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-08-08-at-8.43.44-pm.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;/*
Your challenge is this: make a class hierarchy
for animals, starting with Animal at the top,
then Dog and Cat as subclasses, then Corgi and
Poodle as subclasses of Dog, and Persian and Lion
as subclasses of Cat.&lt;/p&gt;
&lt;p&gt;But there’s more:
The Animal class should have a legs integer
property that tracks how many legs the animal has.
The Dog class should have a speak() method that
prints a generic dog barking string, but each of
the subclasses should print something slightly
different.
The Cat class should have a matching speak() method,
again with each subclass printing something
different.
The Cat class should have an isTame Boolean property,
provided using an initializer.&lt;/p&gt;</description></item><item><title>Scope Creep</title><link>https://devendevour.iankulin.com/scope-creep/</link><pubDate>Sun, 14 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/scope-creep/</guid><description>&lt;p&gt;&lt;a href="https://www.inc.com/lolly-daskal/7-reasons-why-you-need-to-embrace-procrastination.html" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/getty_492816326_104863.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;In project management, and especially in programming &amp;ldquo;scope creep&amp;rdquo; refers to the common situation where what&amp;rsquo;s required to regard a project as finished keeps growing. Most commonly, in the form of extra features required to be added to an application. I&amp;rsquo;ve especially seen this when clients see early versions of applications and it prompts them to request things that were not in the original specification.&lt;/p&gt;
&lt;p&gt;My iOS development learning journey has been experiencing some of this as well. I started out with only four clear &lt;a href="https://devendevour.wordpress.com/goals/" target="_blank" rel="noopener"&gt;goals&lt;/a&gt; :&lt;/p&gt;</description></item><item><title>@ObservedObject v @StateObject</title><link>https://devendevour.iankulin.com/observedobject-v-stateobject/</link><pubDate>Sat, 13 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/observedobject-v-stateobject/</guid><description>&lt;p&gt;The Youtube algorithm thinks I need to watch more MVVM videos, and it turns out it&amp;rsquo;s probably right. A day or two ago in an &lt;a href="https://devendevour.iankulin.com/simple-mvvm/"&gt;MVVM&lt;/a&gt; post using a super simple example, I stored the view model as a property of the view using the @ObservedObject wrapper, as I created it.&lt;/p&gt;
&lt;p&gt;struct ContentView: View {
@ObservedObject var light = LightViewModel()&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var body: some View {
 VStack{
 Spacer()
 if light.isOn(){
 drawLitBulb
 }
 else{
 Image(systemName: &amp;quot;lightbulb.fill&amp;quot;).font(.system(size: 72))
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But then today, Youtube served me up this video from &lt;a href="https://www.youtube.com/c/BeyondOnesAndZeros/videos" target="_blank" rel="noopener"&gt;BeyondOnesAndZeros&lt;/a&gt; &lt;/p&gt;</description></item><item><title>Rust</title><link>https://devendevour.iankulin.com/rust/</link><pubDate>Fri, 12 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/rust/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/rustmemelovetriangle_297886754.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s been exciting to see some of the modern language features in Swift - it&amp;rsquo;s a real joy to work in when I think back to my C++ days which was some of the last commercial programming I did.&lt;/p&gt;
&lt;p&gt;The buzz about Carbon got me wondering about other new languages and what might be going on with them. Rust seems to keep popping up in conversations so I thought I&amp;rsquo;d have a quick look.&lt;/p&gt;</description></item><item><title>Vim</title><link>https://devendevour.iankulin.com/vim/</link><pubDate>Wed, 10 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/vim/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/1-_bwvjb2jzuuzyxgxm6xwqq.png" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been working through the &lt;a href="https://missing.csail.mit.edu/" target="_blank" rel="noopener"&gt;Missing Semester&lt;/a&gt; lectures from MIT, and recently completed the lecture about the &lt;a href="https://github.com/vim/vim" target="_blank" rel="noopener"&gt;Vim editor&lt;/a&gt; . Vim is a test editor, called from the command line, and optimised for programming - in the sense that it assumes most of the use of the editor is navigating around a big text file making small changes rather than entering large amount of test.&lt;/p&gt;
&lt;p&gt;It uses simple, short key presses (as opposed to mouse movements or using menus or toolbars) to achieve things. This makes it highly efficient for good typists who know all the commands, and slightly incomprehensible to those who do not. An additional level of complexity is the idea of modes. Vim has several modes, the main ones being:&lt;/p&gt;</description></item><item><title>Firebase</title><link>https://devendevour.iankulin.com/firebase/</link><pubDate>Tue, 09 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/firebase/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-08-06-at-10.01.15-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;In the category of &amp;ldquo;getting ahead of myself&amp;rdquo;, my list of potential future apps to develop includes an entry for a simple accounting system. I guess transactions could live in SQLite, on iCloud for sharing between Mac and mobile devices. Nevertheless, while noodling about it, I thought I should think about it being fully online, and I&amp;rsquo;d heard Google&amp;rsquo;s Firebase (probably referring for specifically to &lt;a href="https://firebase.google.com/products/firestore" target="_blank" rel="noopener"&gt;Firestore&lt;/a&gt; ) mentioned in several iOS developer podcasts and thought I should take a look.&lt;/p&gt;</description></item><item><title>iOS Academy</title><link>https://devendevour.iankulin.com/ios-academy/</link><pubDate>Mon, 08 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/ios-academy/</guid><description>&lt;p&gt;I seem to consume a lot of &lt;a href="https://iosacademy.io/" target="_blank" rel="noopener"&gt;iOS Academy&lt;/a&gt; videos with great, short (&amp;lt; 10 minute) explanations of various Swift iOS programming topics - particularly little UI topics, like this one on the Grid View.&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/A3jOHj9erQ4?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;I really appreciate the generous content provision in the Swift and iOS development community. Perhaps this is the same for lots of technologies, but for someone who started programming pre-internet, it&amp;rsquo;s a stark difference to how I used to learn - so many magazines, and so many 2&amp;quot; thick books.&lt;/p&gt;</description></item><item><title>MVVM Explained</title><link>https://devendevour.iankulin.com/mvvm-explained/</link><pubDate>Sun, 07 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/mvvm-explained/</guid><description>&lt;p&gt;The first nine minutes of &lt;a href="https://www.youtube.com/watch?v=sLHVxnRS75w" target="_blank" rel="noopener"&gt;this video&lt;/a&gt; from &lt;a href="https://twitter.com/Its_Macco" target="_blank" rel="noopener"&gt;Emmanuel Okwara&lt;/a&gt; finally gave me a clear understanding of the difference between MVC and MVVM.&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/sLHVxnRS75w?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;In both MVC and MVVM the data &amp;amp; logic (Model) are separated from the part that the user interacts (View). Usually the View is a screen with controls and so on, but that&amp;rsquo;s not compulsory - for example a voice mail app interface would be all audio and DTMF. The point is that in both, the user interface (view) does not mess directly with the data (model) - it has to go through some sort of gatekeeper.&lt;/p&gt;</description></item><item><title>Oh My Zsh</title><link>https://devendevour.iankulin.com/oh-my-zsh/</link><pubDate>Sat, 06 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/oh-my-zsh/</guid><description>&lt;p&gt;I&amp;rsquo;ve been playing in the zsh shell since I started on the &lt;a href="https://devendevour.iankulin.com/missing-semester/"&gt;Missing Semester&lt;/a&gt; , and was wondering how to get my git branch name in the prompt. A few googles later, I&amp;rsquo;ve installed Oh My Zsh, and added the git and macos plugins. Pretty.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-08-02-at-7.26.08-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;</description></item><item><title>Missing Semester</title><link>https://devendevour.iankulin.com/missing-semester/</link><pubDate>Fri, 05 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/missing-semester/</guid><description>&lt;p&gt;On my git odyssey yesterday, I came across which is an MIT class for CS about practical things CS students don&amp;rsquo;t strictly need for their degree, but will greatly benefit from. I was interested in their git introduction, but they explain &lt;a href="https://missing.csail.mit.edu/" target="_blank" rel="noopener"&gt;the course&lt;/a&gt; by saying:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://missing.csail.mit.edu/" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-08-01-at-8.50.12-pm.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Videos of the lectures, and all the course notes and assignments are freely made available. I&amp;rsquo;ve only watched the first lecture about the shell, and their git lecture. Both were excellent, so I&amp;rsquo;ll add this series to by &lt;a href="https://devendevour.wordpress.com/goals/" target="_blank" rel="noopener"&gt;Goals&lt;/a&gt; .&lt;/p&gt;</description></item><item><title>Chris Lattner</title><link>https://devendevour.iankulin.com/chris-lattner/</link><pubDate>Wed, 03 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/chris-lattner/</guid><description>&lt;p&gt;Thank you YouTube algorithm for this recommendation - Chris Lattner, the main author of Swift (amongst other things including LVM) chatting with Lex Fridman. Ignore the clickbait title. There is a good, brief discussion about the tradeoffs in value vs references types which is a topic I&amp;rsquo;ve been thinking a bit about this week.&lt;/p&gt;
&lt;p&gt;Also some interesting comments about how a language delivers it&amp;rsquo;s complexity. Chris gives the funny example of what &amp;ldquo;hello world&amp;rdquo; looks like in Swift vs C++. Here&amp;rsquo;s Swift: &lt;code&gt;Print(&amp;quot;Hello world&amp;quot;)&lt;/code&gt;, here&amp;rsquo;s C++:&lt;/p&gt;</description></item><item><title>Retain Cycle</title><link>https://devendevour.iankulin.com/retain-cycle/</link><pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/retain-cycle/</guid><description>&lt;p&gt;Variables and constants in Swift can be a &lt;em&gt;value type&lt;/em&gt; (their data is copied when they are copied) or a &lt;em&gt;reference type&lt;/em&gt; (a pointer to the data is passed when they are copied.&lt;/p&gt;
&lt;p&gt;Structs, integers, and enums are value types, classes are reference types.&lt;/p&gt;
&lt;p&gt;Memory management of value types is relatively straightforward - there’s a 1:1 relationship between the variable name and its data, so if the variable goes out of scope it can get the chop. With reference types, it’s possible to have several variables (or class or struct properties etc) all pointing to the data, so a more sophisticated system is needed to know when it’s safe to delete the data.&lt;/p&gt;</description></item><item><title>Bump One</title><link>https://devendevour.iankulin.com/bump-one/</link><pubDate>Mon, 01 Aug 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/bump-one/</guid><description>&lt;p&gt;Most of the things I’ve learned so far have been familiar, interesting, or cool - but now I’ve ventured far enough into the Swift Language Programming book to find something that is definitely going to take a couple of readings to piece together.&lt;/p&gt;
&lt;p&gt;I was surprised, then pleased with functions as first class types, and the idea of passing closures around is powerful and useful.&lt;/p&gt;
&lt;p&gt;My current difficulty is getting my head around closures capturing variables. It was tolerable (but not safe) when I just thought of it as a pointer, but when turned out the captured variable continues to exist in some sort of zombie state even after the scope where the variable was contained has ended.&lt;/p&gt;</description></item><item><title>Unwrap</title><link>https://devendevour.iankulin.com/unwrap/</link><pubDate>Sun, 31 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/unwrap/</guid><description>&lt;p&gt;Unwrap is the Paul Hudson app for Swift learning. It’s good for using those three minute gaps in life to digest a concept. I’ve incorporated it into my &lt;a href="https://devendevour.wordpress.com/goals/" target="_blank" rel="noopener"&gt;goals&lt;/a&gt; , as some days its the only progress I make.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/fa3cfadd-f6ef-4a05-9131-be5de8f38291.jpeg" alt="" class="img-responsive"&gt; &lt;/p&gt;</description></item><item><title>Xcode Refactor/Rename</title><link>https://devendevour.iankulin.com/xcode-refactor-rename/</link><pubDate>Sat, 30 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/xcode-refactor-rename/</guid><description>&lt;p&gt;This is cool. You can right click on a variable (and I guess any other) name and change it everywhere. No more tedious search and replace.&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/SXSQgtGREKw?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>@ScaledMetric</title><link>https://devendevour.iankulin.com/scaledmetric/</link><pubDate>Fri, 29 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/scaledmetric/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-07-23-at-9.04.21-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I solved the problem (well, I googled a &lt;a href="https://stackoverflow.com/questions/72568296/sf-symbol-images-different-sizes" target="_blank" rel="noopener"&gt;stackoverflow result&lt;/a&gt; to the problem) in the previous post about the different heights of the SF Symbols. The answer was to put them in a frame and lock the height. A problem that then arises from that is that when the user changes the text size, they&amp;rsquo;ll be out of wack. Apple&amp;rsquo;s solution to that, introduced in iOS 14 is the &lt;a href="https://developer.apple.com/documentation/swiftui/scaledmetric" target="_blank" rel="noopener"&gt;@ScaledMetric property wrapper&lt;/a&gt; that does some magic I don&amp;rsquo;t fully understand yet.&lt;/p&gt;</description></item><item><title>Memorise Assignment 1</title><link>https://devendevour.iankulin.com/memorise-assignment-1/</link><pubDate>Thu, 28 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/memorise-assignment-1/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-07-23-at-7.33.03-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;A small milestone achieved - I&amp;rsquo;ve completed the first assignment from the CS193p lecture series - some minor changes to the app being built in the lectures. There was a couple of things I was unhappy with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The text under the SF Symbols you can see in the preview above not being vertically aligned.&lt;/li&gt;
&lt;li&gt;Having duplicated code in my emoji arrays:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; let animalEmojis = [&amp;#34;🐠&amp;#34;, &amp;#34;🐢&amp;#34;, &amp;#34;🦋&amp;#34;, &amp;#34;🐥&amp;#34;, &amp;#34;🐣&amp;#34;, &amp;#34;🐰&amp;#34;, &amp;#34;🐝&amp;#34;, &amp;#34;🦄&amp;#34;, &amp;#34;🐵&amp;#34;, &amp;#34;🐛&amp;#34;]
 let weatherEmojis = [&amp;#34;🌪&amp;#34;, &amp;#34;🌝&amp;#34;, &amp;#34;🌈&amp;#34;, &amp;#34;🔥&amp;#34;, &amp;#34;🌧&amp;#34;, &amp;#34;🌙&amp;#34;, &amp;#34;🌬&amp;#34;, &amp;#34;☃️&amp;#34;, &amp;#34;☔️&amp;#34;, &amp;#34;🌫&amp;#34;]
 let transportEmojis = [&amp;#34;🚗&amp;#34;, &amp;#34;🚕&amp;#34;, &amp;#34;🚲&amp;#34;, &amp;#34;🚚&amp;#34;, &amp;#34;🛵&amp;#34;, &amp;#34;🚜&amp;#34;, &amp;#34;🛴&amp;#34;, &amp;#34;🛺&amp;#34;, &amp;#34;🚃&amp;#34;, &amp;#34;🚡&amp;#34;]

 // I&amp;#39;m not happy with this duplication //TODO
 @State var emojis = [&amp;#34;🐠&amp;#34;, &amp;#34;🐢&amp;#34;, &amp;#34;🦋&amp;#34;, &amp;#34;🐥&amp;#34;, &amp;#34;🐣&amp;#34;, &amp;#34;🐰&amp;#34;, &amp;#34;🐝&amp;#34;, &amp;#34;🦄&amp;#34;, &amp;#34;🐵&amp;#34;, &amp;#34;🐛&amp;#34;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This second problem is because I couldn&amp;rsquo;t just&lt;/p&gt;</description></item><item><title>SwiftUI Essentials</title><link>https://devendevour.iankulin.com/swiftui-essentials/</link><pubDate>Wed, 27 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/swiftui-essentials/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-07-23-at-4.12.38-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I hadn&amp;rsquo;t fully gotten my head around what&amp;rsquo;s going on with the declarative nature of SwiftUI, until I&amp;rsquo;d watched this video&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s from the &lt;a href="https://developer.apple.com/videos/play/wwdc2019/216/" target="_blank" rel="noopener"&gt;2019 WWDC&lt;/a&gt; which is when (I guess) SwiftUI was new. I still don&amp;rsquo;t have a good handle on how the views are bound to their data, but there is a video from this same series about Data Flows which I imagine will also answer those questions.&lt;/p&gt;</description></item><item><title>iOS Dev Weekly</title><link>https://devendevour.iankulin.com/ios-dev-weekly/</link><pubDate>Tue, 26 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/ios-dev-weekly/</guid><description>&lt;p&gt;Dave Verwer&amp;rsquo;s &lt;a href="https://iosdevweekly.com/" target="_blank" rel="noopener"&gt;iOS Dev Weekly&lt;/a&gt; digest of links mainly about Swift libraries was mentioned on a podcast I was listening to last night - perhaps the &lt;em&gt;Swift with Sundell&lt;/em&gt; &lt;a href="https://www.swiftbysundell.com/podcast/16/" target="_blank" rel="noopener"&gt;chat with Sommer Panage&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;My &lt;a href="https://iosdevweekly.com/issues/568?#start" target="_blank" rel="noopener"&gt;first issue&lt;/a&gt; (it&amp;rsquo;s an email newsletter) arrived, and it&amp;rsquo;s pretty great. Not too long, chatty but on topic, and with links to follow for more info. As well as new or improved libraries, other topics are mentioned - I went down a rabbit hole on &lt;a href="https://useyourloaf.com/blog/swiftui-split-view-configuration/" target="_blank" rel="noopener"&gt;SwiftUI Split View Configuration&lt;/a&gt; , ending up at this WWDC video about it.&lt;/p&gt;</description></item><item><title>Xcode Tour</title><link>https://devendevour.iankulin.com/xcode-tour/</link><pubDate>Sun, 24 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/xcode-tour/</guid><description>&lt;p&gt;If you need a solid tour of the basics plus of Xcode, this is a great video from Karin Prater. Its the first video in her &amp;ldquo;Design-oriented course on SwiftUI&amp;rdquo;.&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/EDHl1r5vw6Q?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>SF Symbols</title><link>https://devendevour.iankulin.com/sf-symbols/</link><pubDate>Thu, 21 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/sf-symbols/</guid><description>&lt;p&gt;A couple of times in the App Development seminar I went to, we used system symbols in the place of images, and in his tutorial on Swift UI Basics, Sean Allen spent a few minutes talking about where they come from and how to choose them.&lt;/p&gt;
&lt;p&gt;First, here&amp;rsquo;s how they look in code - this is from the default Hello World app.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;struct ContentView: View {
 var body: some View {
 VStack {
 Image(systemName: &amp;#34;globe&amp;#34;)
 .imageScale(.large)
 .foregroundColor(.accentColor)
 Text(&amp;#34;Hello world&amp;#34;)
 }
 }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-07-17-at-7.26.23-am.png" alt="" class="img-responsive"&gt; &lt;/p&gt;</description></item><item><title>Passing Data</title><link>https://devendevour.iankulin.com/passing-data/</link><pubDate>Wed, 20 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/passing-data/</guid><description>&lt;p&gt;Sean Allen has come to my notice a couple of times, once where he was mentioned as freelance contractor who is a great contributor to the community (I think perhaps that was on &lt;a href="https://podcasts.apple.com/au/podcast/swiftcoders-interviews-with-swift-developers/id1082937962" target="_blank" rel="noopener"&gt;Swiftcoders Podcast&lt;/a&gt; ), and I&amp;rsquo;ve also bumped into him as co-host (with Paul Hudson) of the early episodes of the &amp;ldquo;&lt;a href="https://podcasts.apple.com/au/podcast/swift-over-coffee/id1435076502" target="_blank" rel="noopener"&gt;Swift over Coffee&lt;/a&gt; &amp;rdquo; podcast.&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/HXoVSbwWUIk?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;This video I watched last night is a compilation of the first few videos of &lt;a href="https://seanallen.teachable.com/p/swiftui-fundamentals" target="_blank" rel="noopener"&gt;Sean&amp;rsquo;s SwiftUI course&lt;/a&gt; , and it&amp;rsquo;s pretty great. In particular he does a great job of explaining how to start to refactor child views out and call them, and how all the stacks go together to make a pretty interface. What he does not do is vist/explain any of the Swift language fundamentals. If you don&amp;rsquo;t already know what a struc is, and the Swift flavour of them, it may be a challenging place to start.&lt;/p&gt;</description></item><item><title>App Development in Swift Playgrounds</title><link>https://devendevour.iankulin.com/app-development-in-swift-playgrounds/</link><pubDate>Tue, 19 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/app-development-in-swift-playgrounds/</guid><description>&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/img_1938.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;During the week I attended &amp;ldquo;App Development in Swift Playgrounds&amp;rdquo; run by &lt;a href="https://www.mattrichards.net.au/" target="_blank" rel="noopener"&gt;Matt Richards&lt;/a&gt; with the support of some of the Apple team and hosted by &lt;a href="https://twitter.com/mssgellis" target="_blank" rel="noopener"&gt;Dr Michelle Ellis&lt;/a&gt; . It was aimed a teachers looking at using Playgrounds for digi-tech teaching.&lt;/p&gt;
&lt;p&gt;The day included pulling apart one of the Playgrounds apps and rebuilding it - this being an example of a &amp;ldquo;top-down&amp;rdquo; approach - starting with a complete app and fiddling around with it - to better engage students. The alternative being a bottom-up approach where lesson one would be &amp;ldquo;good morning students, this is a variable, it can hold a value, it has a name we can use to refer to the value&amp;rdquo;.&lt;/p&gt;</description></item><item><title>struct</title><link>https://devendevour.iankulin.com/struct/</link><pubDate>Mon, 18 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/struct/</guid><description>&lt;p&gt;Started on &lt;a href="https://www.hackingwithswift.com/100/swiftui/10" target="_blank" rel="noopener"&gt;Day 10 of 100 days of etc etc&lt;/a&gt; today which is about structs. It was immediately clear when I first started looking at Swift and Swift UI that structs were going to be a big deal. I am used to structs being able to contain a collection of other types, but not methods. So I was confused at why tuples existed; that is now cleared up.&lt;/p&gt;
&lt;p&gt;If structs can have methods as well as properties, it answers the question of why tuples exist, but immediately asks the question, why have classes since structs have all this power? I already know (from my podcast consumption) one of the answers for this is that structs are value types rather than references. When you:&lt;/p&gt;</description></item><item><title>Fireside Swift</title><link>https://devendevour.iankulin.com/fireside-swift/</link><pubDate>Sun, 17 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/fireside-swift/</guid><description>&lt;p&gt;One of the ways I keep engaged in a topic is to listen to podcasts about it. Currently &lt;a href="https://podcasts.apple.com/au/podcast/fireside-swift/id1269435221" target="_blank" rel="noopener"&gt;Fireside Swift&lt;/a&gt; is one of the Swift/SwiftUI/iOS Development podcasts that I have in the rotation.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/firesideswift.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;The blurb for the show is:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;Fireside Swift is a popular iOS Development podcast where four buddies discuss a new Swift programming topic each week. They try to stay informal while also conveying the information they know about each topic with bits of humor sprinkled throughout. Have a seat by the fire, and enjoy some nerdy discussion with friends!&amp;rdquo;&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Checkpoint 5</title><link>https://devendevour.iankulin.com/checkpoint-5/</link><pubDate>Sat, 16 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/checkpoint-5/</guid><description>&lt;pre tabindex="0"&gt;&lt;code&gt;/*
 Your input is this:
 
 let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]
 
 Your job is to:
 
 Filter out any numbers that are even
 Sort the array in ascending order
 Map them to strings in the format “7 is a lucky number”
 Print the resulting array, one item per line
 
 So, your output should be as follows:
 
 7 is a lucky number
 15 is a lucky number
 21 is a lucky number
 31 is a lucky number
 33 is a lucky number
 49 is a lucky number
 */

let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]

func isNumberOdd(number:Int) -&amp;gt; Bool {
 return number%2 == 1
}

let filteredNumbers = luckyNumbers.filter(isNumberOdd)

// this closure effectively does nothing
let sortedNumbers = filteredNumbers.sorted(by: {$0&amp;lt;$1}) 

let mappedNumbers = sortedNumbers.map({ String($0)+&amp;#34; is a lucky number&amp;#34; })

for i in 0..&amp;lt;mappedNumbers.count {
 print(mappedNumbers[i])
}
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Create an Empty Folder on GitHub</title><link>https://devendevour.iankulin.com/create-an-empty-folder-on-github/</link><pubDate>Fri, 15 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/create-an-empty-folder-on-github/</guid><description>&lt;p&gt;You can&amp;rsquo;t, but you can create a folder by adding a file through the web interface and using &lt;code&gt;&amp;lt;folder name&amp;gt;/&amp;lt;file name&amp;gt;&lt;/code&gt; - so add a README.md or whatever. Then you can drag your source into the new folder as normal.&lt;/p&gt;
&lt;p&gt;I learned this from Zack West &lt;a href="https://www.alpharithms.com/how-to-create-a-folder-in-github-repos-463022/" target="_blank" rel="noopener"&gt;here&lt;/a&gt; , where there is also a better explanation with pictures.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-07-11-at-11.11.39-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;</description></item><item><title>Minimum Functionality for App Store</title><link>https://devendevour.iankulin.com/minimum-functionality-for-app-store/</link><pubDate>Fri, 15 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/minimum-functionality-for-app-store/</guid><description>&lt;p&gt;In my &lt;a href="https://devendevour.iankulin.com/app-idea/"&gt;post about&lt;/a&gt; my first app, EasterDay, I mentioned that it might be too trivial for an App Store submission. I&amp;rsquo;ve just been reading the App Store Review Guidelines, and there is a section on &lt;a href="https://developer.apple.com/app-store/review/guidelines/#minimum-functionality" target="_blank" rel="noopener"&gt;Minimum Functionality&lt;/a&gt; that seems like it might be too pointless for acceptance.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-07-11-at-9.22.55-am.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll push on and build it anyway as I still need the rest of the learning experience, but may not submit it. Of course I&amp;rsquo;ve got other ideas for apps (like everyone who has ever met an iOS developer) but they are outside my expertise for the time being.&lt;/p&gt;</description></item><item><title>awesome-ios list on GitHub</title><link>https://devendevour.iankulin.com/awesome-ios-list-on-github/</link><pubDate>Thu, 14 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/awesome-ios-list-on-github/</guid><description>&lt;p&gt;I was looking for some more podcasts with Swift fundamentals content when I came across &lt;a href="https://github.com/vsouza/awesome-ios" target="_blank" rel="noopener"&gt;this&lt;/a&gt; great community built awesome list.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/vsouza/awesome-ios" target="_blank" rel="noopener"&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-07-11-at-8.45.25-am.jpg" alt="" class="img-responsive"&gt; &lt;/a&gt; &lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a few podcasts on the list I have not come across, so I&amp;rsquo;ll check them out.&lt;/p&gt;</description></item><item><title>Learning Retention</title><link>https://devendevour.iankulin.com/learning-retention/</link><pubDate>Thu, 14 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/learning-retention/</guid><description>&lt;p&gt;In order to have something to put up on GitHub (as part of working all that out) I went back to re-write the Checkpoint 2 code that I&amp;rsquo;d written, but not saved, three or four days ago.&lt;/p&gt;
&lt;p&gt;The task was to count the unique elements in an array. The teaching had been about the complex data types, so clearly the hint was to cast the array to a set. Although the idea of sets is new to me this year, I&amp;rsquo;ve come across them twice. Once in the 100 days course (the same day as having to write this code) and once from a few days earlier from a &lt;a href="https://firesideswift.fireside.fm/157" target="_blank" rel="noopener"&gt;podcast episode&lt;/a&gt; . This is high quality learning - getting the same topic a couple of different ways a few days apart, then having to use the information for real.&lt;/p&gt;</description></item><item><title>Checkpoint 4</title><link>https://devendevour.iankulin.com/checkpoint-4/</link><pubDate>Wed, 13 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/checkpoint-4/</guid><description>&lt;pre tabindex="0"&gt;&lt;code&gt;/*
 The challenge is this: write a function that accepts an integer from 1 through 10,000, and returns the integer square root of that number. That sounds easy, but there are some catches:
 
 You can’t use Swift’s built-in sqrt() function or similar – you need to find the square root yourself.
 If the number is less than 1 or greater than 10,000 you should throw an “out of bounds” error.
 You should only consider integer square roots – don’t worry about the square root of 3 being 1.732, for example.
 If you can’t find the square root, throw a “no root” error.
 */

enum IntSqrtError: Error {
 case low, high, noIntRoot
}

func calculateIntSqrt(_ number:Int) throws -&amp;gt; Int {
 let lowerBound = 1
 let upperBound = 10_000
 if number &amp;lt; lowerBound {throw IntSqrtError.low}
 if number &amp;gt; upperBound {throw IntSqrtError.high}
 // brute force sqrt finder
 for i in lowerBound...number {
 if i*i == number {
 return i
 }
 }
 // none found or we would have returned by now
 throw IntSqrtError.noIntRoot
}

do {
 try print(calculateIntSqrt(5929))
} catch IntSqrtError.low {
 print(&amp;#34;Lower bound error&amp;#34;)
} catch IntSqrtError.high {
 print(&amp;#34;Upper bound error&amp;#34;)
} catch IntSqrtError.noIntRoot {
 print(&amp;#34;No integer root&amp;#34;)
} catch {
 assert(false)
 print(&amp;#34;Unknown error&amp;#34;)
}
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Checkpoint 4 optimisation</title><link>https://devendevour.iankulin.com/checkpoint-4-optimisation/</link><pubDate>Wed, 13 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/checkpoint-4-optimisation/</guid><description>&lt;p&gt;The &lt;a href="https://www.hackingwithswift.com/quick-start/beginners/checkpoint-4" target="_blank" rel="noopener"&gt;Checkpoint 4&lt;/a&gt; task was to find an integer square root of numbers up to 10000. My &lt;a href="https://devendevour.iankulin.com/checkpoint-4/"&gt;first pass solution&lt;/a&gt; was:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;func calculateIntSqrt(_ number:Int) throws -&amp;gt; Int {
 let lowerBound = 1
 let upperBound = 10_000
 if number &amp;lt; lowerBound {throw IntSqrtError.low}
 if number &amp;gt; upperBound {throw IntSqrtError.high}
 // brute force sqrt finder
 for i in lowerBound...number {
 if i*i == number {
 return i
 }
 }
 // none found or we would have returned by now
 throw IntSqrtError.noIntRoot
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Although not coded for speed, there are a couple of subtle optimisations here; the first is that it gives up once it gets to the number instead of going up to the end (it assumes the square root of a number can&amp;rsquo;t be greater than the number), and the second is that it counts up from the bottom rather than down from the top - I&amp;rsquo;m assuming the bottom of the range is richer in square roots than the top.&lt;/p&gt;</description></item><item><title>Gitting Started</title><link>https://devendevour.iankulin.com/gitting-started/</link><pubDate>Wed, 13 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/gitting-started/</guid><description>&lt;p&gt;One of my early goals was to get in the habit of using version control with Git/Github, and I&amp;rsquo;ve got that sorted out today. My source was this excellent, very clear video from &lt;a href="https://www.youtube.com/channel/UCxA99Yr6P_tZF9_BgtMGAWA" target="_blank" rel="noopener"&gt;Gwen Faraday&lt;/a&gt; . I highly recommend it if you are just starting.&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/RGOj5yH7evk?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;It possibly helped that I&amp;rsquo;m also on mac, so I didn&amp;rsquo;t have to deal with the &amp;ldquo;or however that&amp;rsquo;s done on your system&amp;rdquo; type problems. Also, where things didn&amp;rsquo;t work as expected, the explanation about what was being done was clear enough that the problem was solvable. For example, the push command Gwen used was:&lt;/p&gt;</description></item><item><title>Tuple Pronunciation</title><link>https://devendevour.iankulin.com/tuple-pronunciation/</link><pubDate>Tue, 12 Jul 2022 00:00:00 +0000</pubDate><guid>https://devendevour.iankulin.com/tuple-pronunciation/</guid><description>&lt;p&gt;Another advantage of the videos, that hadn&amp;rsquo;t occurred to me when I &lt;a href="https://devendevour.iankulin.com/cs193p/"&gt;mentioned it the other day&lt;/a&gt; , is learning the correct pronunciation of things you&amp;rsquo;ve only ever read in books.&lt;/p&gt;
&lt;p&gt;Apparently, tuple is pronounced two-pull, and not with the tup to rhyme with cup as I&amp;rsquo;d always imagined. Google has confirmed, so it&amp;rsquo;s not just a UK thing.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devendevour.iankulin.com/images/screen-shot-2022-07-09-at-12.06.59-pm.jpg" alt="" class="img-responsive"&gt; &lt;/p&gt;</description></item></channel></rss>