PageSourceSearch

https://jonathanchannon.com/

html jonathanchannon.com collected 2026-10-02 05:25:53 UTC 24,385 bytes, 40 lines download raw bytes

1<!doctype html><html lang=en-gb><head><meta name=generator content="Hugo 0.152.1"><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta http-equiv=X-UA-Compatible content="IE=edge"><title>Jonathan Channon's Blog</title><meta name=description content="Jonathan Channon's Blog"><meta name=author content="Jonathan Channon"><meta name=twitter:card content="summary_large_image"><meta name=twitter:title content="Jonathan Channon's Blog"><meta name=twitter:description content="Jonathan Channon's Blog"><link rel=preconnect href=https://fonts.googleapis.com><link rel=preconnect href=https://fonts.gstatic.com crossorigin><link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap" rel=stylesheet><link rel=stylesheet href="/css/style.css?v=1768233931"><link rel=alternate type=application/rss+xml href=https://blog.jonathanchannon.com/index.xml title="Jonathan Channon's Blog">
1<script>(function(){const e=localStorage.getItem("theme");(e==="dark"||!e&&window.matchMedia("(prefers-color-scheme: dark)").matches)&&document.documentElement.setAttribute("data-theme","dark")})()</script>
1<meta property="og:url" content="https://blog.jonathanchannon.com/"><meta property="og:site_name" content="Jonathan Channon's Blog"><meta property="og:title" content="Jonathan Channon's Blog"><meta property="og:description" content="Jonathan Channon's Blog"><meta property="og:locale" content="en_gb"><meta property="og:type" content="website"><meta property="og:image" content="https://blog.jonathanchannon.com/images/og-site.png">
vendor: 63 bytes, line 1
1<script async src="https://www.googletagmanager.com/gtag/js?id=
1G-JEEX96WRGE
vendor: 11 bytes, line 1
1"></script>
1<script>var dnt,doNotTrack=!1;if(!1&&(dnt=navigator.doNotTrack||window.doNotTrack||navigator.msDoNotTrack,doNotTrack=dnt=="1"||dnt=="yes"),!doNotTrack){window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date),gtag("config","G-JEEX96WRGE")}</script>
1</head><body><header class=site-header><div class="container header-inner"><nav class=main-nav><div class=nav-tabs><a href=https://blog.jonathanchannon.com/ class="nav-tab active">Blog</a>
2<a href=/archive/ class=nav-tab>Archive</a></div><div class=header-right><div class="social-links header-social"><a href=https://bsky.app/profile/jonathanchannon.com target=_blank rel="noopener noreferrer" aria-label=Bluesky><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908.0 3.08.0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741.0 01-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478.0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8z"/></svg>
3</a><a href=https://github.com/jchannon target=_blank rel="noopener noreferrer" aria-label=GitHub><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.374.0.0 5.373.0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931.0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176.0.0 1.008-.322 3.301 1.23A11.509 11.509.0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221.0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"/></svg>
4</a><a href=https://linkedin.com/in/jonathanchannon target=_blank rel="noopener noreferrer" aria-label=LinkedIn><svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853.0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601.0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433A2.062 2.062.0 013.274 5.368a2.064 2.064.0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225.0H1.771C.792.0.0.774.0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2.0 22.222.0h.003z"/></svg></a></div><button class=theme-toggle id=theme-toggle aria-label="Toggle dark mode">
5<svg class="sun-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
6<svg class="moon-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg></button></div></nav></div></header><main class=container><section class=post-list-section><ul class=post-list><li class=post-item><h2 class=post-title><a href=https://blog.jonathanchannon.com/2026-01-12-agentic-semantic-data-modelling-csharp/>Agentic Semantic Data Modelling in C#</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
7<time datetime=2026-01-12>January 12, 2026</time></span><div class=tags><a href=/tags/ai/ class=tag>AI</a>
8<a href=/tags/.net/ class=tag>.NET</a>
9<a href=/tags/csharp/ class=tag>csharp</a>
10<a href=/tags/mongodb/ class=tag>MongoDB</a></div></div><div class=post-excerpt><p>Over the last few weeks I&rsquo;ve been working on a feature that allows us to take advantage of AI within businesses and providing increased value to stakeholders. It&rsquo;s a natural language query interface that allows non-technical users to ask questions about data in plain English and get back meaningful results. No SQL to write, no reports to configure, just ask a question and get an answer. The interesting bit though is how I&rsquo;ve approached this problem and what it reveals about building trustworthy AI-powered systems.</p></div><a href=https://blog.jonathanchannon.com/2026-01-12-agentic-semantic-data-modelling-csharp/ class=read-more>Read more &rarr;</a></li><li class=post-item>
10<h2 class=post-title><a href=https://blog.jonathanchannon.com/2026-01-09-running-csharp-against-ollama/>Running C# against Ollama</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
11<time datetime=2026-01-09>January 9, 2026</time></span><div class=tags><a href=/tags/ai/ class=tag>AI</a>
12<a href=/tags/.net/ class=tag>.NET</a>
13<a href=/tags/csharp/ class=tag>csharp</a></div></div><div class=post-excerpt><p>In my previous posts I introduced <a href=https://blog.jonathanchannon.com/2025-12-23-introduction-to-ai/>AI concepts</a> and then showed how to <a href=https://blog.jonathanchannon.com/2026-01-06-using-ai-csharp/>use AI in a C# app</a> using the cloud providers. In this post I want to expand on Ollama and show you how to build a chat agent in C# that runs entirely on your local machine.</p></div><a href=https://blog.jonathanchannon.com/2026-01-09-running-csharp-against-ollama/ class=read-more>Read more &rarr;</a></li><li class=post-item><h2 class=post-title><a href=https://blog.jonathanchannon.com/2026-01-06-using-ai-csharp/>Using AI in a C# app</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
14<time datetime=2026-01-06>January 6, 2026</time></span><div class=tags><a href=/tags/ai/ class=tag>AI</a>
15<a href=/tags/.net/ class=tag>.NET</a>
16<a href=/tags/csharp/ class=tag>csharp</a></div></div><div class=post-excerpt><p>Following on my from my previous <a href=https://blog.jonathanchannon.com/2025-12-23-introduction-to-ai/>introduction to AI</a> post I thought I would now introduce how to use the AI providers in a C# application.</p><p>We may want to build some AI features inside a new or existing app and so where do we start as a C# developer?</p><p>This blog post will go through a fairly simple example just to illustrate the &ldquo;how&rdquo; and then you can adapt it for your needs and maybe I&rsquo;ll add some more thought out examples in other posts.</p></div><a href=https://blog.jonathanchannon.com/2026-01-06-using-ai-csharp/ class=read-more>Read more &rarr;</a></li><li class=post-item><h2 class=post-title><a href=https://blog.jonathanchannon.com/2025-12-23-introduction-to-ai/>Introduction to AI</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
17<time datetime=2025-12-23>December 23, 2025</time></span><div class=tags><a href=/tags/ai/ class=tag>AI</a>
18<a href=/tags/.net/ class=tag>.NET</a>
19<a href=/tags/csharp/ class=tag>csharp</a></div></div><div class=post-excerpt><p>If you can&rsquo;t beat them, join them is probably the best quote to sum up my experience with AI.</p><p>We have known for a long time AI is changing the way we work however, we all know how unreliable it is and personally I have seen that for a long time when it &ldquo;helpfully&rdquo; suggests code suggestions as I type. I have also seen
20how unreliable it is when using an AI Assistant to do something for me.</p><p>My conclusions have been &ldquo;this thing is not going to take away people&rsquo;s jobs or take over the world, it&rsquo;s absolutely useless&rdquo;.</p><p>However, as time has gone on and models have got better and clearly AI is not going away, I decided I better try and learn some fundamentals of AI and try to find ways in which I can test it out.</p><p>Therefore, this post will be an introduction for those still in the &ldquo;this is useless&rdquo; mindset which might help explain some concepts and how to use it so it can be more effective for you.</p></div><a href=https://blog.jonathanchannon.com/2025-12-23-introduction-to-ai/ class=read-more>Read more &rarr;</a></li><li class=post-item>
20<h2 class=post-title><a href=https://blog.jonathanchannon.com/2022-01-29-azuread-golang/>Using Azure AD authentication for a Go API</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
21<time datetime=2022-01-29>January 29, 2022</time></span><div class=tags><a href=/tags/golang/ class=tag>golang</a>
22<a href=/tags/authentication/ class=tag>authentication</a>
23<a href=/tags/auth/ class=tag>auth</a>
24<a href=/tags/golang/ class=tag>golang</a></div></div><div class=post-excerpt><p>So after a long time I thought I&rsquo;d take another look at Go and whilst struggling to think what little app should I write to get back in the saddle with, the legend that is <a href=https://twitter.com/christosmatskas>Christos Matskas</a> mentioned he wanted to try using a Go api against Azure AD for authentication. So I fired up <a href=https://www.jetbrains.com/go/>GoLand</a> and got to work writing an API.</p><h2 id=setting-up-azure-ad>Setting up Azure AD</h2><ol><li>You will need to create an Azure Directory in your account which is pretty straightforward. The only user in the directory will be you.</li><li>Inside the directory you will then need to register an application, again pretty straightforward.</li><li>Next under Certificates & Secrets, you will need to create a secret, this will be used as part of the auth handshake. Give it a name and Azure will create the value. Take a copy of it ready for your API</li><li>On the Overview page take a copy of the Application (client) ID</li><li>On the Overview page take a copy of the Directory (tenant) ID</li><li>Go to Expose An API</li><li>Click Add a scope</li><li>Create something like &ldquo;allow_user&rdquo; and choose Admins and users</li><li>Go to API Permissions and click Add a Permission</li><li>Select My APIs and select your application/API</li><li>Tick the scope you just created</li><li>Now here&rsquo;s a weird thing, if you don&rsquo;t see your scope, try going to another tab in your browser or refresh you Azure Portal page. Something is broken IMO in that it takes time or needs refreshing for it to show up</li><li>Click Manifest on the left hand side</li><li>Change <code>accessTokenAcceptedVersion</code> to <code>2</code> and click Save</li></ol></div><a href=https://blog.jonathanchannon.com/2022-01-29-azuread-golang/ class=read-more>Read more &rarr;</a></li><li class=post-item><h2 class=post-title><a href=https://blog.jonathanchannon.com/2021-04-13-terminology-glossary/>Terminology Glossary</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
25<time datetime=2021-04-13>April 13, 2021</time></span><div class=tags><a href=/tags/glossary/ class=tag>glossary</a>
26<a href=/tags/terminology/ class=tag>terminology</a></div></div><div class=post-excerpt><p>This page will list and describe common words and terms that you might come across as a software developer which you can refer to at a later date knowing there&rsquo;s a place to go to when someone uses a term that you don&rsquo;t know, are unsure of or can&rsquo;t remember</p><h3 id=terms>Terms</h3><p>Cohesion -<br>Composition Root -<br>Coupling -<br>Cross-Cutting -<br>KPI -<br>Lift & Shift -<br>OKR -<br>Orthogonal -<br>Projection -<br>Shift Left -</p></div><a href=https://blog.jonathanchannon.com/2021-04-13-terminology-glossary/ class=read-more>Read more &rarr;</a></li><li class=post-item><h2 class=post-title><a href=https://blog.jonathanchannon.com/2021-01-29-tracing-io-netcore/>Tracing IO in .NET Core</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
27<time datetime=2021-01-29>January 29, 2021</time></span><div class=tags><a href=/tags/oss/ class=tag>OSS</a>
28<a href=/tags/carter/ class=tag>Carter</a>
29<a href=/tags/opentelemetry/ class=tag>OpenTelemetry</a></div></div><div class=post-excerpt><p>
29I was made aware of <a href=https://opentelemetry.io/>OpenTelemetry</a> a while ago by a <a href=https://jimmybogard.com/building-end-to-end-diagnostics-and-tracing-a-primer/>blog series</a> <a href=https://twitter.com/jbogard>Jimmy Bogard</a> and put it in my favourites to read at a later date. Of course I didn&rsquo;t really get back to it in depth and gave it a quick scan at the time although it is a well written in depth blog series so I suggest you do check it out. A while later I saw a <a href=https://rehansaeed.com/deep-dive-into-open-telemetry-for-net/>blog post</a> by <a href=https://twitter.com/RehanSaeedUK>Rehan Saeed</a> which gives an introduction on what OpenTelemetry is and how it works and the concepts behind it and is definitely worth a read. At the same time I saw a <a href="https://www.youtube.com/watch?v=FikF0DtxZno">YouTube video</a> by <a href=https://twitter.com/EltonStoneman>Elton Stoneman</a> that whilst more aimed at using tracing using Kubernetes he demonstrates a .NET app running and the tracing details appear in <a href=https://www.jaegertracing.io/>Jaeger</a></p></div><a href=https://blog.jonathanchannon.com/2021-01-29-tracing-io-netcore/ class=read-more>Read more &rarr;</a></li><li class=post-item><h2 class=post-title><a href=https://blog.jonathanchannon.com/2020-08-07-understanding-type-aliases/>Understanding type aliases</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
30<time datetime=2020-08-07>August 7, 2020</time></span><div class=tags><a href=/tags/oss/ class=tag>OSS</a>
31<a href=/tags/fsharp/ class=tag>fsharp</a>
32<a href=/tags/csharp/ class=tag>csharp</a></div></div><div class=post-excerpt><p>I recently wrote a single case discriminated union which is what I wanted but was also confused why it didn&rsquo;t behave like a type alias and then learnt that these two are different things.</p><p><code>type CustomerId = int</code></p><p><code>type CustomerId = CustomerId of int</code></p><p>I was aware of both syntaxes and from a quick scan they look the same however they behave differently and rightly so. As I travel the F# road there is more emphasis on creating types for your functions. I have used this approach in C# to enforce type discrimination but it seems less prevalent in the mainstream from my experience. For example think of this:</p></div><a href=https://blog.jonathanchannon.com/2020-08-07-understanding-type-aliases/ class=read-more>Read more &rarr;</a></li><li class=post-item><h2 class=post-title><a href=https://blog.jonathanchannon.com/2020-07-17-understanding-fsharp-applicatives-custom-operators/>Understanding F# applicatives and custom operators</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
33<time datetime=2020-07-17>July 17, 2020</time></span><div class=tags><a href=/tags/oss/ class=tag>OSS</a>
34<a href=/tags/fsharp/ class=tag>fsharp</a></div></div><div class=post-excerpt><p>After discussing something with Ian Russell he suggested I take some time to read through another fine <a href=https://www.softwarepark.cc/blog/2019/12/8/functional-validation-in-f-using-applicatives>blog post</a> he has written and understand F# applicatives and custom operators. I found myself in familiar territory when reading F# blog posts and it&rsquo;s something similar to the five stages of grief. Nod, Nod, I understand what&rsquo;s going on, Umm, WTF is going on. As Ian did in his <a href=https://www.softwarepark.cc/blog/2019/9/12/introduction-to-functional-programming-in-f>Intro to F#</a>
34 series he sets out a simple domain problem and goes about how to address it. We want to return a <code>ValidatedUser</code> from a function but if the user fails validation we return a list of validation errors.</p><p>The code in the blog post was pretty self explanatory until, it wasn&rsquo;t, which I have pasted below:</p></div><a href=https://blog.jonathanchannon.com/2020-07-17-understanding-fsharp-applicatives-custom-operators/ class=read-more>Read more &rarr;</a></li><li class=post-item><h2 class=post-title><a href=https://blog.jonathanchannon.com/2020-06-28-understanding-fsharp-map-and-bind/>Understanding F# map/bind</a></h2><div class=post-meta><span class=post-date><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
35<time datetime=2020-06-28>June 28, 2020</time></span><div class=tags><a href=/tags/oss/ class=tag>OSS</a>
36<a href=/tags/fsharp/ class=tag>fsharp</a></div></div><div class=post-excerpt><p>This blog post aims to explain map/bind in F# in a code only example. It took me a while so I&rsquo;m writing it up here so I can come back to it and re-read it for the 100th time most likely!</p></div><a href=https://blog.jonathanchannon.com/2020-06-28-understanding-fsharp-map-and-bind/ class=read-more>Read more &rarr;</a></li></ul><nav class=pagination aria-label=Pagination><span class=disabled>&larr; Newer</span>
37<span class=current>1 / 7</span>
38<a href=/page/2/ aria-label="Next page">Older &rarr;</a></nav></section></main><footer class=site-footer><div class="container footer-inner"><div class=social-links><a href=https://bsky.app/profile/jonathanchannon.com target=_blank rel="noopener noreferrer" aria-label=Bluesky><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908.0 3.08.0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741.0 01-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478.0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8z"/></svg>
39</a><a href=https://github.com/jchannon target=_blank rel="noopener noreferrer" aria-label=GitHub><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.374.0.0 5.373.0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931.0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176.0.0 1.008-.322 3.301 1.23A11.509 11.509.0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221.0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"/></svg>
40</a><a href=https://linkedin.com/in/jonathanchannon target=_blank rel="noopener noreferrer" aria-label=LinkedIn><svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853.0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601.0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433A2.062 2.062.0 013.274 5.368a2.064 2.064.0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225.0H1.771C.792.0.0.774.0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2.0 22.222.0h.003z"/></svg></a></div><p class=copyright>&copy; 2026 Jonathan Channon's Blog. All rights reserved.</p></div></footer>
40<script src=/js/theme-toggle.js></script>
40</body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.