<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Funky Si's Test</title><link>https://blog-test.funkysi1701.com/</link><description>Recent content on Funky Si's Test</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><managingEditor>funkysi1701@gmail.com (Simon Foster)</managingEditor><webMaster>funkysi1701@gmail.com (Simon Foster)</webMaster><lastBuildDate>Tue, 18 Aug 2026 08:00:00 +0000</lastBuildDate><atom:link href="https://blog-test.funkysi1701.com/index.xml" rel="self" type="application/rss+xml"/><item><title>GitOps with Flux on my k3s cluster</title><link>https://blog-test.funkysi1701.com/posts/2026/gitops-with-flux-on-my-k3s-cluster/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 18 Aug 2026 08:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/gitops-with-flux-on-my-k3s-cluster/</guid><category term="Flux">Flux</category><category term="GitOps">GitOps</category><category term="Kubernetes">Kubernetes</category><category term="Helm">Helm</category><category term="k3s">k3s</category><category term="DevOps">DevOps</category><category term="SOPS">SOPS</category><category term="cert-manager">cert-manager</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/gitops-with-flux-k3s.png"/><description>&lt;p&gt;I already knew how to put things &lt;em&gt;on&lt;/em&gt; a Kubernetes cluster. &lt;a href="https://blog-test.funkysi1701.com/posts/2025/deploying-hugo-with-helm/"&gt;Helm&lt;/a&gt;
packages the YAML. &lt;a href="https://blog-test.funkysi1701.com/posts/2025/learning-kubernetes/"&gt;&lt;code&gt;kubectl apply&lt;/code&gt;&lt;/a&gt;
makes it exist. &lt;a href="https://blog-test.funkysi1701.com/posts/2025/kubernetes-and-letsencrypt/"&gt;cert-manager&lt;/a&gt;
mints the certificates. What I did not have was a boring answer to “what happens next week, when I have forgotten which laptop I ran that from?”&lt;/p&gt;
&lt;p&gt;GitOps is that answer, at least for &lt;strong&gt;platform&lt;/strong&gt; on my homelab. In practice, GitOps means keeping the desired cluster state in git and having an in-cluster controller continuously reconcile the live cluster back to that state. &lt;strong&gt;&lt;code&gt;simon-cluster&lt;/code&gt;&lt;/strong&gt; is the name I gave the &lt;a href="https://k3s.io/" target="_blank" rel="noopener noreferrer"&gt;k3s&lt;/a&gt;
cluster I run at home — a small Kubernetes estate for shared ingress, certificates, monitoring, and the GitHub Actions runners this blog builds on. &lt;a href="https://fluxcd.io/" target="_blank" rel="noopener noreferrer"&gt;Flux CD&lt;/a&gt;
on that cluster watches a private platform repo and keeps it in line with &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The useful part is not “I put YAML in git.” It is the &lt;strong&gt;split&lt;/strong&gt;. Flux owns MetalLB, Traefik, cert-manager, GitHub runners, the in-cluster registry, Cloudflare Tunnel, and monitoring. Application Helm releases in &lt;code&gt;develop&lt;/code&gt; / &lt;code&gt;main&lt;/code&gt; / &lt;code&gt;test&lt;/code&gt; still come from &lt;strong&gt;their own repos and pipelines&lt;/strong&gt;. Azure DevOps is still in that second column. Flux is not pretending to be the whole estate.&lt;/p&gt;
&lt;h2 id="pull-not-push"&gt;Pull, not push&lt;a class="anchor ms-1" href="#pull-not-push" aria-label="Permalink: Pull, not push"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A lot of “GitOps” talk is really CI with extra steps: a pipeline authenticates to the cluster and runs &lt;code&gt;helm upgrade&lt;/code&gt;. That is a &lt;strong&gt;push&lt;/strong&gt;. It works. I still do it for apps.&lt;/p&gt;
&lt;p&gt;Flux is a &lt;strong&gt;pull&lt;/strong&gt;. The cluster has a &lt;code&gt;GitRepository&lt;/code&gt; pointed at a private platform repo on &lt;code&gt;main&lt;/code&gt;. Child &lt;code&gt;Kustomization&lt;/code&gt; objects apply paths under that repo on a schedule. If someone (or some leftover pipeline) changes a Flux-managed object by hand, the next reconcile puts it back.&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;source.toolkit.fluxcd.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;GitRepository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;flux-system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;flux-system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;interval&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1m&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ref&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;branch&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;url&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://github.com/example/example-config.git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Bootstrap is once: install the Flux controllers (&lt;code&gt;gotk-components.yaml&lt;/code&gt;), give Flux a git credential and an age key for SOPS, apply &lt;code&gt;gotk-sync.yaml&lt;/code&gt;. After that I mostly work in git rather than reaching for kubeconfig.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git add -A &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit -m &lt;span style="color:#e6db74"&gt;&amp;#34;…&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;flux get all -A
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;flux reconcile kustomization flux-system --with-source
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I still keep &lt;code&gt;kubectl&lt;/code&gt; for poking at pods. I try not to use it as the source of truth for anything Flux already owns.&lt;/p&gt;
&lt;h2 id="how-the-repo-is-laid-out"&gt;How the repo is laid out&lt;a class="anchor ms-1" href="#how-the-repo-is-laid-out" aria-label="Permalink: How the repo is laid out"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clusters/simon-cluster/ # Flux bootstrap + child Kustomizations
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;infrastructure/ # HelmRepositories, HelmReleases, CRs, SOPS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;clusters/simon-cluster&lt;/code&gt; is the entry point Flux syncs. Each child Kustomization is a named slice of the platform with its own interval, &lt;code&gt;dependsOn&lt;/code&gt;, and (where secrets live) SOPS decryption. &lt;code&gt;infrastructure/&lt;/code&gt; is the actual YAML those slices apply.&lt;/p&gt;
&lt;p&gt;Order matters. Helm charts cannot install until the &lt;code&gt;HelmRepository&lt;/code&gt; objects exist. cert-manager cannot come up until those sources do. A shortened version of the cert-manager slice looks like 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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;kustomize.toolkit.fluxcd.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Kustomization&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;flux-system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;interval&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30m&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dependsOn&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;sources&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;./infrastructure/cert-manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;prune&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;wait&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;decryption&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;provider&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;sops&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;secretRef&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;sops-age&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;prune: true&lt;/code&gt; is the bit people skip and then regret. If you delete the manifest and Flux still has prune off, the live object sits there forever looking “fine.” &lt;code&gt;wait: true&lt;/code&gt; plus &lt;code&gt;dependsOn&lt;/code&gt; is the other half of that: cert-manager does not race Traefik because the Kustomization will not move on until the slice is healthy.&lt;/p&gt;
&lt;p&gt;The Helm install itself is a &lt;code&gt;HelmRelease&lt;/code&gt;, not a pipeline task:&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;helm.toolkit.fluxcd.io/v2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;HelmRelease&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;interval&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30m&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;chart&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;chart&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;version&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;v1.21.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;sourceRef&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;HelmRepository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;jetstack&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;flux-system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same idea as &lt;a href="https://blog-test.funkysi1701.com/posts/2025/deploying-hugo-with-helm/"&gt;deploying with Helm&lt;/a&gt;
, except the cluster is the thing that runs &lt;code&gt;helm&lt;/code&gt;, not me.&lt;/p&gt;
&lt;h2 id="one-change-end-to-end"&gt;One change, end to end&lt;a class="anchor ms-1" href="#one-change-end-to-end" aria-label="Permalink: One change, end to end"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A typical platform change is dull, which is the point.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Edit YAML under &lt;code&gt;infrastructure/…&lt;/code&gt; (chart version, values, a &lt;code&gt;ClusterIssuer&lt;/code&gt;, a runner replica count).&lt;/li&gt;
&lt;li&gt;Open a PR, merge to &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Wait for the Kustomization interval, or &lt;code&gt;flux reconcile&lt;/code&gt; if I am impatient.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flux get hr,ks -A&lt;/code&gt; until the slice is &lt;code&gt;Ready&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If it is not Ready, read the condition before assuming git and the cluster agree. That command is the homelab equivalent of a pipeline log.&lt;/p&gt;
&lt;p&gt;I already wrote about &lt;a href="https://blog-test.funkysi1701.com/posts/2025/kubernetes-and-letsencrypt/"&gt;Let’s Encrypt on this cluster&lt;/a&gt;
when cert-manager was a &lt;code&gt;kubectl apply&lt;/code&gt; of upstream YAML. That install now lives in git as the HelmRelease above plus &lt;code&gt;ClusterIssuer&lt;/code&gt; manifests. The DNS-01 token is not in those files in plaintext; it is a SOPS-encrypted Secret Flux decrypts on the cluster.&lt;/p&gt;
&lt;p&gt;Grafana followed the same path. I first ran it in &lt;a href="https://blog-test.funkysi1701.com/posts/2025/setting-up-grafana/"&gt;Docker Compose for .NET metrics&lt;/a&gt;
. The homelab copy now sits in the &lt;code&gt;monitoring&lt;/code&gt; namespace, owned by Flux, with dashboards as ConfigMaps in the same repo. Compose taught me the product; GitOps is how it stays installed when I am not watching.&lt;/p&gt;
&lt;p&gt;This blog is in the picture too, just not as a website on the cluster. Production is still Azure Static Web Apps. What Flux &lt;em&gt;does&lt;/em&gt; provision for this repo is a pool of &lt;a href="https://github.com/actions/actions-runner-controller" target="_blank" rel="noopener noreferrer"&gt;Actions Runner Controller&lt;/a&gt;
runners labelled &lt;code&gt;k8s&lt;/code&gt;, so GitHub Actions can build on the homelab instead of burning hosted minutes. The &lt;code&gt;RunnerDeployment&lt;/code&gt; is YAML in that private platform repo. The workflows stay in &lt;em&gt;this&lt;/em&gt; git repo. That is the split in miniature.&lt;/p&gt;
&lt;h2 id="secrets-in-git-not-in-chat"&gt;Secrets in git, not in chat&lt;a class="anchor ms-1" href="#secrets-in-git-not-in-chat" aria-label="Permalink: Secrets in git, not in chat"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Platform secrets are &lt;code&gt;*.enc.yaml&lt;/code&gt; files encrypted with &lt;a href="https://github.com/getsops/sops" target="_blank" rel="noopener noreferrer"&gt;SOPS&lt;/a&gt;
and &lt;a href="https://age-encryption.org/" target="_blank" rel="noopener noreferrer"&gt;age&lt;/a&gt;
. Flux has a &lt;code&gt;sops-age&lt;/code&gt; Secret in &lt;code&gt;flux-system&lt;/code&gt; (created once, not committed) and Kustomizations that need secrets set &lt;code&gt;decryption.provider: sops&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What &lt;em&gt;is&lt;/em&gt; in git: Cloudflare DNS-01, the ARC GitHub token, Grafana admin, registry pull secrets, tunnel token. What is &lt;strong&gt;not&lt;/strong&gt;: the age private key. If you clone that private platform repo you get ciphertext and the public key in &lt;code&gt;.sops.yaml&lt;/code&gt;. That is enough to &lt;em&gt;add&lt;/em&gt; a secret if you have the private key locally; it is not enough to read the live ones.&lt;/p&gt;
&lt;p&gt;This is not Azure Key Vault. A homelab cluster does not need a cloud HSM to stop me committing a PAT. It needs encryption at rest in git and a bootstrap secret that never hits GitHub. The repo documents how SOPS and age are wired up.&lt;/p&gt;
&lt;h2 id="what-flux-does-not-own"&gt;What Flux does not own&lt;a class="anchor ms-1" href="#what-flux-does-not-own" aria-label="Permalink: What Flux does not own"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I keep an ownership map in that private platform repo because GitOps fails the moment two systems apply the same object. Deciding who is allowed to apply has been more useful than any controller version pin. The short version:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;This repo (Flux)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Namespaces, MetalLB, cert-manager, Traefik, ARC, Zot, cloudflared, monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;App git + CI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Helm releases in &lt;code&gt;develop&lt;/code&gt; / &lt;code&gt;main&lt;/code&gt; / &lt;code&gt;test&lt;/code&gt; (blog chart, TrekRanks, SQL, …)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;k3s / the node&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CoreDNS, local-path, metrics-server, disable bundled Traefik&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Several apps still deploy from Azure DevOps. That is fine. It is &lt;strong&gt;push CI&lt;/strong&gt;, and Flux will not “fix” a Deployment it does not declare. If an old pipeline and a HelmRelease both think they own Grafana, they will fight. I moved monitoring into Flux on purpose so there is one owner.&lt;/p&gt;
&lt;p&gt;k3s itself is not GitOps in this repo either. Node join, versions, and “do not run the bundled Traefik” are documented and applied on the hosts. Flux cannot bootstrap the thing that runs Flux.&lt;/p&gt;
&lt;p&gt;In-cluster &lt;a href="https://docs.renovatebot.com/" target="_blank" rel="noopener noreferrer"&gt;Renovate&lt;/a&gt;
is a small extra: it opens image-bump PRs against that private platform repo. Upgrades become git history too, not SSH-and-hope. One note on Renovate, the Renovate package itself is very noisy, with multiple update PRs raised per day. I have chosen to automerge these, but you may want to consider skipping this package or updating on a schedule.&lt;/p&gt;
&lt;p&gt;I would not start a new cluster by SSHing in and applying twenty manifests. Ingress, certificates, runners, and monitoring are shared, so they belong in git from the start. I would still start a new &lt;em&gt;app&lt;/em&gt; with a pipeline and a Helm chart in &lt;em&gt;that&lt;/em&gt; repo — Flux &lt;code&gt;HelmRelease&lt;/code&gt; is how those charts get onto the cluster, not a replacement for packaging.&lt;/p&gt;
&lt;p&gt;I have not moved every Helm chart into Flux, and I am not pretending that is a moral failing. GitOps earned its place here by making the platform dull. Dull is the goal.&lt;/p&gt;
&lt;p&gt;If you run Kubernetes at home — or you are weighing GitOps against push CI — how do you split &lt;strong&gt;platform&lt;/strong&gt; from &lt;strong&gt;apps&lt;/strong&gt;? Full pull, pipelines only, or a hybrid like mine? I would be interested to hear what works for you in the comments.&lt;/p&gt;
&lt;p&gt;If this is your first step on the same path, these posts are where I started: &lt;a href="https://blog-test.funkysi1701.com/posts/2025/learning-kubernetes/"&gt;learning Kubernetes&lt;/a&gt;
, &lt;a href="https://blog-test.funkysi1701.com/posts/2025/deploying-hugo-with-helm/"&gt;deploying with Helm&lt;/a&gt;
, and &lt;a href="https://blog-test.funkysi1701.com/posts/2025/kubernetes-and-letsencrypt/"&gt;Let&amp;rsquo;s Encrypt on the cluster&lt;/a&gt;
. For a monthly email when I publish something new, &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;subscribe to the newsletter&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Pairing with AI in VS Code and Cursor</title><link>https://blog-test.funkysi1701.com/posts/2026/ai-pair-programming-dotnet/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 07 Aug 2026 12:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/ai-pair-programming-dotnet/</guid><category term="AI">AI</category><category term="DotNet">DotNet</category><category term="Cursor">Cursor</category><category term="VSCode">VSCode</category><category term="GitHubCopilot">GitHubCopilot</category><category term="Productivity">Productivity</category><category term="Programming">Programming</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/ai-pair-programming-dotnet.png"/><description>&lt;p&gt;On a lot of days my pair programmer is not a person. It is Copilot finishing a method, or Cursor proposing a multi-file edit I still have to own.&lt;/p&gt;
&lt;p&gt;Back in April I covered &lt;a href="https://blog-test.funkysi1701.com/posts/2026/how-i-use-ai-on-side-projects/"&gt;how I use ChatGPT, Cursor, and Copilot on side projects&lt;/a&gt;
. That was mostly about which tool I reach for. Here I want to talk about what that looks like when the code is .NET—C#, Blazor, Azure Functions—and I am working in VS Code or Cursor.&lt;/p&gt;
&lt;p&gt;I am not claiming a universal workflow. These are habits that have helped me in 2026.&lt;/p&gt;
&lt;h2 id="a-thin-tools-map-so-we-can-move-on"&gt;A thin tools map (so we can move on)&lt;a class="anchor ms-1" href="#a-thin-tools-map-so-we-can-move-on" aria-label="Permalink: A thin tools map (so we can move on)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I still use the same three buckets. The only change is which bucket I reach for when the stack is .NET-heavy.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;What I reach for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framing a design question or learning path&lt;/td&gt;
&lt;td&gt;ChatGPT (browser)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file change across a solution&lt;/td&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finish this method / test / YAML stanza&lt;/td&gt;
&lt;td&gt;GitHub Copilot in the editor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;ldquo;Build AI &lt;em&gt;into&lt;/em&gt; the product&amp;rdquo;&lt;/td&gt;
&lt;td&gt;Separate concern — see &lt;a href="https://blog-test.funkysi1701.com/posts/using-ai/"&gt;Using AI with .NET and Semantic Kernel&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If you already read the April post, you can skim this table and skip ahead. The interesting part is not the brand names; it is what happens after a suggestion appears.&lt;/p&gt;
&lt;p&gt;For vocabulary (RAG, LLM, Copilot, and friends), &lt;a href="https://blog-test.funkysi1701.com/posts/common-ai-copilot-terms/"&gt;Common AI and Copilot Terms&lt;/a&gt;
is still a useful glossary.&lt;/p&gt;
&lt;h2 id="scenario-unfamiliar-code-that-is-still-mine"&gt;Scenario: unfamiliar code that is still “mine”&lt;a class="anchor ms-1" href="#scenario-unfamiliar-code-that-is-still-mine" aria-label="Permalink: Scenario: unfamiliar code that is still “mine”"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
grew the way hobby apps do: Blazor on the front, Azure Functions and Cosmos DB behind, enough moving parts that I forget my own choices. When I come back after a few weeks, I do not want a greenfield tutorial from a chat window. I want something that has &lt;em&gt;seen&lt;/em&gt; the repo.&lt;/p&gt;
&lt;p&gt;In Cursor I ask questions like &amp;ldquo;where does per-user progress get written?&amp;rdquo; or &amp;ldquo;what breaks if this Cosmos query assumes a different partition key?&amp;rdquo; The useful answers cite &lt;em&gt;my&lt;/em&gt; folders and types. The useless ones invent a service layer I never wrote.&lt;/p&gt;
&lt;p&gt;What I do next matters more than the first reply:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open the files it named and confirm they are the real path.&lt;/li&gt;
&lt;li&gt;Diff any proposed edit against how neighbouring code already looks.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;dotnet build&lt;/code&gt; (and the bit of the app I touched) before I trust it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The productivity win is not that the model &amp;ldquo;knows Episode Atlas.&amp;rdquo; It is that I spend less time remapping a codebase I already wrote.&lt;/p&gt;
&lt;h2 id="scenario-boring-glue-that-still-has-to-be-correct"&gt;Scenario: boring glue that still has to be correct&lt;a class="anchor ms-1" href="#scenario-boring-glue-that-still-has-to-be-correct" aria-label="Permalink: Scenario: boring glue that still has to be correct"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This blog is Hugo plus Azure Static Web Apps, with GitHub Actions and a pile of Node/Python checks. A lot of the work is glue: a layout partial, a workflow step, a Playwright selector after a theme tweak. Copilot is often enough when I already know the shape—finish the next YAML key, sketch a test that matches the one above.&lt;/p&gt;
&lt;p&gt;Cursor earns its keep when the change spans files: &amp;ldquo;update this partial and the smoke test that asserts the heading,&amp;rdquo; or &amp;ldquo;align the SWA config check with what CI runs.&amp;rdquo; Those are exactly the edits where an incomplete suggestion is worse than no suggestion—half-applied config fails in ways that waste an evening.&lt;/p&gt;
&lt;p&gt;On Blazor and Functions work the same pattern shows up as DTOs, mapping, and tests. Copilot is fast at the third similar test. Cursor is better when the DTO, the endpoint, and the client all need to move together.&lt;/p&gt;
&lt;h2 id="scenario-debugging-when-the-model-is-too-confident"&gt;Scenario: debugging when the model is too confident&lt;a class="anchor ms-1" href="#scenario-debugging-when-the-model-is-too-confident" aria-label="Permalink: Scenario: debugging when the model is too confident"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have let an assistant send me on a wild goose chase: wrong package version, an API that never existed, a &amp;ldquo;fix&amp;rdquo; that compiled and still left the bug. A human pair who is sure and wrong is more dangerous than one who says &amp;ldquo;I am guessing.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;When something fails, I try to feed the model the error text and a failing test, not a vague description of what I think is wrong. If the first patch does not change the symptom, I stop re-prompting the same story. I read the stack, check docs, or bisect—same as I would without AI.&lt;/p&gt;
&lt;p&gt;Side projects are a forgiving place to learn that discipline. Production systems are not. Secrets, customer data, and employer code stay out of tools unless policy clearly allows them; I wrote about that boundary in the &lt;a href="https://blog-test.funkysi1701.com/posts/2026/how-i-use-ai-on-side-projects/"&gt;side projects post&lt;/a&gt;
and I still follow it.&lt;/p&gt;
&lt;h2 id="guardrails-that-actually-saved-me-time"&gt;Guardrails that actually saved me time&lt;a class="anchor ms-1" href="#guardrails-that-actually-saved-me-time" aria-label="Permalink: Guardrails that actually saved me time"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are the practices that keep AI pairing from becoming AI babysitting:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Read every diff you did not type.&lt;/strong&gt; Especially NuGet names, HTTP routes, auth, and anything touching data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefer project conventions over &amp;ldquo;cleaner&amp;rdquo; internet defaults.&lt;/strong&gt; If my solution uses one DI style, I reject the rewrite that introduces another for a one-line fix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify against official docs when the call looks unfamiliar.&lt;/strong&gt; Models still hallucinate plausible APIs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep the human review bar.&lt;/strong&gt; I treat agent output like a junior&amp;rsquo;s pull request: helpful when it is right, never something I merge on trust alone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Match depth of context to the task.&lt;/strong&gt; Do not paste half a solution into a browser chat for a one-line rename; do not ask inline Copilot to redesign a Functions + Cosmos flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="what-productivity-has-meant-for-me"&gt;What “productivity” has meant for me&lt;a class="anchor ms-1" href="#what-productivity-has-meant-for-me" aria-label="Permalink: What “productivity” has meant for me"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I am faster at first drafts and at navigating code I have not opened in a month. I am not faster at &lt;em&gt;skipping&lt;/em&gt; judgment. If anything, the cost of a bad accept is higher because the broken change can look polished.&lt;/p&gt;
&lt;p&gt;That lines up with the longer argument in &lt;a href="https://blog-test.funkysi1701.com/posts/2026/ai-wont-replace-developers/"&gt;AI Won&amp;rsquo;t Replace Developers, But It Will Redefine Us&lt;/a&gt;
: the work shifts toward directing, reviewing, and verifying. I see that every time I open Cursor or Copilot on Episode Atlas, this blog, or whichever .NET side project I am tinkering with that week.&lt;/p&gt;
&lt;p&gt;If you are doing similar work in C# or Blazor, leave a comment and tell me which tool you reach for first—and what you still refuse to hand to an assistant. I am always curious how other people draw that line.&lt;/p&gt;</description></item><item><title>HTTP QUERY: requests with a body</title><link>https://blog-test.funkysi1701.com/posts/2026/http-query-method/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 14 Jul 2026 07:30:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/http-query-method/</guid><category term="HTTP">HTTP</category><category term="QUERY">QUERY</category><category term="RFC10008">RFC10008</category><category term="REST">REST</category><category term="ASP.NETCore">ASP.NETCore</category><category term="APIDesign">APIDesign</category><category term="OpenAPI">OpenAPI</category><category term="DotNet">DotNet</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/http-query-method.png"/><description>&lt;p&gt;For years, API designers have had an awkward choice when a search got too complex for a URL. Stuff it into a &lt;code&gt;GET&lt;/code&gt; query string and hit practical URI length limits, or send a body with &lt;code&gt;POST&lt;/code&gt; and pretend a read-only filter is a write. Neither option felt right.&lt;/p&gt;
&lt;p&gt;In June 2026 the IETF published &lt;a href="https://www.rfc-editor.org/rfc/rfc10008.html" target="_blank" rel="noopener noreferrer"&gt;RFC 10008&lt;/a&gt;
, which defines &lt;strong&gt;QUERY&lt;/strong&gt; — a new HTTP method that is safe and idempotent like &lt;code&gt;GET&lt;/code&gt;, but carries request content like &lt;code&gt;POST&lt;/code&gt;. That long-standing gap finally has a standard answer.&lt;/p&gt;
&lt;h2 id="the-problem-query-solves"&gt;The problem QUERY solves&lt;a class="anchor ms-1" href="#the-problem-query-solves" aria-label="Permalink: The problem QUERY solves"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;GET&lt;/code&gt; is the right semantic for &amp;ldquo;please return something, and I am not asking you to change state.&amp;rdquo; It is safe, idempotent, and cacheable. The catch is where the input lives: in the URI. Complex filters, GraphQL-style documents, Elasticsearch queries, or large multi-field search payloads do not always fit comfortably in a URL. RFC 9110 suggests supporting request targets of at least 8,000 octets, but browsers, proxies, and gateways vary — and overflowing those limits is a practical failure, not a theoretical one.&lt;/p&gt;
&lt;p&gt;URI length is not the only issue. Request URIs — including query-string filters — are far more likely to appear in access logs, browser history, and bookmarks than request bodies. If your search payload contains personal data or other sensitive filters (think GDPR and PII), stuffing it into a &lt;code&gt;GET&lt;/code&gt; URL is often a compliance headache. That is one reason many teams already use &lt;code&gt;POST /search&lt;/code&gt;: the body is less exposed in everyday logging.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;POST&lt;/code&gt; accepts a body with a clear media type, which is perfect for structured input. The catch is what the rest of the HTTP stack is allowed to &lt;em&gt;assume&lt;/em&gt;. HTTP treats &lt;code&gt;POST&lt;/code&gt; as potentially unsafe and non-idempotent: a particular search endpoint can be a pure read in practice, but intermediaries cannot tell that from the method alone. They cannot safely auto-retry a failed &lt;code&gt;POST&lt;/code&gt; the way they can a &lt;code&gt;GET&lt;/code&gt;, and shared caches cannot treat it as a normal repeatable read. Tooling that assumes &amp;ldquo;POST means mutate&amp;rdquo; often groups a catalogue search with create/update traffic — culturally understandable, even when your handler never writes.&lt;/p&gt;
&lt;p&gt;People sometimes tried &lt;code&gt;GET&lt;/code&gt; &lt;em&gt;with&lt;/em&gt; a body. RFC 9110 is blunt about that: content on a &lt;code&gt;GET&lt;/code&gt; has no generally defined semantics, must not change the meaning of the request, and some implementations reject it because of request-smuggling concerns. That was never the answer.&lt;/p&gt;
&lt;p&gt;QUERY is the method that says what we meant all along: &lt;em&gt;process this enclosed content as a query, safely and idempotently, and return the result.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="what-rfc-10008-actually-defines"&gt;What RFC 10008 actually defines&lt;a class="anchor ms-1" href="#what-rfc-10008-actually-defines" aria-label="Permalink: What RFC 10008 actually defines"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From the abstract:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A QUERY requests that the request target process the enclosed content in a safe and idempotent manner and then respond with the result of that processing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Compared with &lt;code&gt;GET&lt;/code&gt;, you are not asking for a representation of the target URI by itself. You are asking the target resource to run a query &lt;em&gt;within its scope&lt;/em&gt;, using the request body and &lt;code&gt;Content-Type&lt;/code&gt; to define that query. Servers must fail the request if &lt;code&gt;Content-Type&lt;/code&gt; is missing or inconsistent with the content.&lt;/p&gt;
&lt;p&gt;Key properties:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Meaning for QUERY&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Safe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The client does not request or expect a state change on the target resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Idempotent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The same request can be retried after a connection failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cacheable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Successful responses may be stored and reused for subsequent QUERY requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Body required for the query&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The query lives in the content, not forced into the URI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Safe&lt;/strong&gt; here is the HTTP meaning: the client is not asking to change the &lt;em&gt;target&lt;/em&gt; resource (for example &lt;code&gt;/api/products&lt;/code&gt;). That does not ban every side effect on the planet. Your server can still increment metrics, write an audit row, or — as the RFC allows — create temporary resources behind &lt;code&gt;Location&lt;/code&gt; / &lt;code&gt;Content-Location&lt;/code&gt; so results can be fetched again with &lt;code&gt;GET&lt;/code&gt;. What intermediaries can assume is that QUERY is a read against the resource you addressed, not a create or update of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Idempotent&lt;/strong&gt; means repeating the same request does not cause &lt;em&gt;additional&lt;/em&gt; side effects beyond what a single successful attempt would cause. If the connection drops after you send a QUERY, a client or proxy can send it again without worrying that the second attempt will “do something twice” — unlike a non-idempotent &lt;code&gt;POST&lt;/code&gt; that might create two orders if retried. It does &lt;em&gt;not&lt;/em&gt; mean the response is frozen forever, and it is not the same as “cache forever.” Like &lt;code&gt;GET&lt;/code&gt;, two identical QUERY calls can return different results if the underlying catalogue changed between them.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;200 OK&lt;/code&gt; means the query was processed successfully and the results are in the response content. That matches how people already think about search endpoints — now with HTTP semantics that intermediaries can trust.&lt;/p&gt;
&lt;h2 id="how-it-compares-to-get-and-post"&gt;How it compares to GET and POST&lt;a class="anchor ms-1" href="#how-it-compares-to-get-and-post" aria-label="Permalink: How it compares to GET and POST"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;GET&lt;/th&gt;
&lt;th&gt;QUERY&lt;/th&gt;
&lt;th&gt;POST (as a &amp;ldquo;search&amp;rdquo;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Request body for the query&lt;/td&gt;
&lt;td&gt;No (undefined)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Safe (assumed by intermediaries)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not assumed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idempotent (assumed by intermediaries)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not assumed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typically cacheable as a read&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not assumed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fits large / structured input&lt;/td&gt;
&lt;td&gt;Poorly (URI limits)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keeps filters out of the URI (logs / bookmarks)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-retry after failure&lt;/td&gt;
&lt;td&gt;Safe&lt;/td&gt;
&lt;td&gt;Safe&lt;/td&gt;
&lt;td&gt;Risky&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You still use &lt;code&gt;GET&lt;/code&gt; when the URI alone identifies what you want — and when you are comfortable with that URI being logged. You still use &lt;code&gt;POST&lt;/code&gt; when you are creating or changing something, or when you need a body today and cannot yet rely on QUERY end to end. QUERY is for the awkward middle: &lt;em&gt;read-only operations whose input belongs in a body&lt;/em&gt;, with semantics intermediaries can trust.&lt;/p&gt;
&lt;h2 id="caching-location-and-accept-query"&gt;Caching, Location, and Accept-Query&lt;a class="anchor ms-1" href="#caching-location-and-accept-query" aria-label="Permalink: Caching, Location, and Accept-Query"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Caching QUERY is a bit more work than caching &lt;code&gt;GET&lt;/code&gt;, because the cache key &lt;strong&gt;must&lt;/strong&gt; incorporate the request content (and related metadata). Some caches may normalise insignificant differences when building that key; clients that care can send &lt;code&gt;Cache-Control: no-transform&lt;/code&gt; as advisory guidance.&lt;/p&gt;
&lt;p&gt;The RFC also gives servers a way to hand clients a simpler follow-up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Content-Location&lt;/code&gt;&lt;/strong&gt; — a URI for a resource that holds the &lt;em&gt;results&lt;/em&gt; of this query (temporary storage of what you just got).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Location&lt;/code&gt;&lt;/strong&gt; — a URI for an &lt;em&gt;equivalent resource&lt;/em&gt; that repeats the same query via &lt;code&gt;GET&lt;/code&gt;, without resending the body.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last point matters for CDNs and clients that are still catching up: after the first QUERY, subsequent hits can become ordinary &lt;code&gt;GET&lt;/code&gt;s against a stored-query URI.&lt;/p&gt;
&lt;p&gt;Discovery uses the new &lt;strong&gt;&lt;code&gt;Accept-Query&lt;/code&gt;&lt;/strong&gt; response field. A resource can advertise which query media types it understands, for example:&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-http" data-lang="http"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;Accept-Query: application/json, application/sql
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you send an unsupported type, expect &lt;code&gt;415 Unsupported Media Type&lt;/code&gt;, and you may use &lt;code&gt;Accept-Query&lt;/code&gt; (or &lt;code&gt;Accept&lt;/code&gt; on error responses) to learn what to try next.&lt;/p&gt;
&lt;h2 id="cors-and-security-notes"&gt;CORS and security notes&lt;a class="anchor ms-1" href="#cors-and-security-notes" aria-label="Permalink: CORS and security notes"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QUERY is &lt;strong&gt;not&lt;/strong&gt; a CORS-safelisted method. Browser &lt;code&gt;fetch&lt;/code&gt; calls will trigger a preflight &lt;code&gt;OPTIONS&lt;/code&gt; check, the same way &lt;code&gt;PUT&lt;/code&gt; or &lt;code&gt;DELETE&lt;/code&gt; do. That is intentional: you do not want a body-carrying cross-origin method sliding past CORS just because it is &amp;ldquo;read-like.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Putting filters in the QUERY body already helps versus a fat &lt;code&gt;GET&lt;/code&gt; query string — less sensitive material in URIs that get logged or bookmarked. That benefit disappears if you then mint temporary &lt;code&gt;Location&lt;/code&gt; or &lt;code&gt;Content-Location&lt;/code&gt; URIs that echo those filters into the path or query. The RFC warns those URIs should not include sensitive portions of the original request content.&lt;/p&gt;
&lt;h2 id="using-query-with-aspnet-core"&gt;Using QUERY with ASP.NET Core&lt;a class="anchor ms-1" href="#using-query-with-aspnet-core" aria-label="Permalink: Using QUERY with ASP.NET Core"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You do not need to wait for .NET 11 to try QUERY on the server. ASP.NET Core routing already accepts arbitrary method strings via &lt;code&gt;MapMethods&lt;/code&gt;, and recent releases expose &lt;code&gt;HttpMethods.Query&lt;/code&gt; (with &lt;code&gt;HttpMethods.IsQuery&lt;/code&gt;) so you do not have to sprinkle the literal &lt;code&gt;&amp;quot;QUERY&amp;quot;&lt;/code&gt; everywhere:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.MapMethods(&lt;span style="color:#e6db74"&gt;&amp;#34;/api/products/search&amp;#34;&lt;/span&gt;, [HttpMethods.Query], (ProductSearchRequest request) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; results = ProductCatalogue.Search(request);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; TypedResults.Ok(results);
&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;A thin helper keeps call sites readable:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HttpQueryExtensions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; IEndpointConventionBuilder MapQuery(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; IEndpointRouteBuilder endpoints,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; pattern,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Delegate handler) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; endpoints.MapMethods(pattern, [HttpMethods.Query], handler);
&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;What landed later is OpenAPI documentation. QUERY became a first-class Path Item operation in &lt;strong&gt;OpenAPI 3.2&lt;/strong&gt;. In &lt;strong&gt;.NET 11&lt;/strong&gt;, ASP.NET Core&amp;rsquo;s document generator recognises QUERY when you opt into that version — so Swagger / client generators see a proper &lt;code&gt;query&lt;/code&gt; operation instead of an oddball method string:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.Services.AddOpenApi(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_2;
&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;With OpenAPI 3.2, the operation appears as a sibling of &lt;code&gt;get&lt;/code&gt; / &lt;code&gt;post&lt;/code&gt;. On older document versions, generators may fall back to an extension such as &lt;code&gt;x-oai-additionalOperations&lt;/code&gt; so the endpoint is not silently dropped. Until you are on that stack, you can still ship QUERY endpoints and document them by hand if needed.&lt;/p&gt;
&lt;p&gt;Clients can call it with curl once the server understands the verb:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -X QUERY https://api.example.com/api/products/search &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -H &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;category&amp;#34;:&amp;#34;laptops&amp;#34;,&amp;#34;minPrice&amp;#34;:500,&amp;#34;tags&amp;#34;:[&amp;#34;ultrabook&amp;#34;,&amp;#34;16gb&amp;#34;]}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="what-to-watch-for-in-the-real-world"&gt;What to watch for in the real world&lt;a class="anchor ms-1" href="#what-to-watch-for-in-the-real-world" aria-label="Permalink: What to watch for in the real world"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Standards land before the entire ecosystem catches up. Worth checking before you announce QUERY as your public search API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Proxies, API gateways, and WAFs&lt;/strong&gt; — some still allow-list only a handful of methods.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser and CDN behaviour&lt;/strong&gt; — caching QUERY responses is more complex than &lt;code&gt;GET&lt;/code&gt;; temporary &lt;code&gt;Location&lt;/code&gt; URIs help.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client libraries and OpenAPI codegen&lt;/strong&gt; — support is improving, but pin versions carefully.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logs and analytics&lt;/strong&gt; — make sure QUERY is counted as a read, not lumped in with mutating &lt;code&gt;POST&lt;/code&gt;s.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For service-to-service APIs under your control, QUERY is already useful. For public browser-facing APIs, validate your edge stack and CORS setup first.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;a class="anchor ms-1" href="#why-this-matters" aria-label="Permalink: Why this matters"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;HTTP methods are how we communicate intent to every hop between the client and your app. When intent and method disagree — a read that intermediaries cannot assume from &lt;code&gt;POST&lt;/code&gt;, or a body bolted onto &lt;code&gt;GET&lt;/code&gt; — caches, retries, and security tooling all have to guess.&lt;/p&gt;
&lt;p&gt;QUERY closes that gap with a small, carefully designed verb: safe, idempotent, cacheable, and allowed to carry a body. After more than a decade of drafts, &lt;a href="https://www.rfc-editor.org/rfc/rfc10008.html" target="_blank" rel="noopener noreferrer"&gt;RFC 10008&lt;/a&gt;
makes that contract official. If you maintain search or filter endpoints that never belonged in a URI, it is time to start planning for QUERY — especially on service-to-service paths you control, before you bet a public browser API on every gateway in the path understanding the verb.&lt;/p&gt;</description></item><item><title>.NET 5 to 10: features per release</title><link>https://blog-test.funkysi1701.com/posts/2026/dotnet-5-to-10-features/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 29 Jun 2026 18:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/dotnet-5-to-10-features/</guid><category term="DotNet">DotNet</category><category term=".NET5">.NET5</category><category term=".NET6">.NET6</category><category term=".NET7">.NET7</category><category term=".NET8">.NET8</category><category term=".NET9">.NET9</category><category term=".NET10">.NET10</category><category term="C-Sharp">C-Sharp</category><category term="Blazor">Blazor</category><category term="ASP.NETCore">ASP.NETCore</category><category term="VisualStudio">VisualStudio</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/dotnet-5-to-10-features.png"/><description>&lt;p&gt;Every November, &lt;a href="https://www.dotnetconf.net/" target="_blank" rel="noopener noreferrer"&gt;.NET Conf&lt;/a&gt;
brings a new major release of .NET. If you have been building on the platform since the early 2020s, you have watched the ecosystem move from &amp;ldquo;.NET Core&amp;rdquo; to a single, unified .NET — and pick up minimal APIs, Native AOT, Blazor full stack, Aspire, and a steady stream of C# language improvements along the way.&lt;/p&gt;
&lt;p&gt;This post is a guided tour of what landed in each major version from &lt;strong&gt;.NET 5&lt;/strong&gt; through &lt;strong&gt;.NET 10&lt;/strong&gt;. It is not exhaustive — Microsoft ships hundreds of changes per release — but it should help you remember which version introduced what, and where to dig deeper.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Released&lt;/th&gt;
&lt;th&gt;Support type&lt;/th&gt;
&lt;th&gt;C# version&lt;/th&gt;
&lt;th&gt;Status (June 2026)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.NET 5&lt;/td&gt;
&lt;td&gt;Nov 2020&lt;/td&gt;
&lt;td&gt;STS (18 months)&lt;/td&gt;
&lt;td&gt;C# 9&lt;/td&gt;
&lt;td&gt;End of support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 6&lt;/td&gt;
&lt;td&gt;Nov 2021&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LTS&lt;/strong&gt; (3 years)&lt;/td&gt;
&lt;td&gt;C# 10&lt;/td&gt;
&lt;td&gt;End of support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 7&lt;/td&gt;
&lt;td&gt;Nov 2022&lt;/td&gt;
&lt;td&gt;STS (18 months)&lt;/td&gt;
&lt;td&gt;C# 11&lt;/td&gt;
&lt;td&gt;End of support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 8&lt;/td&gt;
&lt;td&gt;Nov 2023&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LTS&lt;/strong&gt; (3 years)&lt;/td&gt;
&lt;td&gt;C# 12&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 9&lt;/td&gt;
&lt;td&gt;Nov 2024&lt;/td&gt;
&lt;td&gt;STS (2 years)&lt;/td&gt;
&lt;td&gt;C# 13&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 10&lt;/td&gt;
&lt;td&gt;Nov 2025&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LTS&lt;/strong&gt; (3 years)&lt;/td&gt;
&lt;td&gt;C# 14&lt;/td&gt;
&lt;td&gt;Current LTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 11&lt;/td&gt;
&lt;td&gt;Nov 2026&lt;/td&gt;
&lt;td&gt;Preview&lt;/td&gt;
&lt;td&gt;C# 15&lt;/td&gt;
&lt;td&gt;Preview Until Nov 2026 then STS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For the full release schedule and patch versions, see the official &lt;a href="https://learn.microsoft.com/en-us/dotnet/core/releases-and-support" target="_blank" rel="noopener noreferrer"&gt;.NET releases&lt;/a&gt;
documentation.&lt;/p&gt;
&lt;h2 id="net-5--november-2020"&gt;.NET 5 — November 2020&lt;a class="anchor ms-1" href="#net-5--november-2020" aria-label="Permalink: .NET 5 — November 2020"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.NET 5 was the first release after the &amp;ldquo;Core&amp;rdquo; branding was dropped. Version 4.x was skipped deliberately so nobody confused it with .NET Framework 4.x. The message was clear: this is the main implementation of .NET going forward, not a side project.&lt;/p&gt;
&lt;h3 id="platform-and-runtime"&gt;Platform and runtime&lt;a class="anchor ms-1" href="#platform-and-runtime" aria-label="Permalink: Platform and runtime"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unified vision&lt;/strong&gt; — one BCL and runtime targeting cloud, desktop, web, mobile, and IoT (the full unification completed in .NET 6).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single-file applications&lt;/strong&gt; and improved &lt;strong&gt;app trimming&lt;/strong&gt; for smaller deployments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ClickOnce&lt;/strong&gt; publishing for .NET (Windows).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ARM64&lt;/strong&gt; support on Windows.&lt;/li&gt;
&lt;li&gt;Performance work across the runtime, GC, and networking stack.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="c-9"&gt;C# 9&lt;a class="anchor ms-1" href="#c-9" aria-label="Permalink: C# 9"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;C# 9 shipped alongside .NET 5 and brought several features that are now everyday tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Records&lt;/strong&gt; — reference types with value-based equality and &lt;code&gt;with&lt;/code&gt; expressions for non-destructive mutation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Init-only setters&lt;/strong&gt; — immutable object initialisation without verbose constructors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Top-level statements&lt;/strong&gt; — less boilerplate in small console apps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pattern matching&lt;/strong&gt; — relational patterns (&lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt;) and improved &lt;code&gt;switch&lt;/code&gt; expressions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source generators&lt;/strong&gt; — compile-time code generation (the foundation for later JSON and logging generators).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="libraries-and-frameworks"&gt;Libraries and frameworks&lt;a class="anchor ms-1" href="#libraries-and-frameworks" aria-label="Permalink: Libraries and frameworks"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EF Core 5&lt;/strong&gt; — split queries, table-per-entity (TPE) mapping, and Cosmos DB improvements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ASP.NET Core&lt;/strong&gt; in the 5.x line — gRPC improvements, HTTP/2 and HTTP/3 groundwork, and Blazor WebAssembly performance gains.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System.Text.Json&lt;/strong&gt; — constructor and parameterised constructor support, &lt;code&gt;[JsonIgnore]&lt;/code&gt; on properties, and better options for ignoring cycles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.NET 5 reached end of support in May 2022. If you still have projects on it, plan an upgrade — there are no security patches.&lt;/p&gt;
&lt;h2 id="net-6--november-2021-lts"&gt;.NET 6 — November 2021 (LTS)&lt;a class="anchor ms-1" href="#net-6--november-2021-lts" aria-label="Permalink: .NET 6 — November 2021 (LTS)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.NET 6 delivered on the unification promise: one SDK, one base class library, and one runtime across mobile, desktop, IoT, and cloud. It was an &lt;strong&gt;LTS&lt;/strong&gt; release and became the baseline many teams standardised on.&lt;/p&gt;
&lt;h3 id="developer-experience"&gt;Developer experience&lt;a class="anchor ms-1" href="#developer-experience" aria-label="Permalink: Developer experience"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hot reload&lt;/strong&gt; in Visual Studio 2022 and &lt;code&gt;dotnet watch&lt;/code&gt; — edit code and see changes without a full restart.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal APIs&lt;/strong&gt; — build HTTP APIs with far less ceremony than traditional controllers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SDK workloads&lt;/strong&gt; — optional components (MAUI, Blazor WebAssembly AOT, and others) install via &lt;code&gt;dotnet workload&lt;/code&gt; instead of bloating the default SDK.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project templates modernised&lt;/strong&gt; — top-level statements, file-scoped namespaces, nullable reference types, and &lt;code&gt;async Main&lt;/code&gt; in new projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="c-10"&gt;C# 10&lt;a class="anchor ms-1" href="#c-10" aria-label="Permalink: C# 10"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;global using&lt;/code&gt; directives&lt;/li&gt;
&lt;li&gt;File-scoped namespaces&lt;/li&gt;
&lt;li&gt;Record structs&lt;/li&gt;
&lt;li&gt;Improved interpolated strings and constant interpolated strings&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AsyncMethodBuilder&lt;/code&gt; attribute for custom async method builders&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="runtime-and-libraries"&gt;Runtime and libraries&lt;a class="anchor ms-1" href="#runtime-and-libraries" aria-label="Permalink: Runtime and libraries"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DateOnly&lt;/strong&gt; and &lt;strong&gt;TimeOnly&lt;/strong&gt; — separate date and time types without carrying a full &lt;code&gt;DateTime&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PriorityQueue&amp;lt;TElement, TPriority&amp;gt;&lt;/strong&gt; — a built-in min-heap.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System.Text.Json&lt;/strong&gt; source generator, writeable &lt;strong&gt;JsonNode&lt;/strong&gt; DOM, and &lt;code&gt;IAsyncEnumerable&lt;/code&gt; serialisation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP/3&lt;/strong&gt; preview support via QUIC.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt; metrics APIs in &lt;code&gt;System.Diagnostics.Metrics&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FileStream&lt;/strong&gt; rewrite for better async performance on Windows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arm64&lt;/strong&gt; support for macOS (&amp;ldquo;Apple Silicon&amp;rdquo;) and Windows, with side-by-side x64 and Arm64 installs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aspnet-core-6"&gt;ASP.NET Core 6&lt;a class="anchor ms-1" href="#aspnet-core-6" aria-label="Permalink: ASP.NET Core 6"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Minimal APIs as a first-class style for microservices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blazor&lt;/strong&gt; components renderable from JavaScript; AOT compilation for Blazor WebAssembly.&lt;/li&gt;
&lt;li&gt;Improved gRPC and SignalR performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="net-maui"&gt;.NET MAUI&lt;a class="anchor ms-1" href="#net-maui" aria-label="Permalink: .NET MAUI"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;.NET Multi-platform App UI arrived in preview with .NET 6 — one codebase for Android, iOS, macOS, and Windows native apps. GA followed in 2022.&lt;/p&gt;
&lt;p&gt;.NET 6 LTS ended in November 2024.&lt;/p&gt;
&lt;h2 id="net-7--november-2022"&gt;.NET 7 — November 2022&lt;a class="anchor ms-1" href="#net-7--november-2022" aria-label="Permalink: .NET 7 — November 2022"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.NET 7 was a &lt;strong&gt;standard-term support&lt;/strong&gt; release focused heavily on performance, cloud-native patterns, and polishing the developer experience. I wrote about &lt;a href="https://blog-test.funkysi1701.com/posts/2022/dotnet7/"&gt;upgrading to .NET 7&lt;/a&gt;
at the time — mostly smooth, with a few surprises around AutoMapper and EF Core triggers.&lt;/p&gt;
&lt;h3 id="c-11"&gt;C# 11&lt;a class="anchor ms-1" href="#c-11" aria-label="Permalink: C# 11"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Raw string literals&lt;/strong&gt; — multi-line strings without escape-character pain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;required&lt;/code&gt; members&lt;/strong&gt; — enforce initialisation at compile time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generic math&lt;/strong&gt; — static abstract interface members for numeric generics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;List patterns&lt;/strong&gt; — &lt;code&gt;if (list is [var first, .., var last])&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UTF-8 string literals&lt;/strong&gt; — &lt;code&gt;u8&lt;/code&gt; suffix for byte-oriented APIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aspnet-core-7"&gt;ASP.NET Core 7&lt;a class="anchor ms-1" href="#aspnet-core-7" aria-label="Permalink: ASP.NET Core 7"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rate limiting middleware&lt;/strong&gt; — built-in protection against abuse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output caching&lt;/strong&gt; — cache entire responses at the framework level.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal API improvements&lt;/strong&gt; — route groups, typed results, and filters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native AOT&lt;/strong&gt; for console apps — smaller, faster-starting binaries (ASP.NET Core AOT came in .NET 8).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="performance-and-tooling"&gt;Performance and tooling&lt;a class="anchor ms-1" href="#performance-and-tooling" aria-label="Permalink: Performance and tooling"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Continued JIT and GC improvements; &lt;strong&gt;Native AOT&lt;/strong&gt; publishing matured.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regex source generator&lt;/strong&gt; for compile-time pattern compilation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Library multi-targeting&lt;/strong&gt; and package validation tooling for NuGet authors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.NET 7 reached end of support in May 2024.&lt;/p&gt;
&lt;h2 id="net-8--november-2023-lts"&gt;.NET 8 — November 2023 (LTS)&lt;a class="anchor ms-1" href="#net-8--november-2023-lts" aria-label="Permalink: .NET 8 — November 2023 (LTS)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.NET 8 is the current-generation &lt;strong&gt;LTS&lt;/strong&gt; baseline for many production workloads (supported until November 2026). It is the release where cloud-native tooling, Native AOT for web apps, and modern C# really clicked together.&lt;/p&gt;
&lt;h3 id="c-12"&gt;C# 12&lt;a class="anchor ms-1" href="#c-12" aria-label="Permalink: C# 12"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Primary constructors&lt;/strong&gt; — declare constructor parameters on the type declaration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collection expressions&lt;/strong&gt; — &lt;code&gt;[1, 2, 3]&lt;/code&gt; syntax for arrays, spans, and lists.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alias any type&lt;/strong&gt; — &lt;code&gt;using Point = (int X, int Y);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Default lambda parameters&lt;/strong&gt; — optional parameters in lambdas.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aspnet-core-8"&gt;ASP.NET Core 8&lt;a class="anchor ms-1" href="#aspnet-core-8" aria-label="Permalink: ASP.NET Core 8"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blazor full stack&lt;/strong&gt; — server-side rendering, streaming rendering, and enhanced interactivity models in one framework.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native AOT&lt;/strong&gt; for ASP.NET Core — ahead-of-time compilation for web workloads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keyed dependency injection&lt;/strong&gt; — register and resolve multiple implementations of the same interface by key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frozen collections&lt;/strong&gt; — optimised read-only collections for hot paths.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TimeProvider&lt;/strong&gt; — abstract time for testable code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="net-aspire-now-just-called-aspire"&gt;.NET Aspire (now just called Aspire)&lt;a class="anchor ms-1" href="#net-aspire-now-just-called-aspire" aria-label="Permalink: .NET Aspire (now just called Aspire)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/aspire/"&gt;.NET Aspire&lt;/a&gt;
launched in preview with .NET 8 — an opinionated stack for observable, distributed applications. AppHost orchestrates dependencies; ServiceDefaults wire up OpenTelemetry, health checks, and resilience. I have been using it for local microservice development and it removes a lot of port-and-connection-string drudgery. In 2025 .Net Aspire was rebranded to Aspire and version 13 was released (don&amp;rsquo;t ask why 13, but I believe it was so it was no longer tied to .NET releases)&lt;/p&gt;
&lt;h3 id="other-highlights"&gt;Other highlights&lt;a class="anchor ms-1" href="#other-highlights" aria-label="Permalink: Other highlights"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EF Core 8&lt;/strong&gt; — complex types, primitive collections, JSON column mapping, &lt;code&gt;HierarchyId&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NuGet Audit&lt;/strong&gt; — warnings when packages have known vulnerabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows Forms and WPF&lt;/strong&gt; improvements — DPI, data binding, and hardware acceleration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source generators&lt;/strong&gt; for COM interop and configuration binding.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="net-9--november-2024"&gt;.NET 9 — November 2024&lt;a class="anchor ms-1" href="#net-9--november-2024" aria-label="Permalink: .NET 9 — November 2024"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.NET 9 continued the annual cadence with performance, AI integration, and polish across the stack. I covered several highlights in my &lt;a href="https://blog-test.funkysi1701.com/posts/2024/dotnet9/"&gt;.NET 9 post&lt;/a&gt;
when it shipped.&lt;/p&gt;
&lt;h3 id="c-13"&gt;C# 13&lt;a class="anchor ms-1" href="#c-13" aria-label="Permalink: C# 13"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;params&lt;/code&gt; collections&lt;/strong&gt; — &lt;code&gt;params&lt;/code&gt; works with &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code&gt;ReadOnlySpan&amp;lt;T&amp;gt;&lt;/code&gt;, and collection types beyond arrays.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lock&lt;/code&gt; on &lt;code&gt;System.Object&lt;/code&gt;&lt;/strong&gt; — the &lt;code&gt;lock&lt;/code&gt; statement can use more types safely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partial properties and indexers&lt;/strong&gt; — split declarations across files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Escape sequence &lt;code&gt;\e&lt;/code&gt;&lt;/strong&gt; for the ESC character.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="platform-and-libraries"&gt;Platform and libraries&lt;a class="anchor ms-1" href="#platform-and-libraries" aria-label="Permalink: Platform and libraries"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt; — runtime, GC, and JIT improvements across the board; the team publishes detailed benchmark posts each release.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI abstractions&lt;/strong&gt; — &lt;code&gt;Microsoft.Extensions.AI&lt;/code&gt; packages unify access to language models and embeddings from different providers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NuGet Audit&lt;/strong&gt; defaults to reporting &lt;strong&gt;transitive&lt;/strong&gt; dependency vulnerabilities (opt back to direct-only with &lt;code&gt;&amp;lt;NuGetAuditMode&amp;gt;direct&amp;lt;/NuGetAuditMode&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt; enhancements and better observability defaults.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aspnet-core-9-and-blazor"&gt;ASP.NET Core 9 and Blazor&lt;a class="anchor ms-1" href="#aspnet-core-9-and-blazor" aria-label="Permalink: ASP.NET Core 9 and Blazor"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;MapStaticAssets()&lt;/code&gt;&lt;/strong&gt; — fingerprinted, cache-friendly static files replace &lt;code&gt;UseStaticFiles()&lt;/code&gt; for Blazor and modern web apps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blazor&lt;/strong&gt; component state persistence, improved form handling, and better WebAssembly performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.NET Aspire 9&lt;/strong&gt; — dashboard improvements, deployment tooling, and more community integrations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;.NET 9 is &lt;strong&gt;standard-term support&lt;/strong&gt; until November 2026.&lt;/p&gt;
&lt;h2 id="net-10--november-2025-lts"&gt;.NET 10 — November 2025 (LTS)&lt;a class="anchor ms-1" href="#net-10--november-2025-lts" aria-label="Permalink: .NET 10 — November 2025 (LTS)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.NET 10 is the current &lt;strong&gt;LTS&lt;/strong&gt; release (supported until November 2028). If you are choosing a version for a new project in 2026, this is the long-term bet.&lt;/p&gt;
&lt;h3 id="c-14"&gt;C# 14&lt;a class="anchor ms-1" href="#c-14" aria-label="Permalink: C# 14"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Field-backed properties&lt;/strong&gt; — use the &lt;code&gt;field&lt;/code&gt; keyword when you outgrow auto-properties.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;nameof&lt;/code&gt; for unbound generics&lt;/strong&gt; — e.g. &lt;code&gt;nameof(List&amp;lt;&amp;gt;)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implicit &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; conversions&lt;/strong&gt; — less ceremony at API boundaries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ref&lt;/code&gt;/&lt;code&gt;out&lt;/code&gt;/&lt;code&gt;in&lt;/code&gt; in lambdas&lt;/strong&gt; without explicit parameter types.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extension blocks&lt;/strong&gt; — static extension methods and properties in a dedicated syntax.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Null-conditional assignment&lt;/strong&gt; (&lt;code&gt;?.=&lt;/code&gt;) and user-defined compound assignment operators.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="runtime-and-libraries-1"&gt;Runtime and libraries&lt;a class="anchor ms-1" href="#runtime-and-libraries-1" aria-label="Permalink: Runtime and libraries"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JIT improvements&lt;/strong&gt; — better inlining, devirtualisation, and loop inversion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AVX10.2&lt;/strong&gt; support for SIMD workloads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native AOT&lt;/strong&gt; enhancements and improved struct argument code generation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSON&lt;/strong&gt; — stricter serialisation options, &lt;code&gt;PipeReader&lt;/code&gt; support, duplicate property handling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Post-quantum cryptography&lt;/strong&gt; — expanded ML-DSA and related APIs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebSocketStream&lt;/code&gt;&lt;/strong&gt; — simpler WebSocket usage; TLS 1.3 on macOS clients.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="sdk-and-tooling"&gt;SDK and tooling&lt;a class="anchor ms-1" href="#sdk-and-tooling" aria-label="Permalink: SDK and tooling"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;dotnet test&lt;/code&gt;&lt;/strong&gt; integrates &lt;strong&gt;Microsoft.Testing.Platform&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Container images from console apps&lt;/strong&gt; without a separate Dockerfile in simple scenarios.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;dotnet tool exec&lt;/code&gt;&lt;/strong&gt; for one-shot tool runs.&lt;/li&gt;
&lt;li&gt;Native shell tab-completion scripts for the CLI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aspnet-core-10-and-blazor"&gt;ASP.NET Core 10 and Blazor&lt;a class="anchor ms-1" href="#aspnet-core-10-and-blazor" aria-label="Permalink: ASP.NET Core 10 and Blazor"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Blazor WebAssembly &lt;strong&gt;preloading&lt;/strong&gt; and automatic memory pool eviction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Passkey support&lt;/strong&gt; for ASP.NET Core Identity.&lt;/li&gt;
&lt;li&gt;OpenAPI and minimal API improvements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One breaking change caught me when upgrading a Blazor WebAssembly app: &lt;strong&gt;HttpClient response streaming is enabled by default&lt;/strong&gt;, which broke synchronous &lt;code&gt;Stream.Read&lt;/code&gt; calls in generated API clients. I wrote about the fix in &lt;a href="https://blog-test.funkysi1701.com/posts/2025/blazor-and-dotnet10/"&gt;Blazor and .NET 10&lt;/a&gt;
— either opt out with &lt;code&gt;&amp;lt;WasmEnableStreamingResponse&amp;gt;false&amp;lt;/WasmEnableStreamingResponse&amp;gt;&lt;/code&gt; or move to async reads.&lt;/p&gt;
&lt;h3 id="ef-core-10-maui-and-desktop"&gt;EF Core 10, MAUI, and desktop&lt;a class="anchor ms-1" href="#ef-core-10-maui-and-desktop" aria-label="Permalink: EF Core 10, MAUI, and desktop"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EF Core 10&lt;/strong&gt; — named query filters, Cosmos DB improvements, and LINQ performance work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.NET MAUI 10&lt;/strong&gt; — multi-file MediaPicker, WebView interception, Android API 35/36 support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows Forms and WPF&lt;/strong&gt; — continued quality and Fluent-style updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-choose-a-version-in-2026"&gt;How to choose a version in 2026&lt;a class="anchor ms-1" href="#how-to-choose-a-version-in-2026" aria-label="Permalink: How to choose a version in 2026"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New production app, minimise upgrade churn&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;.NET 10 LTS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Existing app on .NET 8 LTS with no pressing need&lt;/td&gt;
&lt;td&gt;Stay on 8 until you are ready; both 8 and 10 are supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Experimenting with the latest features&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;.NET 9&lt;/strong&gt; or &lt;strong&gt;.NET 10&lt;/strong&gt; — check STS/LTS dates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy maintenance&lt;/td&gt;
&lt;td&gt;Upgrade anything still on 5, 6, or 7 — they are all end-of-life&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Microsoft&amp;rsquo;s guidance has shifted over the years: LTS releases (6, 8, 10) alternate with STS releases (5, 7, 9) on an annual November cadence. STS now lasts two years; LTS lasts three. Remember there is no difference in quality between a LTS and STS release, it is only the support window that is different.&lt;/p&gt;
&lt;h2 id="further-reading"&gt;Further reading&lt;a class="anchor ms-1" href="#further-reading" aria-label="Permalink: Further reading"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="official-docs"&gt;Official docs&lt;a class="anchor ms-1" href="#official-docs" aria-label="Permalink: Official docs"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download" target="_blank" rel="noopener noreferrer"&gt;.NET download&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/core/whats-new/" target="_blank" rel="noopener noreferrer"&gt;What&amp;rsquo;s new in each .NET version&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history" target="_blank" rel="noopener noreferrer"&gt;C# language version history&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="on-this-blog"&gt;On this blog&lt;a class="anchor ms-1" href="#on-this-blog" aria-label="Permalink: On this blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/dotnet9/"&gt;.NET 9&lt;/a&gt;
and &lt;a href="https://blog-test.funkysi1701.com/posts/2025/blazor-and-dotnet10/"&gt;Blazor and .NET 10&lt;/a&gt;
— deeper dives from recent releases&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/whats-new-csharp/"&gt;What&amp;rsquo;s new with C#&lt;/a&gt;
— language features that shipped alongside the runtime&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/aspire/"&gt;Getting started with Aspire&lt;/a&gt;
and &lt;a href="https://blog-test.funkysi1701.com/posts/2025/adding-elasticsearch-with-aspire/"&gt;Adding Elasticsearch with Aspire&lt;/a&gt;
— cloud-native .NET after you pick a target framework&lt;/li&gt;
&lt;li&gt;Prefer a short curated path? See &lt;a href="https://blog-test.funkysi1701.com/start-here/"&gt;Start Here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have been on the platform since .NET 5, you have lived through the best decade of .NET since the original framework shipped.&lt;/p&gt;</description></item><item><title>Portfolio: Azure, AI, and dev tools</title><link>https://blog-test.funkysi1701.com/projects/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 22 Jun 2026 21:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/projects/</guid><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/projects/semantic-search.png"/><description>&lt;h2 id="featured-projects-heading"&gt;Featured Projects&lt;/h2&gt;
&lt;p class="projects-featured-intro"&gt;Three live Azure workloads I own end-to-end — CI/CD static delivery, AI-backed search on real content, and full-stack Blazor with actual users. &lt;/p&gt;
&lt;div class="projects-featured" role="region" aria-labelledby="featured-projects-heading"&gt;
&lt;div class="projects-featured-grid"&gt;
&lt;article class="projects-featured-card"&gt;
&lt;h3 class="projects-featured-title"&gt;&lt;a href="https://www.episodeatlas.com" target="_blank" rel="noopener noreferrer"&gt;🔧 Episode Atlas&lt;/a&gt;&lt;/h3&gt;
&lt;p class="projects-featured-hook"&gt;Track TV progress at scale with per-user state and cloud-backed data.&lt;/p&gt;
&lt;a href="https://www.episodeatlas.com" target="_blank" rel="noopener noreferrer"&gt;&lt;img src="https://blog-test.funkysi1701.com/images/projects/episode-atlas.png" alt="Episode Atlas: TV episode tracking app" width="800" height="450" loading="lazy"&gt;&lt;/a&gt;
&lt;p class="projects-featured-meta"&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Per-user episode lists, “last watched” markers, and curated metadata links — so long-running franchises stay manageable.&lt;/p&gt;
&lt;p class="projects-featured-meta"&gt;&lt;strong&gt;Tech used:&lt;/strong&gt; .NET Blazor, Azure Static Web Apps, Azure Functions, Cosmos DB, GitHub auth.&lt;/p&gt;
&lt;p class="projects-featured-impressive"&gt;&lt;strong&gt;Why it’s impressive:&lt;/strong&gt; Demonstrates scalable data modelling and cloud-first architecture for user-driven applications.&lt;/p&gt;
&lt;div class="projects-signals" role="group" aria-label="Engineering signals"&gt;&lt;span class="projects-signal"&gt;Deployed to Azure&lt;/span&gt;&lt;span class="projects-signal"&gt;Implements authentication / APIs / caching&lt;/span&gt;&lt;/div&gt;
&lt;p class="projects-featured-outcome"&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; Turned a personal “where was I in 900+ episodes?” problem into a maintainable multi-tenant pattern for identity, persistence, and UX for ongoing shows.&lt;/p&gt;
&lt;p class="projects-featured-links"&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.episodeatlas.com" target="_blank" rel="noopener noreferrer"&gt;episodeatlas.com&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;article class="projects-featured-card"&gt;
&lt;h3 class="projects-featured-title"&gt;&lt;a href="https://search.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;🔧 Semantic Search&lt;/a&gt;&lt;/h3&gt;
&lt;p class="projects-featured-hook"&gt;AI-powered natural language search for discovering content beyond keywords.&lt;/p&gt;
&lt;a href="https://search.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;&lt;img src="https://blog-test.funkysi1701.com/images/projects/semantic-search.png" alt="Semantic Search: natural-language blog search" width="800" height="450" loading="lazy"&gt;&lt;/a&gt;
&lt;p class="projects-featured-meta"&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Accepts conversational queries, retrieves meaningfully related posts, and surfaces them alongside the site’s JSON index search.&lt;/p&gt;
&lt;p class="projects-featured-meta"&gt;&lt;strong&gt;Tech used:&lt;/strong&gt; .NET, Azure, Cosmos DB, OpenAI.&lt;/p&gt;
&lt;p class="projects-featured-impressive"&gt;&lt;strong&gt;Why it’s impressive:&lt;/strong&gt; Showcases practical LLM integration in .NET beyond basic chat interfaces.&lt;/p&gt;
&lt;div class="projects-signals" role="group" aria-label="Engineering signals"&gt;&lt;span class="projects-signal"&gt;Deployed to Azure&lt;/span&gt;&lt;span class="projects-signal"&gt;Designed with clean architecture&lt;/span&gt;&lt;/div&gt;
&lt;p class="projects-featured-outcome"&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; Explored how vector-style retrieval and operational concerns (cost, latency, content freshness) fit next to a static Hugo site without compromising the authoring workflow.&lt;/p&gt;
&lt;p class="projects-featured-links"&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://search.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;search.funkysi1701.com&lt;/a&gt; · linked from &lt;a href="https://blog-test.funkysi1701.com/search/"&gt;Search&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;article class="projects-featured-card"&gt;
&lt;h3 class="projects-featured-title"&gt;&lt;a href="https://www.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;🔧 Blog Platform&lt;/a&gt;&lt;/h3&gt;
&lt;p class="projects-featured-hook"&gt;Technical blog on Azure with CI/CD—fast static pages, search, and comments without babysitting an app server.&lt;/p&gt;
&lt;a href="https://www.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;&lt;img src="https://blog-test.funkysi1701.com/images/projects/blog.png" alt="Blog homepage: navigation and latest posts" width="800" height="450" loading="lazy"&gt;&lt;/a&gt;
&lt;p class="projects-featured-meta"&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Publishes posts, generates RSS and a JSON search index, integrates Giscus for discussions, and deploys on every merge.&lt;/p&gt;
&lt;p class="projects-featured-meta"&gt;&lt;strong&gt;Tech used:&lt;/strong&gt; Hugo, GitHub Actions, Azure Static Web Apps, Giscus.&lt;/p&gt;
&lt;p class="projects-featured-impressive"&gt;&lt;strong&gt;Why it’s impressive:&lt;/strong&gt; Highlights modern static-first architecture with automated deployment pipelines.&lt;/p&gt;
&lt;div class="projects-signals" role="group" aria-label="Engineering signals"&gt;&lt;span class="projects-signal"&gt;Deployed to Azure&lt;/span&gt;&lt;span class="projects-signal"&gt;CI/CD via GitHub Actions&lt;/span&gt;&lt;/div&gt;
&lt;p class="projects-featured-outcome"&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; Demonstrates a production-shaped static pipeline — preview builds, repeatable deploys, and content-driven SEO — suitable as a reference architecture for docs and marketing sites.&lt;/p&gt;
&lt;p class="projects-featured-links"&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/funkysi1701/funkysi1701.github.io" target="_blank" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="-cloud--production-systems"&gt;💼 Cloud &amp; Production Systems&lt;a class="anchor ms-1" href="#-cloud--production-systems" aria-label="Permalink: 💼 Cloud &amp;amp; Production Systems"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The featured trio — &lt;strong&gt;Episode Atlas&lt;/strong&gt;, &lt;strong&gt;this blog&lt;/strong&gt; (Hugo on Azure), and &lt;strong&gt;Semantic Search&lt;/strong&gt; (&lt;a href="https://search.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;search.funkysi1701.com&lt;/a&gt;
) — is fully described in &lt;strong&gt;&lt;a href="#featured-projects-heading"&gt;Featured Projects&lt;/a&gt;
&lt;/strong&gt; above and not repeated here. Below is the rest of the catalogue by category.&lt;/p&gt;
&lt;h3 id="-thorne-pentecostal-church"&gt;🔧 Thorne Pentecostal Church&lt;a class="anchor ms-1" href="#-thorne-pentecostal-church" aria-label="Permalink: 🔧 Thorne Pentecostal Church"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Dependable church presence online—clear for newcomers, simple for volunteers to keep current.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.thornepentecostalchurch.co.uk" target="_blank" rel="noopener noreferrer"&gt;
&lt;img class="img-fluid" alt="Thorne Pentecostal Church website homepage" src="https://blog-test.funkysi1701.com/images/projects/thorne-pentecostal-church.png" loading="lazy"
width="1280" height="800"
/&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does&lt;/strong&gt; — Presents service times, beliefs, and visitor information with a simple structure so members and newcomers get answers in one place.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tech used&lt;/strong&gt; — HTML/CSS, Azure Static Web Apps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it’s impressive&lt;/strong&gt; — Demonstrates proportionate engineering: production-grade static hosting and clear information architecture for stakeholders who need reliability, not complexity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Engineering signals:&lt;/strong&gt; Deployed to Azure · CI/CD via GitHub Actions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; Delivered a first web presence focused on clarity and sustainability so non-developers can keep content current with minimal process overhead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.thornepentecostalchurch.co.uk" target="_blank" rel="noopener noreferrer"&gt;Thorne Pentecostal Church&lt;/a&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="-tools--utilities"&gt;🛠 Tools &amp; Utilities&lt;a class="anchor ms-1" href="#-tools--utilities" aria-label="Permalink: 🛠 Tools &amp;amp; Utilities"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="-mandelbrot-generator"&gt;🔧 Mandelbrot Generator&lt;a class="anchor ms-1" href="#-mandelbrot-generator" aria-label="Permalink: 🔧 Mandelbrot Generator"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Interactive Mandelbrot exploration in the browser—smooth zoom, pure WASM, zero server-side rendering cost.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mandelbrot.funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;
&lt;img class="img-fluid" alt="Mandelbrot Generator: fractal view in the browser" src="https://blog-test.funkysi1701.com/images/projects/mandelbrot.png" loading="lazy"
width="1280" height="800"
/&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does&lt;/strong&gt; — Renders the Mandelbrot set in the client with zoom for desktop and mobile, demonstrating CPU-bound UI work in WASM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tech used&lt;/strong&gt; — .NET Blazor WebAssembly, Azure Static Web Apps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it’s impressive&lt;/strong&gt; — Demonstrates client-side compute discipline in Blazor WASM: rich, interactive UI with predictable cost because heavy work never hits the server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Engineering signals:&lt;/strong&gt; Deployed to Azure · Designed with clean architecture&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; Built the tool to stress-test interactive Blazor WASM performance and touch UX patterns — a small codebase that still informs decisions about heavier client-side workloads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://mandelbrot.funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;Mandelbrot Generator&lt;/a&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="-ongoing-exploration"&gt;💡 Ongoing exploration&lt;a class="anchor ms-1" href="#-ongoing-exploration" aria-label="Permalink: 💡 Ongoing exploration"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Areas I keep hands-on with outside these shipped projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;.NET Aspire&lt;/strong&gt; — Cloud-native composition and local dev parity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; — Orchestration and service boundaries&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elasticsearch&lt;/strong&gt; — Search and analytics stacks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Functions&lt;/strong&gt; — Event-driven and serverless patterns&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DevOps automation&lt;/strong&gt; — CI/CD, IaC, and release hygiene&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="-collaborate-with-me"&gt;🤝 Collaborate With Me&lt;a class="anchor ms-1" href="#-collaborate-with-me" aria-label="Permalink: 🤝 Collaborate With Me"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Interested in collaborating on a project or discussing an idea?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/contact/"&gt;Contact Me&lt;/a&gt;
— Get in touch&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
— Code and experiments&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linkedin.com/in/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
— Connect professionally&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="-more-resources"&gt;📚 More resources&lt;a class="anchor ms-1" href="#-more-resources" aria-label="Permalink: 📚 More resources"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/tools-and-resources/"&gt;Tools &amp;amp; Resources&lt;/a&gt;
— Recommended development tools&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/about/"&gt;About Me&lt;/a&gt;
— Background and experience&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/"&gt;Blog Posts&lt;/a&gt;
— Technical writing&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Stay visible when made redundant</title><link>https://blog-test.funkysi1701.com/posts/2026/stay-visible-as-a-developer-when-you-are-made-redundant/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 22 Jun 2026 12:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/stay-visible-as-a-developer-when-you-are-made-redundant/</guid><category term="Career">Career</category><category term="Redundancy">Redundancy</category><category term="Networking">Networking</category><category term="Blogging">Blogging</category><category term="SideProjects">SideProjects</category><category term="Conferences">Conferences</category><category term="Developer">Developer</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/stay-visible-redundancy.png"/><description>&lt;p&gt;Sadly earlier this year I was made redundant from my Software Developer job. Looking for a new job has not been fun, but a few common themes have emerged that I wanted to share. My hope is that these will help others to put things in place that may help them in the future.&lt;/p&gt;
&lt;h2 id="go-to-events-and-meet-people"&gt;Go to events and meet people&lt;a class="anchor ms-1" href="#go-to-events-and-meet-people" aria-label="Permalink: Go to events and meet people"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Something I have said often is that I enjoy going to events or conferences, like &lt;a href="https://blog-test.funkysi1701.com/posts/2026/ndc-london-2026"&gt;NDC London&lt;/a&gt;
. These are great places to hear interesting talks, however that is not all they are good for. When you are at a conference or user group you are in a room full of like-minded people, each of them has unique experiences of being a software developer.&lt;/p&gt;
&lt;p&gt;I am not very good at networking, I tend to stand in the corner or look awkward. However the more of these events I go to the better I get. Even if you only talk to one new person, that is one more person that you have spoken to. Want an advantage in meeting people? Volunteer. If you are a volunteer at an event, you will need to interact with other people, you may need to help direct people or assist one of the speakers. I have found this gives me a tiny bit more confidence to go and start speaking with someone or ask a question. Check out my &lt;a href="https://blog-test.funkysi1701.com/posts/2025/volunteering-at-ndc/"&gt;Volunteering at NDC&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;User Groups often have the same people coming week after week, take advantage of this and be one of those people as well. You will start to get noticed and remembered even if you barely speak to anyone. For me I don&amp;rsquo;t have any really local user groups, however I am enjoying spending time at &lt;a href="https://www.meetup.com/leeds-sharp/" target="_blank" rel="noopener noreferrer"&gt;LeedsSharp&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;If you genuinely had a good conversation with someone, find them on LinkedIn (or other social media) and send them a quick &amp;ldquo;It was nice chatting with you&amp;rdquo; message, this helps solidify the connection and helps you remember it.&lt;/p&gt;
&lt;p&gt;So far during this job search I have met a recruiter who I would not have met without going to events, I have had jobs suggested to me to apply for that I would not have received otherwise, and one hiring manager is someone I have met previously at an event.&lt;/p&gt;
&lt;h2 id="build-a-blog-and-write-about-what-you-are-learning"&gt;Build a blog and write about what you are learning&lt;a class="anchor ms-1" href="#build-a-blog-and-write-about-what-you-are-learning" aria-label="Permalink: Build a blog and write about what you are learning"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Almost every interview I have had has featured a comment about my blog. Now building a blog is for the long game. If you are unemployed now and don&amp;rsquo;t have a blog this won&amp;rsquo;t help you today, but if you start one and write about your experiences a few times a year it may help you tomorrow.&lt;/p&gt;
&lt;p&gt;Back in 2014 when I started blogging I wasn&amp;rsquo;t even a Software Developer, I was just an IT guy at a small company and I wanted to write about some of the cool things I was learning. I kept writing, some years I wrote more than others, there have been some big gaps where I didn&amp;rsquo;t write anything. But somehow I keep coming back to it and writing a short piece about a new version of X or a conference I have been to, or a trend that is happening.&lt;/p&gt;
&lt;p&gt;My blog is a great talking point during interviews, it helps me talk about why I think sharing information with the community is so important, what technology I have used over the years, some of the things I have learnt. My blog is featured at the top of my CV, and hiring managers have said they love it.&lt;/p&gt;
&lt;p&gt;When redundancy hit, refreshing my CV and LinkedIn was one of the first practical jobs I did: update the headline, add recent projects, link to the blog and &lt;a href="https://blog-test.funkysi1701.com/projects"&gt;projects&lt;/a&gt;
page, and make sure nothing still implied I was in my old role. Mundane, yes — but recruiters and hiring managers check both before they ever speak to you.&lt;/p&gt;
&lt;p&gt;Today blogging isn&amp;rsquo;t the only way you can share your ideas. You could create videos, start a podcast, or have an active social media channel. I think the key is consistency, if you do a lot of it, it can easily look impressive if you look back after a few years. I personally prefer the well written blog post that I can refer back to, or search for again and again.&lt;/p&gt;
&lt;p&gt;Some ideas to get you started (but there are loads more):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What have you learnt today/this week&lt;/li&gt;
&lt;li&gt;What do you think about technology X&lt;/li&gt;
&lt;li&gt;How do you solve problem Y&lt;/li&gt;
&lt;li&gt;Compare two approaches to the same problem&lt;/li&gt;
&lt;li&gt;Your experience at a conference or meetup&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="build-side-projects"&gt;Build side projects&lt;a class="anchor ms-1" href="#build-side-projects" aria-label="Permalink: Build side projects"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Side projects are a great way to learn. You can create a side project with the goal of learning technology X, you can also blog about your journey, what problems you solved and what insights you gained from it.&lt;/p&gt;
&lt;p&gt;I personally feel there is a lot of value from getting your side project into the wild and letting users interact with it. Users will find your edge cases and ask questions you hadn&amp;rsquo;t considered. Publishing onto the internet is not free so consider your architecture carefully.&lt;/p&gt;
&lt;p&gt;What you can deploy depends on what you build. For simple websites you can do a lot with Github Pages or Azure Static Web Apps. For example this website is built with Hugo which is deployed to an Azure Static Web App for pennies per month. If you have more complex needs small Linux VMs can be created for not a lot more.&lt;/p&gt;
&lt;p&gt;I have learnt more from running a side project in production than I have the original idea. Things like DNS, SSL certificates, authentication, SEO are all very important for running a project but they would have been missed if you only ever ran your side project on localhost. I think having a rounded experience gives you a leg up when it comes to talking about your skills in an interview scenario.&lt;/p&gt;
&lt;p&gt;If you are between jobs, it is tempting to start something ambitious — the next big SaaS idea, a full-stack app with every feature you can think of. I have fallen into that trap myself. A small project you actually finish is worth more than a grand one that never ships. Pick something you can complete in a weekend or two: a CLI tool, a simple API, a static site, even a useful script. You will have something concrete to talk about in interviews, and the momentum of finishing one thing often makes the next one easier.&lt;/p&gt;
&lt;p&gt;My personal side projects can be found on my &lt;a href="https://blog-test.funkysi1701.com/projects"&gt;projects&lt;/a&gt;
page. My inspiration came from various places, my hobbies and interests, problems I am facing or hear about, or just stuff I want to learn.&lt;/p&gt;
&lt;h2 id="keep-learning-deliberately"&gt;Keep learning deliberately&lt;a class="anchor ms-1" href="#keep-learning-deliberately" aria-label="Permalink: Keep learning deliberately"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Between applications there is often more waiting than interviewing. Use that time deliberately: look at the job descriptions you are targeting, spot a recurring skill gap, and focus on one thing rather than trying to learn everything. I listen to &lt;a href="https://blog-test.funkysi1701.com/podcasts"&gt;development podcasts&lt;/a&gt;
on the commute and dip into courses — I have written before about using &lt;a href="https://blog-test.funkysi1701.com/posts/2018/pluralsight/"&gt;Pluralsight&lt;/a&gt;
while doing the washing up. You will not become an expert in a fortnight, but being able to talk about what you are learning still comes up in interviews. For more general advice, see &lt;a href="https://blog-test.funkysi1701.com/posts/2018/tips-for-developing-yourself/"&gt;Tips for Developing Yourself&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="closing-thoughts"&gt;Closing thoughts&lt;a class="anchor ms-1" href="#closing-thoughts" aria-label="Permalink: Closing thoughts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Being made redundant is not something I would wish on anyone, and I am still in the middle of finding my next role. Some days the job search feels slow and frustrating. On the better days, I remind myself that the things I have been doing for years — showing up at events, writing on this blog, shipping side projects, keeping my skills current — are not wasted effort. They are what give me stories to tell in interviews and reasons for people to remember my name.&lt;/p&gt;
&lt;p&gt;None of this replaces the practical side of job hunting: refreshing your CV and LinkedIn, talking to recruiters, applying properly, and working through the admin that comes with redundancy. I went through redundancy before, in 2021, and wrote about recruiters, interview rounds, and the spreadsheet I used to keep track of it all in &lt;a href="https://blog-test.funkysi1701.com/posts/2021/lone-developer-to-senior-developer-my-2021-story/"&gt;my 2021 story&lt;/a&gt;
. Visibility helps people remember your name; applications still get you in the door.&lt;/p&gt;
&lt;p&gt;But small, consistent habits compound. You do not need to do everything at once. Pick one thing you can start this month: a user group, a blog post, a course on something job ads keep asking for, or a side project you can actually finish — &lt;a href="https://blog-test.funkysi1701.com/start-here/"&gt;Start Here&lt;/a&gt;
collects a short reading path if you want inspiration from this blog first. Community work counts too; running a &lt;a href="https://blog-test.funkysi1701.com/posts/2024/codeclub/"&gt;Code Club&lt;/a&gt;
taught me as much about showing up as any meetup talk. If you still have a job but worry the ground is shifting beneath you, even better — start now while you have a bit more energy and headspace.&lt;/p&gt;
&lt;p&gt;If you are going through something similar, I hope this helps. If you have found other things that worked for you, I would love to hear about them in the comments.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want a monthly email with my latest posts, please sign up for my &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. You can also &lt;a href="https://blog-test.funkysi1701.com/contact"&gt;get in touch&lt;/a&gt;
if you have questions or just want to chat.&lt;/p&gt;</description></item><item><title>Episode Atlas: track your Trek rewatch</title><link>https://blog-test.funkysi1701.com/posts/2026/episode-atlas/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jun 2026 12:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/episode-atlas/</guid><category term="StarTrek">StarTrek</category><category term="SideProjects">SideProjects</category><category term="EpisodeAtlas">EpisodeAtlas</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/episode-atlas/episode-atlas-home.png"/><description>&lt;p&gt;If you have ever tried to rewatch &lt;em&gt;Star Trek&lt;/em&gt; properly—not just dip into a favourite episode, but work through hundreds of instalments across multiple series—you will know the feeling. You pause &lt;em&gt;Deep Space Nine&lt;/em&gt; for a few weeks, start something else, and suddenly you have no idea which episode you were on. Spreadsheets help for a while, then they do not. Notes on your phone get lost. Memory is unreliable when you jump between TNG, DS9, and whatever new show has just dropped.&lt;/p&gt;
&lt;p&gt;That is the problem &lt;strong&gt;&lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
&lt;/strong&gt; exists to solve: &lt;strong&gt;search 900+ episodes and films, mark what you have watched, and always know what to watch next&lt;/strong&gt;—without treating a rewatch like a project-management exercise.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Episode Atlas homepage: search and track Star Trek episodes" src="https://blog-test.funkysi1701.com/images/2026/episode-atlas/episode-atlas-home.png" loading="lazy"
width="1280" height="800"
/&gt;
&lt;/p&gt;
&lt;h2 id="why-i-built-it"&gt;Why I built it&lt;a class="anchor ms-1" href="#why-i-built-it" aria-label="Permalink: Why I built it"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I write about &lt;em&gt;Star Trek&lt;/em&gt; on this blog from time to time—episode reviews, top-50 lists, thoughts on new series. The honest origin is simpler than that, though: &lt;strong&gt;I wanted a better way to track my own rewatches&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Generic TV trackers are fine if you watch a bit of everything. They are less helpful when you care about &lt;strong&gt;one enormous franchise&lt;/strong&gt; with inconsistent stardates, films mixed in with series, and the urge to jump to &amp;ldquo;all the Borg episodes&amp;rdquo; rather than the next sequential instalment. Episode Atlas is deliberately narrow (if you can describe a database of over 900 episodes and films narrow!): all of &lt;em&gt;Star Trek&lt;/em&gt;, in one place, with features shaped by how fans actually rewatch.&lt;/p&gt;
&lt;h2 id="browse-first-sign-in-to-save"&gt;Browse first, sign in to save&lt;a class="anchor ms-1" href="#browse-first-sign-in-to-save" aria-label="Permalink: Browse first, sign in to save"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can use &lt;strong&gt;&lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
&lt;/strong&gt; without creating an account. Search the catalogue, open episodes, browse collections, and spin the random picker—no signup required.&lt;/p&gt;
&lt;p&gt;When you want your progress to stick, sign in and start your &lt;strong&gt;captain’s log&lt;/strong&gt;. Mark episodes watched, and the site remembers where you left off across every series—even if you detour from DS9 to TNG and back again.&lt;/p&gt;
&lt;h2 id="your-service-record"&gt;Your service record&lt;a class="anchor ms-1" href="#your-service-record" aria-label="Permalink: Your service record"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you are logging watches, the homepage gives you a &lt;strong&gt;service record&lt;/strong&gt; at a glance: how many of the 900+ episodes you have seen, your percentage through the franchise, and your current &lt;strong&gt;watch rank&lt;/strong&gt; (from the early ranks up through Lieutenant, Commander, and beyond). The site shows how many more episodes you need for the next rank, so a long rewatch feels like progress rather than a vague “I think I am halfway through Voyager.”&lt;/p&gt;
&lt;p&gt;You can also earn &lt;strong&gt;commendations&lt;/strong&gt; and build an &lt;strong&gt;active duty streak&lt;/strong&gt;—small nudges to keep visiting when you are in the middle of a serious rewatch. It is the same idea as a fitness streak, but for &lt;em&gt;Star Trek&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="find-any-episode-in-seconds"&gt;Find any episode in seconds&lt;a class="anchor ms-1" href="#find-any-episode-in-seconds" aria-label="Permalink: Find any episode in seconds"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Search&lt;/strong&gt; is the front door. Most visits start with “I know roughly what I want” or “which episode was that again?” Filter by series and season to narrow the list; keywords catch titles and descriptions you only half remember. Every series and the films are in one catalogue.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Episode list: find and filter Star Trek episodes" src="https://blog-test.funkysi1701.com/images/2026/episode-atlas/episode-atlas-episodes.png" loading="lazy"
width="1280" height="800"
/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Search results filtered by keyword" src="https://blog-test.funkysi1701.com/images/2026/episode-atlas/episode-atlas-search.png" loading="lazy"
width="1280" height="800"
/&gt;
&lt;/p&gt;
&lt;h2 id="episode-pages-context-and-next-steps"&gt;Episode pages: context and next steps&lt;a class="anchor ms-1" href="#episode-pages-context-and-next-steps" aria-label="Permalink: Episode pages: context and next steps"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open any episode and you get what you need for a rewatch session: metadata, &lt;strong&gt;previous and next&lt;/strong&gt; navigation within the series, season progress, and actions to mark the episode watched or jump to the suggested &lt;strong&gt;next episode&lt;/strong&gt;. Your captain’s log ties it together—what you logged today, what you have already seen, and where to pick up when you return.&lt;/p&gt;
&lt;p&gt;The flow the site describes is simple: &lt;strong&gt;search → open → mark watched → move on&lt;/strong&gt;. Three gestures, no spreadsheet.&lt;/p&gt;
&lt;h2 id="collections-when-you-want-a-mood-not-a-season"&gt;Collections when you want a mood, not a season&lt;a class="anchor ms-1" href="#collections-when-you-want-a-mood-not-a-season" aria-label="Permalink: Collections when you want a mood, not a season"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Collections&lt;/strong&gt; answer a different question from search: &lt;em&gt;“It is late; show me something good in this mood.”&lt;/em&gt; Each collection points at Borg stories, time-travel episodes, holodeck highlights, and similar lists—fan knowledge encoded as browseable sets, so you skip filler without digging through every season.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Curated Star Trek episode collections" src="https://blog-test.funkysi1701.com/images/2026/episode-atlas/episode-atlas-collections.png" loading="lazy"
width="1280" height="800"
/&gt;
&lt;/p&gt;
&lt;h2 id="random-episode-when-you-cannot-decide"&gt;Random episode when you cannot decide&lt;a class="anchor ms-1" href="#random-episode-when-you-cannot-decide" aria-label="Permalink: Random episode when you cannot decide"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;&lt;a href="https://www.episodeatlas.com/random" target="_blank" rel="noopener noreferrer"&gt;random episode&lt;/a&gt;
&lt;/strong&gt; picker is for the evenings when you and the sofa have agreed on &lt;em&gt;Star Trek&lt;/em&gt; but not on &lt;em&gt;which&lt;/em&gt; &lt;em&gt;Star Trek&lt;/em&gt;. One click, one suggestion—useful when commitment is the hard part.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Random episode picker" src="https://blog-test.funkysi1701.com/images/2026/episode-atlas/episode-atlas-random.png" loading="lazy"
width="1280" height="800"
/&gt;
&lt;/p&gt;
&lt;h2 id="how-it-compares-to-other-sites"&gt;How it compares to other sites&lt;a class="anchor ms-1" href="#how-it-compares-to-other-sites" aria-label="Permalink: How it compares to other sites"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Episode Atlas is not trying to replace &lt;a href="https://memory-alpha.fandom.com/" target="_blank" rel="noopener noreferrer"&gt;Memory Alpha&lt;/a&gt;
for lore or IMDb for cast lists. It is built for &lt;strong&gt;progress&lt;/strong&gt;: what you have watched, what rank you have earned, and what to play next. If you have ever bounced between a wiki, a ratings site, and a generic tracker and still not known where you were in DS9, this is the gap it fills.&lt;/p&gt;
&lt;h2 id="try-it"&gt;Try it&lt;a class="anchor ms-1" href="#try-it" aria-label="Permalink: Try it"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;episodeatlas.com&lt;/a&gt;
&lt;/strong&gt; — free to browse, sign in when you want your captain’s log saved. Search, mark your first episode, and see your rank climb.&lt;/p&gt;
&lt;p&gt;How do you track long rewatches—spreadsheet, app, or pure memory? If you try Episode Atlas, I would genuinely like to know what works for you and what does not: features you love, gaps that annoy you, or anything that would make a rewatch easier. Leave a comment below, or use the &lt;strong&gt;feedback&lt;/strong&gt; option on &lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;episodeatlas.com&lt;/a&gt;
—both reach me, and both help shape what I build next.&lt;/p&gt;</description></item><item><title>AI on side projects: Cursor, Copilot</title><link>https://blog-test.funkysi1701.com/posts/2026/how-i-use-ai-on-side-projects/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 10 Apr 2026 12:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/how-i-use-ai-on-side-projects/</guid><category term="AI">AI</category><category term="ChatGPT">ChatGPT</category><category term="Cursor">Cursor</category><category term="GitHubCopilot">GitHubCopilot</category><category term="SideProjects">SideProjects</category><category term="DeveloperWorkflow">DeveloperWorkflow</category><category term="Blazor">Blazor</category><category term="Hugo">Hugo</category><category term="Productivity">Productivity</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/ai-with-side-projects.png"/><description>&lt;p&gt;There is no shortage of AI tools aimed at developers right now: chat assistants, IDE completions, agents that promise to run your tests, and new products every month with overlapping features. I am not going to argue which one is &amp;ldquo;best.&amp;rdquo; Instead, here is &lt;strong&gt;what I am actually using today&lt;/strong&gt; on hobby code: &lt;a href="https://chatgpt.com/" target="_blank" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;
for quick, low-context questions, &lt;a href="https://cursor.com/" target="_blank" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;
when the work needs my repository in the loop, and &lt;a href="https://github.com/features/copilot" target="_blank" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;
for fast inline help while I type. That trio might change, but it reflects how I have learned to spend money and attention in 2026.&lt;/p&gt;
&lt;p&gt;The through-line is simple: &lt;strong&gt;match the tool to how much context the problem needs&lt;/strong&gt;. That stops me from dumping half a repo into a browser tab for a vague design question, or firing up an editor assistant when I only wanted a two-paragraph explanation of something I could read in the docs.&lt;/p&gt;
&lt;p&gt;This is not a product review. It is a snapshot of how I work, using the projects on &lt;a href="https://blog-test.funkysi1701.com/projects/"&gt;my projects page&lt;/a&gt;
as concrete examples.&lt;/p&gt;
&lt;h2 id="chatgpt-questions-that-do-not-need-my-codebase"&gt;ChatGPT: questions that do not need my codebase&lt;a class="anchor ms-1" href="#chatgpt-questions-that-do-not-need-my-codebase" aria-label="Permalink: ChatGPT: questions that do not need my codebase"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://chatgpt.com/" target="_blank" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;
is still my first stop when I am trying to &lt;em&gt;frame&lt;/em&gt; a problem. I use it when the answer is mostly portable knowledge: comparisons, vocabulary, &amp;ldquo;what should I read next,&amp;rdquo; and sanity checks that do not depend on the exact shape of my solution.&lt;/p&gt;
&lt;p&gt;A few examples from things I have built:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This blog (Hugo + Azure Static Web Apps)&lt;/strong&gt; — I might ask how people usually implement site search on static sites, or what the trade-offs are between generating a JSON index at build time versus leaning on a hosted search service. I am not looking for a drop-in patch to my theme; I want a short list of options so I can decide what fits a hobby budget.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
(Blazor, Functions, Cosmos DB)&lt;/strong&gt; — good prompts sound like &amp;ldquo;patterns for tracking per-user progress through a large catalogue&amp;rdquo; or &amp;ldquo;when a tiny Blazor app might still justify a separate API layer.&amp;rdquo; Those are design conversations. The model does not need to see my episode containers to help me think about partition keys and stale data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://mandelbrot.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;Mandelbrot Generator&lt;/a&gt;
(Blazor WebAssembly)&lt;/strong&gt; — I have used general chats to reason about why browser-side fractals feel CPU-bound, or what people typically do first when zoom performance tanks. Again, that is physics-of-the-platform stuff, not &amp;ldquo;line 40 of my render loop.&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Experiments&lt;/strong&gt; — when I am poking at &lt;a href="https://blog-test.funkysi1701.com/projects/"&gt;.NET Aspire&lt;/a&gt;
, Kubernetes, Elasticsearch, or Azure Functions in my own time, ChatGPT is useful for learning paths: what to skim first, what terms I am mixing up, and what I am over-engineering for a toy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Where ChatGPT falls down is predictable: anything that requires &lt;em&gt;my&lt;/em&gt; wiring—pipeline YAML that only fails in CI, a Hugo partial that interacts with three others, a Blazor component that only breaks after publish. For that, context wins.&lt;/p&gt;
&lt;h2 id="cursor-when-the-answer-is-in-the-repo"&gt;Cursor: when the answer is in the repo&lt;a class="anchor ms-1" href="#cursor-when-the-answer-is-in-the-repo" aria-label="Permalink: Cursor: when the answer is in the repo"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://cursor.com/" target="_blank" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;
(or any &amp;ldquo;chat with your codebase&amp;rdquo; style editor) is where I go when I need &lt;strong&gt;consistency across files&lt;/strong&gt; and &lt;strong&gt;diff-shaped output&lt;/strong&gt;. Side projects accumulate small decisions—naming, folder layout, how strict nullability is—and the model only respects those if it can see them.&lt;/p&gt;
&lt;p&gt;Typical jobs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Blog platform&lt;/strong&gt; — adjusting a Hugo layout or partial, fixing warnings after a Hugo upgrade, or tweaking GitHub Actions / Azure Pipelines so the build still emits RSS and the JSON search index. Those changes are boring, fiddly, and easy to get subtly wrong if you guess from memory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Episode Atlas&lt;/strong&gt; — refactoring a Blazor page, aligning a Function endpoint with what the client expects, or tightening a Cosmos query once I know the access pattern. Here I want suggestions that match &lt;em&gt;my&lt;/em&gt; project structure, not a generic sample from the internet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mandelbrot&lt;/strong&gt; — iterating on rendering code where small mistakes show up as wrong colours or runaway iterations. Having the file in context beats describing the algorithm in chat.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.thornepentecostalchurch.co.uk/" target="_blank" rel="noopener noreferrer"&gt;Thorne Pentecostal Church&lt;/a&gt;
site&lt;/strong&gt; — simple HTML and CSS still benefit from repo context when the goal is &amp;ldquo;match what is already there&amp;rdquo; rather than &amp;ldquo;invent a new design system.&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I still treat Cursor as an accelerator, not an author. I read diffs, run the site or tests, and verify anything touching hosting or secrets. Side projects are a great place to learn &lt;em&gt;when&lt;/em&gt; to trust an edit—and when the model confidently invents an API that never existed.&lt;/p&gt;
&lt;h2 id="github-copilot-the-inline-teammate"&gt;GitHub Copilot: the inline teammate&lt;a class="anchor ms-1" href="#github-copilot-the-inline-teammate" aria-label="Permalink: GitHub Copilot: the inline teammate"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/features/copilot" target="_blank" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;
fills a different gap. Where Cursor often drives &lt;strong&gt;multi-file&lt;/strong&gt; or &lt;strong&gt;exploratory&lt;/strong&gt; edits, Copilot shines on &lt;strong&gt;local&lt;/strong&gt; work: finishing a line, sketching a test, or repeating a pattern I have already established in the file.&lt;/p&gt;
&lt;p&gt;I reach for it when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I am writing repetitive Blazor markup or boilerplate DTOs.&lt;/li&gt;
&lt;li&gt;I am editing YAML or shell and want a plausible next stanza that matches the block above.&lt;/li&gt;
&lt;li&gt;I already know what I am doing and want speed more than architecture.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is overlap between Copilot and Cursor in my workflow, and I am fine with that. If you only pay for one tool, you can still apply the same &lt;em&gt;principle&lt;/em&gt;: shallow context versus deep context.&lt;/p&gt;
&lt;h2 id="a-quick-decision-table"&gt;A quick decision table&lt;a class="anchor ms-1" href="#a-quick-decision-table" aria-label="Permalink: A quick decision table"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;What I use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;ldquo;What are my options?&amp;rdquo; / compare approaches&lt;/td&gt;
&lt;td&gt;ChatGPT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;ldquo;Change this project to do X&amp;rdquo;&lt;/td&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;ldquo;Finish this method / this pipeline step&amp;rdquo;&lt;/td&gt;
&lt;td&gt;Copilot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security, secrets, production incidents&lt;/td&gt;
&lt;td&gt;Me, plus docs—AI optional and heavily verified&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="boundaries-privacy-and-verification"&gt;Boundaries, privacy, and verification&lt;a class="anchor ms-1" href="#boundaries-privacy-and-verification" aria-label="Permalink: Boundaries, privacy, and verification"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What I do not put in AI tools.&lt;/strong&gt; I treat anything that could identify a person, anything contractual from work, and anything that unlocks production (passwords, API keys, connection strings, private certificates) as off-limits unless the product’s policy and my employer’s policy both say otherwise. For side projects that usually means personal repos only, secrets in environment variables or Key Vault—not in chat—and if I need help with a failing pipeline I redact resource names and paste error text, not the whole variable block. If you have a day job, your company’s acceptable-use rules beat anything you read in a blog post; when in doubt, use vendor docs and internal support channels instead of a model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How I check output before it counts.&lt;/strong&gt; I never merge a multi-file change on trust alone: I read the diff file by file, run &lt;code&gt;hugo&lt;/code&gt; / &lt;code&gt;dotnet build&lt;/code&gt; / whatever the project’s normal build is, and exercise the path I changed in the browser or with a quick manual test. If the assistant suggested a library call or HTTP API I do not recognise, I cross-check the official documentation or source before I rely on it—side projects are where I have been burned by plausible-but-wrong method names. For anything security-sensitive (auth callbacks, CORS, SQL, dependency upgrades), I assume the model is giving me a sketch and I still apply the same review I would give a junior’s pull request.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Learning paths are still verified.&lt;/strong&gt; When I use ChatGPT to orient around Aspire, Kubernetes, or Elasticsearch, I use it to build a mental map and a reading list, then I confirm version-specific behaviour in Microsoft Learn, Kubernetes docs, or Elastic’s docs. The goal is to shorten &lt;em&gt;where to look&lt;/em&gt;, not to skip looking.&lt;/p&gt;
&lt;h2 id="closing-thought"&gt;Closing thought&lt;a class="anchor ms-1" href="#closing-thought" aria-label="Permalink: Closing thought"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AI tools have not replaced the fun of side projects for me. Projects like Episode Atlas exist because I wanted a better way to track &lt;em&gt;Star Trek&lt;/em&gt; rewatches across hundreds of episodes; the Mandelbrot app exists because fractals are still cool; this blog exists because writing things down forces clarity. What has changed is how fast I can get through the glue work—if I pick the right assistant for the amount of context the task really needs.&lt;/p&gt;
&lt;p&gt;If you are a developer experimenting with the same stack—.NET, static sites, Azure—how do you split tools today? I would be interested to hear what works for you in the comments.&lt;/p&gt;</description></item><item><title>AI will not replace us developers</title><link>https://blog-test.funkysi1701.com/posts/2026/ai-wont-replace-developers/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 14 Mar 2026 09:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/ai-wont-replace-developers/</guid><category term="AI">AI</category><category term="SoftwareDevelopment">SoftwareDevelopment</category><category term="Career">Career</category><category term="engineering">engineering</category><category term="Productivity">Productivity</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/ai-wont-replace-developers.png"/><description>&lt;h2 id="introduction--the-shift-we-are-living-through"&gt;Introduction – The Shift We are Living Through&lt;a class="anchor ms-1" href="#introduction--the-shift-we-are-living-through" aria-label="Permalink: Introduction – The Shift We are Living Through"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As I write this, I have just been made redundant. AI is not being used to explain this particular redundancy, but it is being used to explain many redundancies across the industry.&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;I just got laid off..... Again...... I am still in shock. I loved my new job and was creating great impact but here we are again. Layoffs are not personal so I am ok but yeh will be looking for something new...... Again......&lt;/p&gt;&amp;mdash; Debbie O&amp;#39;Brien (@debs_obrien) &lt;a href="https://twitter.com/debs_obrien/status/2027171846743892254?ref_src=twsrc%5Etfw"&gt;February 27, 2026&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;I listened to an excellent talk at &lt;a href="https://blog-test.funkysi1701.com/posts/2026/ndc-london-2026/"&gt;NDC London&lt;/a&gt;
by Debbie O&amp;rsquo;Brien about using AI to do amazing things with &lt;a href="https://youtu.be/Numb52aJkJw" target="_blank" rel="noopener noreferrer"&gt;Playwright MCP&lt;/a&gt;
. If people who are using AI to its fullest are losing their jobs to AI, what hope is there for our industry? Are we all going to be writing AI prompts and that&amp;rsquo;s it?&lt;/p&gt;
&lt;p&gt;But let&amp;rsquo;s stop for a minute. Software development is an ever-changing industry. There is always something new to learn and this AI craze is no different.&lt;/p&gt;
&lt;p&gt;The role of the developer has always shifted as tools improved. We moved from writing assembly to high-level languages, from manual deployments to automated pipelines, and from managing servers to deploying infrastructure with a few commands.&lt;/p&gt;
&lt;p&gt;The real question is how our role is changing and how we need to adapt and make the most of the new tools available to us.&lt;/p&gt;
&lt;h2 id="whats-actually-changed"&gt;What’s Actually Changed?&lt;a class="anchor ms-1" href="#whats-actually-changed" aria-label="Permalink: What’s Actually Changed?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a lot of noise around AI in software development. Headlines swing between &amp;ldquo;AI will replace developers&amp;rdquo; and &amp;ldquo;AI is just autocomplete.&amp;rdquo; The truth, as usual, sits somewhere in the middle.&lt;/p&gt;
&lt;p&gt;But something real has changed. Not just the tools we use, but the speed, shape, and workflow of software development.&lt;/p&gt;
&lt;h3 id="from-reactive-to-proactive"&gt;From Reactive to Proactive&lt;a class="anchor ms-1" href="#from-reactive-to-proactive" aria-label="Permalink: From Reactive to Proactive"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For years, developer productivity tools focused on helping us type faster.&lt;/p&gt;
&lt;p&gt;We had IntelliSense, snippets, code generation tools, and IDE refactorings. These were useful, but they were fundamentally reactive. They waited for the developer to start typing and then offered suggestions.&lt;/p&gt;
&lt;p&gt;AI coding tools have crossed a different threshold.&lt;/p&gt;
&lt;p&gt;Instead of simply completing the next line, they can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generate entire classes or modules&lt;/li&gt;
&lt;li&gt;Suggest architecture patterns&lt;/li&gt;
&lt;li&gt;Write tests&lt;/li&gt;
&lt;li&gt;Perform multi-file refactors&lt;/li&gt;
&lt;li&gt;Explain unfamiliar codebases&lt;/li&gt;
&lt;li&gt;Propose fixes for bugs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The important shift is this:&lt;/p&gt;
&lt;p&gt;The tool is no longer just responding to the code — it&amp;rsquo;s responding to the intent.&lt;/p&gt;
&lt;p&gt;You describe a goal, and the AI attempts to produce the implementation.&lt;/p&gt;
&lt;p&gt;This moves AI from being an autocomplete engine to something closer to an execution partner.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not autonomous in the sense of replacing developers, but it does change the relationship between the developer and the code.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re no longer writing every line ourselves. Increasingly, we are directing the creation of code rather than manually constructing it.&lt;/p&gt;
&lt;h3 id="the-cost-of-a-first-draft-has-collapsed"&gt;The Cost of a First Draft Has Collapsed&lt;a class="anchor ms-1" href="#the-cost-of-a-first-draft-has-collapsed" aria-label="Permalink: The Cost of a First Draft Has Collapsed"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Historically, one of the hidden costs of software development was simply getting started.&lt;/p&gt;
&lt;p&gt;Creating a prototype involved:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting up project structure&lt;/li&gt;
&lt;li&gt;Writing boilerplate&lt;/li&gt;
&lt;li&gt;Defining models&lt;/li&gt;
&lt;li&gt;Creating basic tests&lt;/li&gt;
&lt;li&gt;Wiring components together&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of this work was intellectually difficult, but it took time.&lt;/p&gt;
&lt;p&gt;AI tools have dramatically reduced the cost of that first draft.&lt;/p&gt;
&lt;p&gt;You can now describe a feature and quickly get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A rough implementation&lt;/li&gt;
&lt;li&gt;Basic unit tests&lt;/li&gt;
&lt;li&gt;A starting architecture&lt;/li&gt;
&lt;li&gt;A prototype that actually runs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This doesn&amp;rsquo;t mean the output is perfect. In fact, it often isn&amp;rsquo;t. But the barrier to experimentation has dropped significantly.&lt;/p&gt;
&lt;p&gt;Ideas that might have taken half a day to prototype can now be explored in minutes.&lt;/p&gt;
&lt;p&gt;And that has a subtle but powerful effect on development culture:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When experimentation becomes cheap, developers try more ideas.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This encourages iteration, exploration, and rapid feedback in ways that previously required more discipline and effort.&lt;/p&gt;
&lt;h3 id="writing-code-is-no-longer-the-bottleneck"&gt;Writing Code Is No Longer the Bottleneck&lt;a class="anchor ms-1" href="#writing-code-is-no-longer-the-bottleneck" aria-label="Permalink: Writing Code Is No Longer the Bottleneck"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the most surprising outcomes of AI coding tools is that they reveal something many experienced developers already suspected:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Typing code was never the hardest part of software development.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The real difficulty lies elsewhere:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understanding the problem&lt;/li&gt;
&lt;li&gt;Designing a clean solution&lt;/li&gt;
&lt;li&gt;Managing complexity&lt;/li&gt;
&lt;li&gt;Communicating intent to other developers&lt;/li&gt;
&lt;li&gt;Maintaining systems over time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI can produce large volumes of code very quickly. But that doesn&amp;rsquo;t automatically translate into good software.&lt;/p&gt;
&lt;p&gt;If anything, it shifts the constraint.&lt;/p&gt;
&lt;p&gt;The bottleneck is no longer how fast code can be written.&lt;/p&gt;
&lt;p&gt;The bottleneck is now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How clearly can problems be defined&lt;/li&gt;
&lt;li&gt;How well can systems be designed&lt;/li&gt;
&lt;li&gt;How effectively can code be reviewed and maintained&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, AI accelerates the mechanical part of development, but the thinking part becomes even more important.&lt;/p&gt;
&lt;h2 id="what-hasnt-changed-but-people-think-it-has"&gt;What Hasn’t Changed (But People Think It Has)&lt;a class="anchor ms-1" href="#what-hasnt-changed-but-people-think-it-has" aria-label="Permalink: What Hasn’t Changed (But People Think It Has)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With every major technological shift, there&amp;rsquo;s a temptation to assume everything is different now. AI has amplified that feeling in software development. When tools can generate large amounts of code in seconds, it&amp;rsquo;s easy to believe the fundamentals of the profession have been rewritten.&lt;/p&gt;
&lt;p&gt;But when you look closely at real software projects, something interesting appears: many of the hardest parts of software development haven&amp;rsquo;t changed at all.&lt;/p&gt;
&lt;p&gt;AI has accelerated the mechanics of coding, but the underlying challenges of building reliable, useful software are still very much human problems.&lt;/p&gt;
&lt;h3 id="understanding-requirements-is-still-the-hardest-problem"&gt;Understanding Requirements Is Still the Hardest Problem&lt;a class="anchor ms-1" href="#understanding-requirements-is-still-the-hardest-problem" aria-label="Permalink: Understanding Requirements Is Still the Hardest Problem"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Software projects rarely fail because developers can&amp;rsquo;t write code. They fail because the problem wasn&amp;rsquo;t clearly understood in the first place.&lt;/p&gt;
&lt;p&gt;AI tools can generate implementations, but they rely entirely on the input they&amp;rsquo;re given. If the requirement is vague, incomplete, or contradictory, the output will reflect that.&lt;/p&gt;
&lt;p&gt;Consider how requirements often arrive in real projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A stakeholder describes a problem in business language.&lt;/li&gt;
&lt;li&gt;Important edge cases are discovered later.&lt;/li&gt;
&lt;li&gt;Different teams have slightly different expectations.&lt;/li&gt;
&lt;li&gt;Requirements evolve as users interact with the system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of this has changed with AI.&lt;/p&gt;
&lt;p&gt;The ability to ask the right questions, clarify ambiguity, and translate business needs into technical solutions remains one of the most valuable skills a developer can have.&lt;/p&gt;
&lt;p&gt;In fact, as code generation becomes easier, clear problem definition becomes even more important.&lt;/p&gt;
&lt;h3 id="architecture-and-trade-offs-still-matter"&gt;Architecture and Trade-Offs Still Matter&lt;a class="anchor ms-1" href="#architecture-and-trade-offs-still-matter" aria-label="Permalink: Architecture and Trade-Offs Still Matter"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AI can suggest design patterns, propose architectures, and generate project structures. But good software architecture isn&amp;rsquo;t just about picking the right pattern.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s about making trade-offs.&lt;/p&gt;
&lt;p&gt;Questions like these still require human judgment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Should this be a microservice or part of the monolith?&lt;/li&gt;
&lt;li&gt;Is the added complexity of caching worth the performance gain?&lt;/li&gt;
&lt;li&gt;What level of abstraction will make this system maintainable in five years?&lt;/li&gt;
&lt;li&gt;Where should the boundaries between components sit?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These decisions depend heavily on context:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Team size&lt;/li&gt;
&lt;li&gt;Deployment environment&lt;/li&gt;
&lt;li&gt;Operational constraints&lt;/li&gt;
&lt;li&gt;Long-term maintenance costs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI can offer suggestions, but it cannot fully understand the organisational and operational realities of the system it&amp;rsquo;s helping to build.&lt;/p&gt;
&lt;p&gt;That responsibility still sits with the developer.&lt;/p&gt;
&lt;h3 id="accountability-doesnt-disappear"&gt;Accountability Doesn’t Disappear&lt;a class="anchor ms-1" href="#accountability-doesnt-disappear" aria-label="Permalink: Accountability Doesn’t Disappear"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One thing that definitely hasn&amp;rsquo;t changed is ownership.&lt;/p&gt;
&lt;p&gt;When software breaks in production, nobody blames the IDE. The same principle applies to AI.&lt;/p&gt;
&lt;p&gt;If an AI-generated query deletes the wrong data, or a generated implementation introduces a subtle performance issue, the responsibility still lies with the developer who reviewed and shipped the code.&lt;/p&gt;
&lt;p&gt;Production systems still require:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Careful testing&lt;/li&gt;
&lt;li&gt;Monitoring and observability&lt;/li&gt;
&lt;li&gt;Security awareness&lt;/li&gt;
&lt;li&gt;Performance tuning&lt;/li&gt;
&lt;li&gt;Ongoing maintenance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI can assist with many of these areas, but it doesn&amp;rsquo;t remove the need for human accountability.&lt;/p&gt;
&lt;p&gt;At the end of the day, someone has to understand the system well enough to take responsibility for it.&lt;/p&gt;
&lt;p&gt;And that hasn&amp;rsquo;t changed at all.&lt;/p&gt;
&lt;h2 id="the-new-developer-skill-stack"&gt;The New Developer Skill Stack&lt;a class="anchor ms-1" href="#the-new-developer-skill-stack" aria-label="Permalink: The New Developer Skill Stack"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If we accept that AI has collapsed the cost of a first draft, then the skill stack shifts upward.&lt;/p&gt;
&lt;p&gt;Not because the old skills are irrelevant, but because they&amp;rsquo;re no longer the limiting factor as often.&lt;/p&gt;
&lt;p&gt;Syntax still matters. Fundamentals still matter. But the competitive advantage moves towards the parts of the job that are hard to automate: precision, judgment, and system-level thinking.&lt;/p&gt;
&lt;p&gt;Think of it as an evolution of the same craft.&lt;/p&gt;
&lt;h3 id="prompting-as-a-technical-skill"&gt;Prompting as a Technical Skill&lt;a class="anchor ms-1" href="#prompting-as-a-technical-skill" aria-label="Permalink: Prompting as a Technical Skill"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&amp;ldquo;Prompting&amp;rdquo; sounds fluffy until you realise what it actually is in practice: specifying a problem clearly enough that another agent (human or machine) can make progress without guessing.&lt;/p&gt;
&lt;p&gt;The better you are at being precise, the more useful the tool becomes.&lt;/p&gt;
&lt;p&gt;That means getting specific about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The goal (what &amp;ldquo;done&amp;rdquo; looks like)&lt;/li&gt;
&lt;li&gt;The constraints (performance, security, backward compatibility, tech stack)&lt;/li&gt;
&lt;li&gt;Inputs/outputs and edge cases&lt;/li&gt;
&lt;li&gt;The environment (language version, framework, database, deployment model)&lt;/li&gt;
&lt;li&gt;The trade-offs you care about (simplicity vs flexibility, latency vs cost)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you ask an AI to &amp;ldquo;build a feature&amp;rdquo;, you&amp;rsquo;ll get a lot of code, but it will almost always bake in assumptions you didn&amp;rsquo;t mean to make.&lt;/p&gt;
&lt;p&gt;The best results come when you treat it like a junior developer with infinite typing speed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ask it to propose an approach first&lt;/li&gt;
&lt;li&gt;Get it to list assumptions and risks&lt;/li&gt;
&lt;li&gt;Then implement one slice at a time (and keep the changes small)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, iterative refinement becomes the workflow.&lt;/p&gt;
&lt;p&gt;You rarely get the best output on the first prompt. But you can converge quickly if you review the result, point out what is wrong or missing, and re-run with tighter guidance.&lt;/p&gt;
&lt;p&gt;In other words, prompting is less about &amp;ldquo;magic words&amp;rdquo; and more about feedback loops.&lt;/p&gt;
&lt;h3 id="code-review-becomes-critical-thinking"&gt;Code Review Becomes Critical Thinking&lt;a class="anchor ms-1" href="#code-review-becomes-critical-thinking" aria-label="Permalink: Code Review Becomes Critical Thinking"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When AI can generate 200 lines of code in seconds, reviewing becomes the high-leverage skill.&lt;/p&gt;
&lt;p&gt;That review can&amp;rsquo;t just be &amp;ldquo;does it compile&amp;rdquo; or &amp;ldquo;does it look idiomatic&amp;rdquo;. It has to be critical thinking.&lt;/p&gt;
&lt;p&gt;AI-generated code often fails in ways that are subtle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It handles the happy path beautifully and ignores weird real-world inputs&lt;/li&gt;
&lt;li&gt;It silently changes behaviour (especially around dates, nulls, and defaults)&lt;/li&gt;
&lt;li&gt;It introduces concurrency bugs that only show up under load&lt;/li&gt;
&lt;li&gt;It uses a library/API incorrectly but convincingly&lt;/li&gt;
&lt;li&gt;It passes tests that are too shallow to be meaningful&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most important thing to review is not the code itself, but the assumptions underneath it.&lt;/p&gt;
&lt;p&gt;I find it useful to explicitly ask:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What does this code assume about the data?&lt;/li&gt;
&lt;li&gt;What does it assume about ordering, timing, and retries?&lt;/li&gt;
&lt;li&gt;What happens when dependencies fail?&lt;/li&gt;
&lt;li&gt;What would I see in logs/metrics if this breaks in production?&lt;/li&gt;
&lt;li&gt;What tests would convince me this is correct?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where experienced developers become even more valuable: not because they can type faster, but because they&amp;rsquo;ve seen how systems fail.&lt;/p&gt;
&lt;h3 id="systems-thinking--syntax-knowledge"&gt;Systems Thinking &gt; Syntax Knowledge&lt;a class="anchor ms-1" href="#systems-thinking--syntax-knowledge" aria-label="Permalink: Systems Thinking &amp;gt; Syntax Knowledge"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AI is good at syntax and local patterns. It is much worse at understanding the bigger picture.&lt;/p&gt;
&lt;p&gt;The developers who thrive in this shift will be the ones who can hold the system in their head:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How data flows through the application&lt;/li&gt;
&lt;li&gt;Where the boundaries are between components&lt;/li&gt;
&lt;li&gt;What needs to be observable in production (logs, metrics, traces)&lt;/li&gt;
&lt;li&gt;What makes the codebase maintainable for the next person&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Systems thinking is what stops an AI-generated &amp;ldquo;solution&amp;rdquo; from becoming a future incident.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also why the old advice from &lt;a href="https://blog-test.funkysi1701.com/posts/2025/pragmatic-programmer/"&gt;The Pragmatic Programmer&lt;/a&gt;
matters even more now: remember the big picture.&lt;/p&gt;
&lt;p&gt;Not &amp;ldquo;can we generate this function&amp;rdquo;, but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is this the simplest thing that could work?&lt;/li&gt;
&lt;li&gt;Can we operate it at 2am?&lt;/li&gt;
&lt;li&gt;Can we change it safely in six months?&lt;/li&gt;
&lt;li&gt;Are we making the system easier to understand or harder?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI accelerates output, but it doesn&amp;rsquo;t automatically improve outcomes, and that creates real risk if we aren&amp;rsquo;t careful.&lt;/p&gt;
&lt;h2 id="the-risk-shallow-engineers"&gt;The Risk: Shallow Engineers&lt;a class="anchor ms-1" href="#the-risk-shallow-engineers" aria-label="Permalink: The Risk: Shallow Engineers"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The biggest danger is not that AI replaces us.&lt;/p&gt;
&lt;p&gt;The biggest danger is that it makes us lazy.&lt;/p&gt;
&lt;p&gt;If we outsource too much thinking to tools, we can accidentally create a generation of engineers who can ship quickly but cannot explain what they shipped, why it works, or how to fix it when it fails.&lt;/p&gt;
&lt;p&gt;That risk shows up in subtle ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copying generated code without understanding the trade-offs&lt;/li&gt;
&lt;li&gt;Accepting tests because they are green, even when they don&amp;rsquo;t test anything meaningful&lt;/li&gt;
&lt;li&gt;Mistaking confidence in the AI&amp;rsquo;s tone for correctness in the implementation&lt;/li&gt;
&lt;li&gt;Losing touch with fundamentals like debugging, data structures, networking, and performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is especially dangerous under delivery pressure. If a team rewards speed above all else, AI can amplify the wrong behaviour: lots of output, little understanding.&lt;/p&gt;
&lt;p&gt;And that debt compounds.&lt;/p&gt;
&lt;p&gt;Six months later, nobody trusts the codebase, incidents increase, and every change becomes risky.&lt;/p&gt;
&lt;p&gt;So yes, AI can make us faster. But if we use it without discipline, it can also make us shallow.&lt;/p&gt;
&lt;p&gt;The antidote is simple, even if not always easy: use AI to accelerate execution, not to bypass understanding.&lt;/p&gt;
&lt;h2 id="the-opportunity-increased-leverage-for-the-right-people"&gt;The Opportunity: Increased Leverage (For the Right People)&lt;a class="anchor ms-1" href="#the-opportunity-increased-leverage-for-the-right-people" aria-label="Permalink: The Opportunity: Increased Leverage (For the Right People)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The upside is huge for developers who combine AI with strong engineering habits.&lt;/p&gt;
&lt;p&gt;When you can generate a solid first draft in minutes, you can spend more time where value actually lives:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better problem framing&lt;/li&gt;
&lt;li&gt;Better architecture decisions&lt;/li&gt;
&lt;li&gt;Better test strategy&lt;/li&gt;
&lt;li&gt;Better operational design&lt;/li&gt;
&lt;li&gt;Better developer experience for your team&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where leverage appears.&lt;/p&gt;
&lt;p&gt;One thoughtful developer with AI support can now do the kind of end-to-end work that used to require more hand-offs and more waiting.&lt;/p&gt;
&lt;p&gt;Not because they became magically smarter overnight, but because the mechanical drag has been reduced.&lt;/p&gt;
&lt;p&gt;If your fundamentals are strong, AI multiplies your impact.&lt;/p&gt;
&lt;p&gt;If your fundamentals are weak, AI multiplies your mistakes.&lt;/p&gt;
&lt;p&gt;That is the real divide.&lt;/p&gt;
&lt;h2 id="practical-advice-for-developers"&gt;Practical Advice for Developers&lt;a class="anchor ms-1" href="#practical-advice-for-developers" aria-label="Permalink: Practical Advice for Developers"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to stay relevant and thrive in this shift, here is what I would do right now.&lt;/p&gt;
&lt;h3 id="1-treat-ai-output-as-a-draft-not-truth"&gt;1. Treat AI Output as a Draft, Not Truth&lt;a class="anchor ms-1" href="#1-treat-ai-output-as-a-draft-not-truth" aria-label="Permalink: 1. Treat AI Output as a Draft, Not Truth"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Assume every generated answer is a proposal.&lt;/p&gt;
&lt;p&gt;Read it. Challenge it. Test it.&lt;/p&gt;
&lt;p&gt;Never merge code you cannot explain to another developer.&lt;/p&gt;
&lt;h3 id="2-strengthen-your-core-engineering-muscles"&gt;2. Strengthen Your Core Engineering Muscles&lt;a class="anchor ms-1" href="#2-strengthen-your-core-engineering-muscles" aria-label="Permalink: 2. Strengthen Your Core Engineering Muscles"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Double down on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Testing strategy&lt;/li&gt;
&lt;li&gt;System design&lt;/li&gt;
&lt;li&gt;Observability&lt;/li&gt;
&lt;li&gt;Performance and security fundamentals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are durable skills and AI makes them more valuable, not less.&lt;/p&gt;
&lt;h3 id="3-get-better-at-problem-framing"&gt;3. Get Better at Problem Framing&lt;a class="anchor ms-1" href="#3-get-better-at-problem-framing" aria-label="Permalink: 3. Get Better at Problem Framing"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before asking AI to implement anything, write down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The problem in one sentence&lt;/li&gt;
&lt;li&gt;The constraints&lt;/li&gt;
&lt;li&gt;The non-goals&lt;/li&gt;
&lt;li&gt;The acceptance criteria&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This habit improves both the AI output and your own clarity.&lt;/p&gt;
&lt;h3 id="4-work-in-small-reviewable-slices"&gt;4. Work in Small, Reviewable Slices&lt;a class="anchor ms-1" href="#4-work-in-small-reviewable-slices" aria-label="Permalink: 4. Work in Small, Reviewable Slices"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ask AI for smaller changes, not giant rewrites.&lt;/p&gt;
&lt;p&gt;Small slices make it easier to reason about behaviour, review quality, and rollback safely.&lt;/p&gt;
&lt;h3 id="5-raise-the-bar-for-code-reviews"&gt;5. Raise the Bar for Code Reviews&lt;a class="anchor ms-1" href="#5-raise-the-bar-for-code-reviews" aria-label="Permalink: 5. Raise the Bar for Code Reviews"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Review assumptions, failure modes, and operational impact, not just style.&lt;/p&gt;
&lt;p&gt;A useful question in every review: &amp;ldquo;What breaks first in production?&amp;rdquo;&lt;/p&gt;
&lt;h3 id="6-build-a-personal-ai-workflow"&gt;6. Build a Personal AI Workflow&lt;a class="anchor ms-1" href="#6-build-a-personal-ai-workflow" aria-label="Permalink: 6. Build a Personal AI Workflow"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create repeatable prompt patterns for tasks you do often:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Writing tests&lt;/li&gt;
&lt;li&gt;Refactoring legacy code&lt;/li&gt;
&lt;li&gt;Generating migration scripts&lt;/li&gt;
&lt;li&gt;Creating docs from code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Treat these as reusable tools in your engineering toolbox.&lt;/p&gt;
&lt;h3 id="7-keep-shipping-real-things"&gt;7. Keep Shipping Real Things&lt;a class="anchor ms-1" href="#7-keep-shipping-real-things" aria-label="Permalink: 7. Keep Shipping Real Things"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best learning still comes from production reality.&lt;/p&gt;
&lt;p&gt;Build, deploy, monitor, and improve. Feedback from real users teaches lessons no model can replace.&lt;/p&gt;
&lt;h2 id="what-this-means-for-juniors-vs-seniors"&gt;What This Means for Juniors vs Seniors&lt;a class="anchor ms-1" href="#what-this-means-for-juniors-vs-seniors" aria-label="Permalink: What This Means for Juniors vs Seniors"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AI changes the game for everyone, but not in exactly the same way.&lt;/p&gt;
&lt;p&gt;For junior developers, AI can be a force multiplier for learning if used correctly.&lt;/p&gt;
&lt;p&gt;It can explain unfamiliar concepts, generate examples, and speed up experimentation. But juniors still need mentorship and deliberate practice to build judgment.&lt;/p&gt;
&lt;p&gt;If you skip the fundamentals and rely only on generated output, you&amp;rsquo;ll progress fast on paper and slowly in reality.&lt;/p&gt;
&lt;p&gt;For senior developers, the expectation shifts from individual output to system-level impact.&lt;/p&gt;
&lt;p&gt;Seniors become the multipliers of multipliers: setting standards, designing guardrails, mentoring teams, and ensuring AI usage improves quality rather than eroding it.&lt;/p&gt;
&lt;p&gt;In short:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Juniors should use AI to learn faster&lt;/li&gt;
&lt;li&gt;Seniors should use AI to scale better decisions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both groups win when curiosity stays high and ego stays low.&lt;/p&gt;
&lt;h2 id="the-big-question-are-we-becoming-directors-instead-of-builders"&gt;The Big Question: Are We Becoming Directors Instead of Builders?&lt;a class="anchor ms-1" href="#the-big-question-are-we-becoming-directors-instead-of-builders" aria-label="Permalink: The Big Question: Are We Becoming Directors Instead of Builders?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Partly, yes, and that is not a bad thing.&lt;/p&gt;
&lt;p&gt;More of our time is moving toward direction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Defining intent&lt;/li&gt;
&lt;li&gt;Making trade-offs&lt;/li&gt;
&lt;li&gt;Reviewing outputs&lt;/li&gt;
&lt;li&gt;Orchestrating systems&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But we are still builders.&lt;/p&gt;
&lt;p&gt;Good directors in software are grounded in reality. They understand implementation details, constraints, and failure modes. They can still get into the code when needed.&lt;/p&gt;
&lt;p&gt;So the role is not &amp;ldquo;director instead of builder.&amp;rdquo; It is &amp;ldquo;builder with broader leverage.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;We are not giving up craftsmanship.&lt;/p&gt;
&lt;p&gt;We are applying craftsmanship at a higher level of abstraction.&lt;/p&gt;
&lt;p&gt;But let&amp;rsquo;s be honest about the uncomfortable part of this question.&lt;/p&gt;
&lt;p&gt;If one developer with AI can now do the work that previously required three, the natural business response is to hire fewer developers. That is already happening. It is likely to continue.&lt;/p&gt;
&lt;p&gt;The optimistic framing — that AI creates more software demand and therefore more developer jobs — is plausible in the long run. But it does not help the developer who is looking for work today, and it does not guarantee the transition is smooth or fair.&lt;/p&gt;
&lt;p&gt;I am not going to pretend the economics are simple.&lt;/p&gt;
&lt;p&gt;What I do believe is that developers who understand systems, take ownership of quality, and use AI as a serious tool will remain competitive for the work that does exist. That work will increasingly require judgment, not just output.&lt;/p&gt;
&lt;p&gt;The shift is real. The disruption is real. But the craft is not going away — it is just raising its entry bar.&lt;/p&gt;
&lt;h2 id="conclusion--my-opinion"&gt;Conclusion – My Opinion&lt;a class="anchor ms-1" href="#conclusion--my-opinion" aria-label="Permalink: Conclusion – My Opinion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I do not believe AI will eliminate software developers.&lt;/p&gt;
&lt;p&gt;I do believe it will split the field.&lt;/p&gt;
&lt;p&gt;Developers who keep learning, think in systems, and take ownership of outcomes will become more effective — not despite AI, but partly because of it.&lt;/p&gt;
&lt;p&gt;Developers who treat AI as a shortcut, blindly trusting its output without understanding the system underneath, will increasingly struggle to hold ground.&lt;/p&gt;
&lt;p&gt;The disruption happening right now is real. But I think the long-term demand for engineers who can reason clearly, design well, and take responsibility for what they ship is going to hold.&lt;/p&gt;
&lt;p&gt;The path forward is straightforward even if the road is uncertain: stay curious, deepen the fundamentals, use AI seriously, and never stop questioning the output.&lt;/p&gt;
&lt;h2 id="call-to-action"&gt;Call to Action&lt;a class="anchor ms-1" href="#call-to-action" aria-label="Permalink: Call to Action"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned at the start of this article, I am a .NET developer looking for my next role. If you know of any opportunities where I could help, please reach out.&lt;/p&gt;
&lt;p&gt;And if you are in the same position, message me as well. We are stronger when we support each other.&lt;/p&gt;</description></item><item><title>ACR vs ECR: Azure and AWS registries</title><link>https://blog-test.funkysi1701.com/posts/2026/acr-vs-ecr/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 23 Feb 2026 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/acr-vs-ecr/</guid><category term="Azure">Azure</category><category term="AWS">AWS</category><category term="Docker">Docker</category><category term="Containers">Containers</category><category term="DevOps">DevOps</category><category term="ACR">ACR</category><category term="ECR">ECR</category><category term="Cloud">Cloud</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/acr-vs-ecr.png"/><description>&lt;p&gt;As someone who works with both Azure and AWS regularly, I&amp;rsquo;ve had hands-on experience with both &lt;strong&gt;Azure Container Registry (ACR)&lt;/strong&gt; and &lt;strong&gt;AWS Elastic Container Registry (ECR)&lt;/strong&gt;. Recently, while migrating my blog&amp;rsquo;s deployment pipeline to use ECR, I encountered some interesting differences that are worth sharing.&lt;/p&gt;
&lt;h2 id="the-basics"&gt;The Basics&lt;a class="anchor ms-1" href="#the-basics" aria-label="Permalink: The Basics"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Both services provide secure, private Docker container registries that integrate seamlessly with their respective cloud ecosystems. They&amp;rsquo;re designed to store, manage, and deploy container images for your applications.&lt;/p&gt;
&lt;h3 id="azure-container-registry-acr"&gt;Azure Container Registry (ACR)&lt;a class="anchor ms-1" href="#azure-container-registry-acr" aria-label="Permalink: Azure Container Registry (ACR)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Fully managed Docker registry service&lt;/li&gt;
&lt;li&gt;Integrated with Azure Kubernetes Service (AKS), Azure Container Instances, and other Azure services&lt;/li&gt;
&lt;li&gt;Supports Docker images and OCI artifacts&lt;/li&gt;
&lt;li&gt;Available in multiple tiers: Basic, Standard, Premium&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aws-elastic-container-registry-ecr"&gt;AWS Elastic Container Registry (ECR)&lt;a class="anchor ms-1" href="#aws-elastic-container-registry-ecr" aria-label="Permalink: AWS Elastic Container Registry (ECR)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Fully managed Docker container registry&lt;/li&gt;
&lt;li&gt;Integrated with Amazon ECS, EKS, and AWS Lambda&lt;/li&gt;
&lt;li&gt;Supports Docker images and OCI artifacts&lt;/li&gt;
&lt;li&gt;Single pricing model with pay-as-you-go&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;OCI artifacts&lt;/strong&gt; are container-related objects that follow the Open Container Initiative (OCI) specifications. Originally, OCI defined standards for Docker container images, but now it covers a broader range of artifacts—including Helm charts, software bill of materials (SBOMs), and other files—stored in container registries.&lt;/p&gt;
&lt;h2 id="pricing-comparison"&gt;Pricing Comparison&lt;a class="anchor ms-1" href="#pricing-comparison" aria-label="Permalink: Pricing Comparison"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where things get interesting.&lt;/p&gt;
&lt;h3 id="azure-container-registry"&gt;Azure Container Registry&lt;a class="anchor ms-1" href="#azure-container-registry" aria-label="Permalink: Azure Container Registry"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ACR uses a &lt;strong&gt;tiered pricing model&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Basic&lt;/strong&gt;: £4.23/month + storage (£0.083/GB) + bandwidth&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standard&lt;/strong&gt;: £16.93/month + storage (£0.083/GB) + bandwidth&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Premium&lt;/strong&gt;: £42.32/month + storage (£0.083/GB) + bandwidth + geo-replication&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Premium tier adds features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Geo-replication across Azure regions&lt;/li&gt;
&lt;li&gt;Content trust for image signing&lt;/li&gt;
&lt;li&gt;Private link with private endpoints&lt;/li&gt;
&lt;li&gt;Enhanced throughput&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aws-elastic-container-registry"&gt;AWS Elastic Container Registry&lt;a class="anchor ms-1" href="#aws-elastic-container-registry" aria-label="Permalink: AWS Elastic Container Registry"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ECR uses &lt;strong&gt;simple pay-as-you-go pricing&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Storage&lt;/strong&gt;: $0.10/GB per month (£0.08/GB)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Transfer&lt;/strong&gt;: Standard AWS data transfer pricing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No base fee&lt;/strong&gt; - you only pay for what you use&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="authentication--setup"&gt;Authentication &amp; Setup&lt;a class="anchor ms-1" href="#authentication--setup" aria-label="Permalink: Authentication &amp;amp; Setup"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where I hit some friction with ECR.&lt;/p&gt;
&lt;h3 id="azure-container-registry-1"&gt;Azure Container Registry&lt;a class="anchor ms-1" href="#azure-container-registry-1" aria-label="Permalink: Azure Container Registry"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ACR authentication is straightforward:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Login using Azure CLI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;az acr login --name myregistry
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Or use service principal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker login myregistry.azurecr.io -u $SP_ID -p $SP_PASSWORD
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# In pipelines, it&amp;#39;s seamless with Azure DevOps tasks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Azure DevOps integration is particularly smooth - the &lt;code&gt;Docker@2&lt;/code&gt; task handles authentication automatically when using service connections.&lt;/p&gt;
&lt;h3 id="aws-elastic-container-registry-1"&gt;AWS Elastic Container Registry&lt;a class="anchor ms-1" href="#aws-elastic-container-registry-1" aria-label="Permalink: AWS Elastic Container Registry"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ECR authentication requires an extra step:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Get login password and pipe to docker login&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws ecr get-login-password --region eu-north-1 | &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; docker login --username AWS --password-stdin &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 111111111111.dkr.ecr.eu-north-1.amazonaws.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my Azure Pipelines, I had to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install AWS CLI (not included by default)&lt;/li&gt;
&lt;li&gt;Configure AWS credentials as environment variables&lt;/li&gt;
&lt;li&gt;Run the login command manually&lt;/li&gt;
&lt;/ol&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;task&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;CmdLine@2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;displayName&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Install AWS CLI&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; curl &amp;#34;https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip&amp;#34; -o &amp;#34;awscliv2.zip&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; unzip -q awscliv2.zip
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; ./aws/install --bin-dir ~/.local/bin --install-dir ~/.local/aws-cli
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;task&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;CmdLine@2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;displayName&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Login to ECR&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;$(AWS_ACCESS_KEY_ID)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;$(AWS_SECRET_ACCESS_KEY)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; export PATH=$HOME/.local/bin:$PATH
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; aws ecr get-login-password --region eu-north-1 | \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; docker login --username AWS --password-stdin \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 111111111111.dkr.ecr.eu-north-1.amazonaws.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Winner&lt;/strong&gt;: ACR (simpler authentication, especially in Azure DevOps)&lt;/p&gt;
&lt;h2 id="image-naming--urls"&gt;Image Naming &amp; URLs&lt;a class="anchor ms-1" href="#image-naming--urls" aria-label="Permalink: Image Naming &amp;amp; URLs"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="azure-container-registry-2"&gt;Azure Container Registry&lt;a class="anchor ms-1" href="#azure-container-registry-2" aria-label="Permalink: Azure Container Registry"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Clean, predictable naming:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;myregistry.azurecr.io/myapp:v1.0.0
myregistry.azurecr.io/namespace/myapp:latest
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="aws-elastic-container-registry-2"&gt;AWS Elastic Container Registry&lt;a class="anchor ms-1" href="#aws-elastic-container-registry-2" aria-label="Permalink: AWS Elastic Container Registry"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Includes your AWS account ID:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;111111111111.dkr.ecr.eu-north-1.amazonaws.com/funkysi1701/blog:10.1.1.123-develop
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The account ID in the URL may pose a security consideration - it&amp;rsquo;s visible to anyone who has access to your images or deployment configs. Attackers could use the account ID for targeted phishing, social engineering, or brute-force attacks. If combined with leaked credentials or misconfigured permissions, it makes it easier for someone to identify and target your AWS resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;/strong&gt;: ACR (cleaner URLs)&lt;/p&gt;
&lt;h2 id="features-comparison"&gt;Features Comparison&lt;a class="anchor ms-1" href="#features-comparison" aria-label="Permalink: Features Comparison"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;ACR&lt;/th&gt;
&lt;th&gt;ECR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Image Scanning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Premium tier&lt;/td&gt;
&lt;td&gt;✅ Included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vulnerability Scanning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Premium tier&lt;/td&gt;
&lt;td&gt;✅ Basic + Enhanced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Geo-Replication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Premium tier&lt;/td&gt;
&lt;td&gt;❌ Manual setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Webhooks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ All tiers&lt;/td&gt;
&lt;td&gt;✅ Included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Image Retention Policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ All tiers&lt;/td&gt;
&lt;td&gt;✅ Lifecycle policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Private Endpoints&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Premium tier&lt;/td&gt;
&lt;td&gt;✅ VPC endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Image Signing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Content Trust&lt;/td&gt;
&lt;td&gt;✅ AWS Signer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cross-Region Replication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Premium&lt;/td&gt;
&lt;td&gt;❌ Requires manual setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Import from Docker Hub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Built-in&lt;/td&gt;
&lt;td&gt;❌ Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="integration-with-kubernetes"&gt;Integration with Kubernetes&lt;a class="anchor ms-1" href="#integration-with-kubernetes" aria-label="Permalink: Integration with Kubernetes"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="acr--aks"&gt;ACR + AKS&lt;a class="anchor ms-1" href="#acr--aks" aria-label="Permalink: ACR + AKS"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Seamless integration with Azure Kubernetes Service:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Attach ACR to AKS cluster&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;az aks update --name myaks --resource-group mygroup --attach-acr myregistry
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;AKS nodes can pull images without credentials. Magical.&lt;/p&gt;
&lt;h3 id="ecr--eks"&gt;ECR + EKS&lt;a class="anchor ms-1" href="#ecr--eks" aria-label="Permalink: ECR + EKS"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Also integrated, but requires IAM roles:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Attach IAM policy to EKS node role&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws iam attach-role-policy &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --role-name eksNodeRole &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Works well once configured, but requires understanding of AWS IAM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;/strong&gt;: Tie (both integrate well with their respective K8s offerings)&lt;/p&gt;
&lt;h2 id="developer-experience"&gt;Developer Experience&lt;a class="anchor ms-1" href="#developer-experience" aria-label="Permalink: Developer Experience"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="what-i-like-about-acr"&gt;What I Like About ACR&lt;a class="anchor ms-1" href="#what-i-like-about-acr" aria-label="Permalink: What I Like About ACR"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Simple authentication in Azure DevOps&lt;/li&gt;
&lt;li&gt;Clean, readable image URLs&lt;/li&gt;
&lt;li&gt;Excellent documentation&lt;/li&gt;
&lt;li&gt;Azure Portal UI is intuitive&lt;/li&gt;
&lt;li&gt;Helm chart support is first-class&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="what-i-like-about-ecr"&gt;What I Like About ECR&lt;a class="anchor ms-1" href="#what-i-like-about-ecr" aria-label="Permalink: What I Like About ECR"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No minimum cost - truly pay-per-use&lt;/li&gt;
&lt;li&gt;Built-in vulnerability scanning at all levels&lt;/li&gt;
&lt;li&gt;AWS CLI is powerful and ubiquitous&lt;/li&gt;
&lt;li&gt;Great for multi-cloud strategies&lt;/li&gt;
&lt;li&gt;Excellent API and automation support&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="pain-points"&gt;Pain Points&lt;a class="anchor ms-1" href="#pain-points" aria-label="Permalink: Pain Points"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;ACR&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Premium tier gets expensive for features that should be standard&lt;/li&gt;
&lt;li&gt;Minimum £4/month even for tiny projects&lt;/li&gt;
&lt;li&gt;Geo-replication requires Premium tier (£42/month)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Geo-replication is important because it allows your container images and artifacts to be stored and accessed in multiple geographic regions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ECR&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Authentication is more complex outside AWS&lt;/li&gt;
&lt;li&gt;Account ID in image URL&lt;/li&gt;
&lt;li&gt;Requires AWS CLI installation in non-AWS CI/CD&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="my-real-world-experience"&gt;My Real-World Experience&lt;a class="anchor ms-1" href="#my-real-world-experience" aria-label="Permalink: My Real-World Experience"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For my blog&amp;rsquo;s deployment pipeline, I recently migrated from ACR to ECR primarily for &lt;strong&gt;cost reasons&lt;/strong&gt;. Here&amp;rsquo;s what I learned:&lt;/p&gt;
&lt;h3 id="the-migration"&gt;The Migration&lt;a class="anchor ms-1" href="#the-migration" aria-label="Permalink: The Migration"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Before (ACR)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cost: ~£4.50/month (Basic tier + minimal storage)&lt;/li&gt;
&lt;li&gt;Authentication: Seamless in Azure DevOps&lt;/li&gt;
&lt;li&gt;Image URLs: Clean and simple&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;After (ECR)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cost: £0/month (due to free trial)&lt;/li&gt;
&lt;li&gt;Authentication: Required custom pipeline steps&lt;/li&gt;
&lt;li&gt;Image URLs: Include AWS account ID&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="was-it-worth-it"&gt;Was It Worth It?&lt;a class="anchor ms-1" href="#was-it-worth-it" aria-label="Permalink: Was It Worth It?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For my small personal project, &lt;strong&gt;yes&lt;/strong&gt; - saving money is meaningful. But the setup was more complex than I expected.&lt;/p&gt;
&lt;p&gt;For enterprise workloads, I&amp;rsquo;d still choose ACR Premium if I needed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Geo-replication&lt;/li&gt;
&lt;li&gt;Content trust&lt;/li&gt;
&lt;li&gt;Azure-native integration&lt;/li&gt;
&lt;li&gt;Enterprise support&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="recommendations"&gt;Recommendations&lt;a class="anchor ms-1" href="#recommendations" aria-label="Permalink: Recommendations"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="choose-acr-if"&gt;Choose ACR if&lt;a class="anchor ms-1" href="#choose-acr-if" aria-label="Permalink: Choose ACR if"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;✅ You&amp;rsquo;re heavily invested in Azure ecosystem&lt;br&gt;
✅ You need geo-replication&lt;br&gt;
✅ You want seamless AKS integration&lt;br&gt;
✅ You value simplified authentication&lt;br&gt;
✅ You need Azure-native compliance features&lt;/p&gt;
&lt;h3 id="choose-ecr-if"&gt;Choose ECR if&lt;a class="anchor ms-1" href="#choose-ecr-if" aria-label="Permalink: Choose ECR if"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;✅ You want zero minimum costs&lt;br&gt;
✅ You&amp;rsquo;re on AWS or multi-cloud&lt;br&gt;
✅ You need built-in vulnerability scanning&lt;br&gt;
✅ You prefer pay-per-use pricing&lt;br&gt;
✅ You&amp;rsquo;re comfortable with IAM and AWS CLI&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Both ACR and ECR are excellent services. Your choice should depend on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Your cloud platform&lt;/strong&gt; - Use the registry that matches your deployment target&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your budget&lt;/strong&gt; - ECR wins for small projects, ACR Premium for enterprise features&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your team&amp;rsquo;s expertise&lt;/strong&gt; - Stick with what your team knows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your requirements&lt;/strong&gt; - Need geo-replication? ACR Premium. Need low-cost? ECR.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For my personal projects, I&amp;rsquo;m happy with ECR&amp;rsquo;s cost savings. For enterprise work, I still recommend ACR Premium for its advanced features and Azure integration.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s your experience with container registries? Let me know in the comments!&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources&lt;a class="anchor ms-1" href="#resources" aria-label="Permalink: Resources"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/container-registry/" target="_blank" rel="noopener noreferrer"&gt;Azure Container Registry Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/ecr/" target="_blank" rel="noopener noreferrer"&gt;AWS ECR Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-gb/pricing/details/container-registry/" target="_blank" rel="noopener noreferrer"&gt;ACR Pricing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ecr/pricing/" target="_blank" rel="noopener noreferrer"&gt;ECR Pricing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>NDC London 2026</title><link>https://blog-test.funkysi1701.com/posts/2026/ndc-london-2026/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 02 Feb 2026 20:46:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/ndc-london-2026/</guid><category term="NDCLondon">NDCLondon</category><category term="Conference">Conference</category><category term="DotNet">DotNet</category><category term="AI">AI</category><category term="Accessibility">Accessibility</category><category term="WCAG">WCAG</category><category term="Playwright">Playwright</category><category term="Testing">Testing</category><category term="Azure">Azure</category><category term="OpenTelemetry">OpenTelemetry</category><category term="UX">UX</category><category term="Volunteering">Volunteering</category><category term="2026">2026</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2026/ndc-me.jpg"/><description>&lt;img src="https://blog-test.funkysi1701.com/images/2026/ndc-me.jpg" alt="Volunteering at NDC London 2026" width="250px" style="float:left;padding-right: 15px; " /&gt;
&lt;p&gt;For the second year running, I had the privilege of volunteering at NDC London – one of Europe&amp;rsquo;s premier software development conferences. This year&amp;rsquo;s event was packed with insights on AI, accessibility, testing automation, and the future of software development. If you&amp;rsquo;re interested in my first experience, check out my &lt;a href="https://blog-test.funkysi1701.com/posts/2025/volunteering-at-ndc/"&gt;2025 report&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;The volunteer experience was just as rewarding as last year – the team was fantastic, the energy was incredible, and the sense of community was palpable. In this post, I&amp;rsquo;ll focus on the talks I attended and the key insights I gained from them.&lt;/p&gt;
&lt;p&gt;As I mentioned last year, volunteering gave me a &lt;strong&gt;superpower&lt;/strong&gt;: increased confidence to network with speakers, vendors, fellow volunteers, and attendees. The connections you make at conferences like this are invaluable, and being part of the team made it even easier to engage with the community.&lt;/p&gt;
&lt;h2 id="wednesday"&gt;Wednesday&lt;a class="anchor ms-1" href="#wednesday" aria-label="Permalink: Wednesday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="lets-break-some-wcag-rules-speaker-elise-kristiansen"&gt;Let’s Break Some WCAG Rules (Speaker: Elise Kristiansen)&lt;a class="anchor ms-1" href="#lets-break-some-wcag-rules-speaker-elise-kristiansen" aria-label="Permalink: Let’s Break Some WCAG Rules (Speaker: Elise Kristiansen)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This eye-opening talk examined how pervasively websites violate Web Content Accessibility Guidelines (WCAG). For those unfamiliar, WCAG provides a framework to make web content accessible to everyone, including people with disabilities. The guidelines are organized into three conformance levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level A&lt;/strong&gt; - The bare minimum requirements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level AA&lt;/strong&gt; - The legal requirement (what most laws mandate)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level AAA&lt;/strong&gt; - The gold standard, aspirational but not legally required&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The statistics Elise shared were sobering: 15-25% of people have some form of disability (whether permanent, temporary, or situational), yet a staggering &lt;strong&gt;94.8% of websites contain at least one WCAG AA violation&lt;/strong&gt; – meaning they&amp;rsquo;re actually breaking the law.&lt;/p&gt;
&lt;p&gt;One of the most powerful demonstrations was a colour blindness test where only colour blind individuals could read certain numbers. It really drove home how design choices can inadvertently exclude significant portions of our users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WCAG compliance isn&amp;rsquo;t optional – it&amp;rsquo;s a legal requirement and moral imperative&lt;/li&gt;
&lt;li&gt;Stop using &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for everything; HTML is semantically rich for a reason&lt;/li&gt;
&lt;li&gt;Consider learning to use a screen reader to understand user experiences better&lt;/li&gt;
&lt;li&gt;Accessibility benefits everyone, not just those with disabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="social-engineering-hacking-humans-speaker-pawel-sucholbiak"&gt;Social Engineering: Hacking Humans (Speaker: Pawel Sucholbiak)&lt;a class="anchor ms-1" href="#social-engineering-hacking-humans-speaker-pawel-sucholbiak" aria-label="Permalink: Social Engineering: Hacking Humans (Speaker: Pawel Sucholbiak)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A timely reminder that as soon as humans enter the equation, social engineering becomes a significant security risk. This talk explored various tactics malicious actors use to manipulate people into divulging confidential information or performing actions that compromise security.&lt;/p&gt;
&lt;p&gt;Pawel demonstrated real-world scenarios like phishing emails that appear to come from trusted colleagues, pretexting phone calls where attackers impersonate IT support, and how seemingly innocent information shared on social media can be weaponized. The human element remains the weakest link in any security chain.&lt;/p&gt;
&lt;h3 id="supercharged-testing-ai-powered-workflows-with-playwright--mcp-speaker-debbie-obrien"&gt;Supercharged Testing: AI-Powered Workflows with Playwright + MCP (Speaker: Debbie O’Brien)&lt;a class="anchor ms-1" href="#supercharged-testing-ai-powered-workflows-with-playwright--mcp-speaker-debbie-obrien" aria-label="Permalink: Supercharged Testing: AI-Powered Workflows with Playwright + MCP (Speaker: Debbie O’Brien)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;d heard Debbie discuss the Playwright MCP (Model Context Protocol) on .NET Rocks, but seeing it demonstrated live was transformative. This session showed how AI can dramatically enhance testing workflows by understanding test intent and generating Playwright test code.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve already started using it to write some tests for this very website!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaway:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Experiment with the Playwright MCP – it&amp;rsquo;s a game-changer for test automation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-undersea-cable-network-speaker-richard-campbell"&gt;The Undersea Cable Network (Speaker: Richard Campbell)&lt;a class="anchor ms-1" href="#the-undersea-cable-network-speaker-richard-campbell" aria-label="Permalink: The Undersea Cable Network (Speaker: Richard Campbell)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Richard took us on a fascinating journey through the history of undersea telecommunications cables – the literal backbone of the internet. He explored how these cables are laid, maintained, and the significant challenges when they&amp;rsquo;re damaged (whether accidental or deliberate). It&amp;rsquo;s humbling to realize that our globally connected world depends on physical cables crossing ocean floors.&lt;/p&gt;
&lt;h3 id="java-sucks-so-c-didnt-have-to-speaker-adele-carpenter"&gt;Java Sucks (So C# Didn’t Have To) (Speaker: Adele Carpenter)&lt;a class="anchor ms-1" href="#java-sucks-so-c-didnt-have-to-speaker-adele-carpenter" aria-label="Permalink: Java Sucks (So C# Didn’t Have To) (Speaker: Adele Carpenter)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An entertaining and insightful exploration of Java&amp;rsquo;s history, examining how its early popularity locked in certain design decisions that became problematic over time. Adele showed how C# learned from Java&amp;rsquo;s mistakes and made different choices that enabled better evolution. The key lesson: early success can create technical debt that&amp;rsquo;s nearly impossible to pay down.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://speakerdeck.com/97adele/java-sucks-so-c-number-didnt-have-to" target="_blank" rel="noopener noreferrer"&gt;View the slides&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id="think-like-a-user-practical-ux-design-tips-for-developers-speaker-lex-lofthouse"&gt;Think Like a User: Practical UX Design Tips for Developers (Speaker: Lex Lofthouse)&lt;a class="anchor ms-1" href="#think-like-a-user-practical-ux-design-tips-for-developers-speaker-lex-lofthouse" aria-label="Permalink: Think Like a User: Practical UX Design Tips for Developers (Speaker: Lex Lofthouse)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This session challenged developers to shift perspectives and consider user experience from the ground up. Lex provided practical, actionable advice for creating more intuitive interfaces.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.figma.com/deck/FgeSzQhT74JlnxW3iiONqj/UX-Tips?node-id=1-42&amp;amp;t=h9PIcTBhU6KRDMNU-1" target="_blank" rel="noopener noreferrer"&gt;View the slides&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommended Reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;The Design of Everyday Things&lt;/em&gt; by Don Norman&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="thursday"&gt;Thursday&lt;a class="anchor ms-1" href="#thursday" aria-label="Permalink: Thursday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="opentelemetry-at-scale-101-intro-to-opamp-speakers-aakansha-priya-and-adriana-villela"&gt;OpenTelemetry At Scale 101: Intro to OpAMP (Speakers: Aakansha Priya and Adriana Villela)&lt;a class="anchor ms-1" href="#opentelemetry-at-scale-101-intro-to-opamp-speakers-aakansha-priya-and-adriana-villela" aria-label="Permalink: OpenTelemetry At Scale 101: Intro to OpAMP (Speakers: Aakansha Priya and Adriana Villela)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This session introduced OpAMP (Open Agent Management Protocol) for managing OpenTelemetry collectors at scale. While the scale discussed was beyond my current needs, it was valuable to understand the challenges and solutions for production observability in large distributed systems.&lt;/p&gt;
&lt;h3 id="a-defence-of-technical-excellence-speaker-chris-simon"&gt;A Defence of Technical Excellence (Speaker: Chris Simon)&lt;a class="anchor ms-1" href="#a-defence-of-technical-excellence-speaker-chris-simon" aria-label="Permalink: A Defence of Technical Excellence (Speaker: Chris Simon)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Chris made a compelling argument for maintaining high technical standards even under pressure to deliver quickly. Technical excellence isn&amp;rsquo;t about perfectionism – it&amp;rsquo;s about sustainable, maintainable code that serves the business long-term.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://chrissimon.au/speaking/talks/a-defence-of-technical-excellence/?read-more=1" target="_blank" rel="noopener noreferrer"&gt;Read more about this talk&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id="how-to-git-away-with-murder-speaker-sergès-goma"&gt;How to Git Away with Murder (Speaker: Sergès Goma)&lt;a class="anchor ms-1" href="#how-to-git-away-with-murder-speaker-sergès-goma" aria-label="Permalink: How to Git Away with Murder (Speaker: Sergès Goma)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A humorous yet practical look at Git workflows and how to recover from common (and not-so-common) Git disasters. The Q&amp;amp;A session at the end turned into a group therapy session where attendees shared their most spectacular Git mishaps and recovery stories. If you&amp;rsquo;ve ever accidentally force-pushed to main, this talk was for you!&lt;/p&gt;
&lt;h3 id="code-that-writes-code-net-source-generators-speaker-glenn-f-henriksen"&gt;Code That Writes Code: .NET Source Generators (Speaker: Glenn F. Henriksen)&lt;a class="anchor ms-1" href="#code-that-writes-code-net-source-generators-speaker-glenn-f-henriksen" aria-label="Permalink: Code That Writes Code: .NET Source Generators (Speaker: Glenn F. Henriksen)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Source generators are one of .NET&amp;rsquo;s most powerful yet underutilized features. Glenn demonstrated how they can eliminate boilerplate, improve performance by moving work to compile-time, and create type-safe code generation patterns. This is definitely an area I need to explore more for my own projects.&lt;/p&gt;
&lt;h3 id="warm-and-fuzzy-semantic-search-in-net-speaker-jonathan-j-tower"&gt;Warm and Fuzzy: Semantic Search in .NET (Speaker: Jonathan “J.” Tower)&lt;a class="anchor ms-1" href="#warm-and-fuzzy-semantic-search-in-net-speaker-jonathan-j-tower" aria-label="Permalink: Warm and Fuzzy: Semantic Search in .NET (Speaker: Jonathan “J.” Tower)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Jonathan delivered an excellent introduction to implementing semantic search using vector databases. He covered several options for .NET developers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQL Server 2025&lt;/strong&gt; with native vector support&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Cosmos DB&lt;/strong&gt; for NoSQL vector storage&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Qdrant&lt;/strong&gt; as a specialized vector database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The talk also touched on &lt;strong&gt;Semantic Kernel&lt;/strong&gt;, which is now part of the Microsoft Agent Framework – a significant development for building intelligent applications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Action Items:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement semantic search for my blog to improve content discovery&lt;/li&gt;
&lt;li&gt;Explore the &lt;a href="https://github.com/trailheadtechnology/dotnet-semantic-search/tree/main/code" target="_blank" rel="noopener noreferrer"&gt;demo code on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="coding-4-fun-8-bit-game-emulation-in-net-speaker-alex-thissen"&gt;Coding 4 Fun: 8-bit Game Emulation in .NET (Speaker: Alex Thissen)&lt;a class="anchor ms-1" href="#coding-4-fun-8-bit-game-emulation-in-net-speaker-alex-thissen" aria-label="Permalink: Coding 4 Fun: 8-bit Game Emulation in .NET (Speaker: Alex Thissen)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Pure fun! Alex walked through building an 8-bit game emulator in .NET, demonstrating low-level programming concepts in a modern language. A great reminder that not everything we build needs to be &amp;ldquo;enterprise-ready&amp;rdquo; – sometimes coding is just about learning and enjoyment. Lots of shifting bytes around, so a great example of the different things you can do with .NET.&lt;/p&gt;
&lt;h2 id="friday"&gt;Friday&lt;a class="anchor ms-1" href="#friday" aria-label="Permalink: Friday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="keynote-ai-powered-app-development-speaker-steve-sanderson"&gt;Keynote: AI-Powered App Development (Speaker: Steve Sanderson)&lt;a class="anchor ms-1" href="#keynote-ai-powered-app-development-speaker-steve-sanderson" aria-label="Permalink: Keynote: AI-Powered App Development (Speaker: Steve Sanderson)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Steve Sanderson delivered an inspiring keynote on how AI is transforming application development. The &lt;a href="https://github.com/features/copilot/cli" target="_blank" rel="noopener noreferrer"&gt;GitHub Copilot CLI&lt;/a&gt;
was demonstrated, with a new feature added in front of our eyes. Hundreds of Pull Requests can be generated with AI, but they all need reviewing and maintaining by Software Developers and there are no easy answers for managing that.&lt;/p&gt;
&lt;h3 id="what-in-the-hunger-games-is-happening-with-recruitment-speaker-suzi-edwards-alexander"&gt;What in the Hunger Games is Happening with Recruitment? (Speaker: Suzi Edwards-Alexander)&lt;a class="anchor ms-1" href="#what-in-the-hunger-games-is-happening-with-recruitment-speaker-suzi-edwards-alexander" aria-label="Permalink: What in the Hunger Games is Happening with Recruitment? (Speaker: Suzi Edwards-Alexander)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A frank and often amusing look at the current state of tech recruitment. Suzi traced how we arrived at today&amp;rsquo;s challenging hiring landscape – from the first interview questions created by Thomas Edison, to the rise of LinkedIn and modern recruitment processes. Recruitment is broken, and there are no easy ways of fixing it.&lt;/p&gt;
&lt;h3 id="the-great-brain-robbery-navigating-the-dark-future-of-online-manipulation-speaker-jeff-watkins"&gt;The Great Brain Robbery: Navigating the Dark Future of Online Manipulation (Speaker: Jeff Watkins)&lt;a class="anchor ms-1" href="#the-great-brain-robbery-navigating-the-dark-future-of-online-manipulation-speaker-jeff-watkins" aria-label="Permalink: The Great Brain Robbery: Navigating the Dark Future of Online Manipulation (Speaker: Jeff Watkins)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A sobering examination of how online platforms use psychological manipulation and dark patterns to exploit users&amp;rsquo; attention and data. Jeff didn&amp;rsquo;t just highlight the problems – he offered strategies for recognizing and resisting these tactics, both as developers and as users. This talk was rather bleak reinforcing the notion that you can not trust anything you see or read online.&lt;/p&gt;
&lt;h3 id="beyond-the-ai-hype-whats-real-whats-next-speaker-richard-campbell"&gt;Beyond the AI Hype: What’s Real, What’s Next (Speaker: Richard Campbell)&lt;a class="anchor ms-1" href="#beyond-the-ai-hype-whats-real-whats-next-speaker-richard-campbell" aria-label="Permalink: Beyond the AI Hype: What’s Real, What’s Next (Speaker: Richard Campbell)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Richard cut through the AI hype to examine what&amp;rsquo;s genuinely transformative versus what&amp;rsquo;s just marketing. He explored current capabilities, realistic near-term developments, and the fundamental limitations we need to understand. A perfect counterbalance to the morning&amp;rsquo;s optimistic keynote – both perspectives are necessary for making informed decisions about AI adoption.&lt;/p&gt;
&lt;h3 id="resilient-by-design-speaker-chris-ayers"&gt;Resilient by Design (Speaker: Chris Ayers)&lt;a class="anchor ms-1" href="#resilient-by-design-speaker-chris-ayers" aria-label="Permalink: Resilient by Design (Speaker: Chris Ayers)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The final session I attended focused on building resilient systems in Azure from the ground up. Chris covered how much downtime you can have if your SLA is 99.99% (8.6s a day see &lt;a href="https://uptime.is" target="_blank" rel="noopener noreferrer"&gt;uptime.is&lt;/a&gt;
) – but more importantly, the mindset shift required to design for failure rather than just success. In production, it&amp;rsquo;s not &lt;em&gt;if&lt;/em&gt; things will fail, but &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;how gracefully&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="networking-break-jetbrains-rider-team"&gt;Networking Break: JetBrains Rider Team&lt;a class="anchor ms-1" href="#networking-break-jetbrains-rider-team" aria-label="Permalink: Networking Break: JetBrains Rider Team"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I skipped one session to have an extended conversation with the &lt;a href="https://www.jetbrains.com/rider/" target="_blank" rel="noopener noreferrer"&gt;JetBrains Rider&lt;/a&gt;
team at their booth. These unstructured conversations are often where you get the most value at conferences – I am a big fan of Visual Studio, but I have never tried Rider, this informal chat has encouraged me to download Rider and give it a try.&lt;/p&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;a class="anchor ms-1" href="#final-thoughts" aria-label="Permalink: Final Thoughts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;NDC London 2026 was another incredible experience. The breadth of topics – from accessibility and UX to AI, observability, and system resilience – reflects the diverse skills modern developers need.&lt;/p&gt;
&lt;p&gt;My key takeaways from this year:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Accessibility is non-negotiable&lt;/strong&gt; – both legally and morally&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI tools are here to stay&lt;/strong&gt; – learn to leverage them effectively&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Technical excellence matters&lt;/strong&gt; – shortcuts today become tomorrow&amp;rsquo;s technical debt&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Community is everything&lt;/strong&gt; – the conversations between sessions were as valuable as the talks themselves&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Huge thanks to the NDC organizing team, my fellow volunteers, all the speakers who shared their knowledge, and the attendees who made this such an engaging event. If you get the chance to attend (or volunteer at) &lt;a href="https://ndcconferences.com/" target="_blank" rel="noopener noreferrer"&gt;NDC Conferences&lt;/a&gt;
, I highly recommend it.&lt;/p&gt;
&lt;p&gt;Interested in attending NDC London 2027? Follow &lt;a href="https://twitter.com/NDC_Conferences" target="_blank" rel="noopener noreferrer"&gt;@NDC_Conferences&lt;/a&gt;
for updates!&lt;/p&gt;
&lt;p&gt;See you at NDC London 2027! 🚀&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="The Awesome Volunteer Team at NDC London" src="https://blog-test.funkysi1701.com/images/2026/ndc-team.jpg" loading="lazy"
width="2048" height="1536"
/&gt;
&lt;/p&gt;</description></item><item><title>Parkrun Results</title><link>https://blog-test.funkysi1701.com/parkrun/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/parkrun/</guid><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2026/Parkrun.jpg"/><description>&lt;h2 id="parkrun"&gt;Parkrun&lt;a class="anchor ms-1" href="#parkrun" aria-label="Permalink: Parkrun"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/2026/Parkrun.jpg" alt="parkrun" style="width:200px;height:auto;float:left;margin:0 1.5em 1em 0;" /&gt;
&lt;p&gt;Parkrun is a free, weekly, community event offering 5km timed runs and walks in parks and open spaces around the world. It is open to everyone, regardless of age or ability, and is run entirely by volunteers. You can find your nearest event, register for a barcode, and view results at the official &lt;a href="https://www.parkrun.com/" target="_blank" rel="noopener noreferrer"&gt;parkrun website&lt;/a&gt;
. For more information about how it works, visit the &lt;a href="https://www.parkrun.org.uk/" target="_blank" rel="noopener noreferrer"&gt;parkrun UK page&lt;/a&gt;
or check out the &lt;a href="https://blog.parkrun.com/" target="_blank" rel="noopener noreferrer"&gt;parkrun blog&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;I started parkrun in 2025. The &lt;strong&gt;parkrun results&lt;/strong&gt; table below is generated from official parkrun.org.uk data. Other races, walks, and notes are maintained by hand in the sections further down.&lt;/p&gt;
&lt;!-- BEGIN PARKRUN_GENERATED --&gt;
&lt;h2 id="progress-chart"&gt;Progress chart&lt;a class="anchor ms-1" href="#progress-chart" aria-label="Permalink: Progress chart"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div style="background: #f5f5f5; padding: 20px; border-radius: 8px; margin: 20px 0; color: #333333;"&gt;
&lt;h3 style="margin-top: 0;"&gt;5k Parkrun Times&lt;/h3&gt;
&lt;p style="font-size: 0.9em; margin-top: 0;"&gt;Most recent 10 runs (left to right by date); official parkrun results (taller bar = slower time). Green bars are personal bests at that course.&lt;/p&gt;
&lt;div class="table-responsive"&gt;
&lt;table style="width: 100%; border-collapse: collapse; background: white; border-radius: 4px;"&gt;
&lt;tr style="vertical-align: bottom; height: 250px;"&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;40m 16s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 137px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;25 Apr&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;39m 45s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 136px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;9 May&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;39m 06s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 134px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;23 May&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;1h 04m 56s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 210px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;4 Jul&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;36m 27s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 126px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;18 Jul&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;38m 03s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 131px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;25 Jul&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;37m 52s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 130px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;1 Aug&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;37m 07s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 128px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;8 Aug&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;34m 11s&lt;/div&gt;
&lt;div style="background: #4CAF50; height: 120px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;15 Aug&lt;/div&gt;
&lt;/td&gt;
&lt;td style="text-align: center; padding: 5px; position: relative;"&gt;
&lt;div style="position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-weight: bold; font-size: 11px;"&gt;38m 17s&lt;/div&gt;
&lt;div style="background: #2196F3; height: 132px; margin: 0 auto; width: 60px; border-radius: 4px 4px 0 0;"&gt;&lt;/div&gt;
&lt;div style="font-size: 10px; margin-top: 5px;"&gt;22 Aug&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="parkrun-results"&gt;Parkrun results&lt;a class="anchor ms-1" href="#parkrun-results" aria-label="Permalink: Parkrun results"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Official 5 km parkrun times from &lt;a href="https://www.parkrun.org.uk/parkrunner/11453050/" target="_blank" rel="noopener noreferrer"&gt;parkrun.org.uk&lt;/a&gt;
.&lt;/p&gt;
&lt;h3 id="2026"&gt;2026&lt;a class="anchor ms-1" href="#2026" aria-label="Permalink: 2026"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Run&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Results&lt;/th&gt;
&lt;th&gt;min/km&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;22 August 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 38m 17s&lt;/td&gt;
&lt;td&gt;07m 39s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;15 August 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 34m 11s&lt;/td&gt;
&lt;td&gt;06m 50s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;8 August 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 37m 07s&lt;/td&gt;
&lt;td&gt;07m 25s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Withernsea Promenade parkrun&lt;/td&gt;
&lt;td&gt;1 August 2026&lt;/td&gt;
&lt;td&gt;Withernsea Promenade&lt;/td&gt;
&lt;td&gt;0h 37m 52s&lt;/td&gt;
&lt;td&gt;07m 34s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;25 July 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 38m 03s&lt;/td&gt;
&lt;td&gt;07m 37s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;18 July 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 36m 27s&lt;/td&gt;
&lt;td&gt;07m 17s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;4 July 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;1h 04m 56s&lt;/td&gt;
&lt;td&gt;12m 59s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Poolsbrook parkrun&lt;/td&gt;
&lt;td&gt;23 May 2026&lt;/td&gt;
&lt;td&gt;Poolsbrook&lt;/td&gt;
&lt;td&gt;0h 39m 06s&lt;/td&gt;
&lt;td&gt;07m 49s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frickley Country parkrun&lt;/td&gt;
&lt;td&gt;9 May 2026&lt;/td&gt;
&lt;td&gt;Frickley Country&lt;/td&gt;
&lt;td&gt;0h 39m 45s&lt;/td&gt;
&lt;td&gt;07m 57s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;25 April 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 40m 16s&lt;/td&gt;
&lt;td&gt;08m 03s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;18 April 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 36m 27s&lt;/td&gt;
&lt;td&gt;07m 17s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;11 April 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 40m 02s&lt;/td&gt;
&lt;td&gt;08m 00s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;14 March 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 39m 49s&lt;/td&gt;
&lt;td&gt;07m 58s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scunthorpe parkrun&lt;/td&gt;
&lt;td&gt;14 February 2026&lt;/td&gt;
&lt;td&gt;Scunthorpe&lt;/td&gt;
&lt;td&gt;0h 38m 21s&lt;/td&gt;
&lt;td&gt;07m 40s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;24 January 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 39m 42s&lt;/td&gt;
&lt;td&gt;07m 56s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;17 January 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;1h 17m 00s&lt;/td&gt;
&lt;td&gt;15m 24s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;10 January 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 39m 46s&lt;/td&gt;
&lt;td&gt;07m 57s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;3 January 2026&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 56m 34s&lt;/td&gt;
&lt;td&gt;11m 19s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Humber Bridge parkrun&lt;/td&gt;
&lt;td&gt;1 January 2026&lt;/td&gt;
&lt;td&gt;Humber Bridge&lt;/td&gt;
&lt;td&gt;0h 43m 59s&lt;/td&gt;
&lt;td&gt;08m 48s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="2025"&gt;2025&lt;a class="anchor ms-1" href="#2025" aria-label="Permalink: 2025"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Run&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Results&lt;/th&gt;
&lt;th&gt;min/km&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;27 December 2025&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 41m 13s&lt;/td&gt;
&lt;td&gt;08m 15s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Normanby Hall parkrun&lt;/td&gt;
&lt;td&gt;13 December 2025&lt;/td&gt;
&lt;td&gt;Normanby Hall&lt;/td&gt;
&lt;td&gt;0h 37m 28s&lt;/td&gt;
&lt;td&gt;07m 30s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Goole parkrun&lt;/td&gt;
&lt;td&gt;29 November 2025&lt;/td&gt;
&lt;td&gt;Goole&lt;/td&gt;
&lt;td&gt;0h 40m 49s&lt;/td&gt;
&lt;td&gt;08m 10s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sandall Park parkrun&lt;/td&gt;
&lt;td&gt;22 November 2025&lt;/td&gt;
&lt;td&gt;Sandall Park&lt;/td&gt;
&lt;td&gt;0h 40m 56s&lt;/td&gt;
&lt;td&gt;08m 11s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;8 November 2025&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 45m 57s&lt;/td&gt;
&lt;td&gt;09m 11s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;11 October 2025&lt;/td&gt;
&lt;td&gt;Vermuyden Way&lt;/td&gt;
&lt;td&gt;0h 41m 41s&lt;/td&gt;
&lt;td&gt;08m 20s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;!-- END PARKRUN_GENERATED --&gt;
&lt;h2 id="manual-parkrun-notes"&gt;Manual parkrun notes&lt;a class="anchor ms-1" href="#manual-parkrun-notes" aria-label="Permalink: Manual parkrun notes"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Results below are not on the official results feed (for example DNF) or add context for rows that appear in the generated table (for example volunteer pacing).&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cusworth Hall parkrun&lt;/td&gt;
&lt;td&gt;6 December 2025&lt;/td&gt;
&lt;td&gt;DNF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;17 January 2026&lt;/td&gt;
&lt;td&gt;Volunteer tail walker — time reflects a support pace, not a race effort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vermuyden Way parkrun&lt;/td&gt;
&lt;td&gt;3 January 2026&lt;/td&gt;
&lt;td&gt;Volunteer tail walker — time reflects a support pace, not a race effort&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="other-races-and-events"&gt;Other races and events&lt;a class="anchor ms-1" href="#other-races-and-events" aria-label="Permalink: Other races and events"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Runs, walks, and events that are not official parkrun 5k events. Edit this section by hand when you take part in something new.&lt;/p&gt;
&lt;h3 id="2026-1"&gt;2026&lt;a class="anchor ms-1" href="#2026-1" aria-label="Permalink: 2026"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Run&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Results&lt;/th&gt;
&lt;th&gt;min/km&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Run the Runway (5.8k)&lt;/td&gt;
&lt;td&gt;21 March 2026&lt;/td&gt;
&lt;td&gt;Doncaster&lt;/td&gt;
&lt;td&gt;0h 38m 55s&lt;/td&gt;
&lt;td&gt;06m 43s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="2025-1"&gt;2025&lt;a class="anchor ms-1" href="#2025-1" aria-label="Permalink: 2025"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Run&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Results&lt;/th&gt;
&lt;th&gt;min/km&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Coastal 10k&lt;/td&gt;
&lt;td&gt;21 September 2025&lt;/td&gt;
&lt;td&gt;Cleethorpes&lt;/td&gt;
&lt;td&gt;1h 30m 34s&lt;/td&gt;
&lt;td&gt;09m 03s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blackpool Night Run 7.5k&lt;/td&gt;
&lt;td&gt;27 August 2025&lt;/td&gt;
&lt;td&gt;Blackpool&lt;/td&gt;
&lt;td&gt;1h 04m 49s&lt;/td&gt;
&lt;td&gt;08m 39s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Normanby Hall 10k&lt;/td&gt;
&lt;td&gt;13 July 2025&lt;/td&gt;
&lt;td&gt;Normanby Hall&lt;/td&gt;
&lt;td&gt;1h 36m 58s&lt;/td&gt;
&lt;td&gt;09m 42s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://runforwildlife.com/run-for-wildlife-night-5k" target="_blank" rel="noopener noreferrer"&gt;Night Walk 5k&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;4 January 2025&lt;/td&gt;
&lt;td&gt;Yorkshire Wildlife Park&lt;/td&gt;
&lt;td&gt;0h 48m 09s&lt;/td&gt;
&lt;td&gt;09m 38s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="2024"&gt;2024&lt;a class="anchor ms-1" href="#2024" aria-label="Permalink: 2024"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Run&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/charity-hike"&gt;Charity Walk&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;8 June 2024&lt;/td&gt;
&lt;td&gt;Peak District&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description></item><item><title>2025 in Review and Goals for 2026</title><link>https://blog-test.funkysi1701.com/posts/2026/2025-in-review-and-2026-goals/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 01 Jan 2026 09:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2026/2025-in-review-and-2026-goals/</guid><category term="Retrospective">Retrospective</category><category term="Goals">Goals</category><category term="YearlyReview">YearlyReview</category><category term="Blogging">Blogging</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/welcome-2026.png"/><description>&lt;h2 id="2025-in-review"&gt;2025 in Review&lt;a class="anchor ms-1" href="#2025-in-review" aria-label="Permalink: 2025 in Review"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What a year 2025 has been! I published 24 blog posts covering a wide range of topics from cloud-native technologies to AI experiments, and even some personal reflections. Here are the key themes and highlights from my blogging year:&lt;/p&gt;
&lt;h3 id="cloud-native-and-devops"&gt;Cloud-Native and DevOps&lt;a class="anchor ms-1" href="#cloud-native-and-devops" aria-label="Permalink: Cloud-Native and DevOps"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was a major focus area for me in 2025, not really surprising as I moved into a DevOps role this year, with deep dives into modern infrastructure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/learning-kubernetes/"&gt;&lt;strong&gt;Learning Kubernetes&lt;/strong&gt;&lt;/a&gt;
- Started my journey into container orchestration and shared my beginner experiences&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/deploying-hugo-with-helm/"&gt;&lt;strong&gt;Deploying Hugo with Helm&lt;/strong&gt;&lt;/a&gt;
- Deployed this very blog to Kubernetes using Helm charts&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/kubernetes-and-letsencrypt/"&gt;&lt;strong&gt;Kubernetes and Let&amp;rsquo;s Encrypt&lt;/strong&gt;&lt;/a&gt;
- Tackled SSL certificate management in Kubernetes&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/monitoring-with-nagios-docker/"&gt;&lt;strong&gt;Monitoring with Nagios Docker&lt;/strong&gt;&lt;/a&gt;
- Explored monitoring solutions in containerized environments&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="net-and-development"&gt;.NET and Development&lt;a class="anchor ms-1" href="#net-and-development" aria-label="Permalink: .NET and Development"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;My bread and butter continues to be .NET development, with several posts exploring new features and tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/blazor-and-dotnet10/"&gt;&lt;strong&gt;Blazor and .NET 10&lt;/strong&gt;&lt;/a&gt;
- Covered breaking changes, fixes, and new features in the latest .NET release&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/adding-elasticsearch-with-aspire/"&gt;&lt;strong&gt;Adding Elasticsearch with .NET Aspire&lt;/strong&gt;&lt;/a&gt;
- Integrated search capabilities using Aspire&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/aspire-9.2/"&gt;&lt;strong&gt;Aspire 9.2&lt;/strong&gt;&lt;/a&gt;
- Explored the latest Aspire release&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/nuget-central-package-management/"&gt;&lt;strong&gt;NuGet Central Package Management&lt;/strong&gt;&lt;/a&gt;
- Streamlined dependency management&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/whats-new-csharp/"&gt;&lt;strong&gt;What&amp;rsquo;s New in C#&lt;/strong&gt;&lt;/a&gt;
- Covered the latest language features&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/exceptions/"&gt;&lt;strong&gt;Exceptions&lt;/strong&gt;&lt;/a&gt;
- Best practices for error handling&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="observability-and-monitoring"&gt;Observability and Monitoring&lt;a class="anchor ms-1" href="#observability-and-monitoring" aria-label="Permalink: Observability and Monitoring"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Understanding what&amp;rsquo;s happening in production became a key theme:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/getting-started-with-opentelemetry/"&gt;&lt;strong&gt;Getting Started with OpenTelemetry&lt;/strong&gt;&lt;/a&gt;
- Made observability easy with modern tracing&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/opentelemetry-logs/"&gt;&lt;strong&gt;OpenTelemetry Logs&lt;/strong&gt;&lt;/a&gt;
- Extended observability to include logging&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/setting-up-grafana/"&gt;&lt;strong&gt;Setting up Grafana&lt;/strong&gt;&lt;/a&gt;
- Built dashboards for monitoring&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cloud-platforms"&gt;Cloud Platforms&lt;a class="anchor ms-1" href="#cloud-platforms" aria-label="Permalink: Cloud Platforms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/merge-two-projects-into-one/"&gt;&lt;strong&gt;Merging Two Projects into One&lt;/strong&gt;&lt;/a&gt;
- Shared my experience consolidating codebases&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ai-and-creativity"&gt;AI and Creativity&lt;a class="anchor ms-1" href="#ai-and-creativity" aria-label="Permalink: AI and Creativity"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/fun-with-ai/"&gt;&lt;strong&gt;Fun with AI&lt;/strong&gt;&lt;/a&gt;
- Explored ChatGPT&amp;rsquo;s image generation capabilities&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/using-ai/"&gt;&lt;strong&gt;Using AI&lt;/strong&gt;&lt;/a&gt;
- Practical applications of AI in daily work&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/mandelbrot-set/"&gt;&lt;strong&gt;Mandelbrot Set&lt;/strong&gt;&lt;/a&gt;
- A fun mathematical exploration&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="professional-development"&gt;Professional Development&lt;a class="anchor ms-1" href="#professional-development" aria-label="Permalink: Professional Development"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/pragmatic-programmer/"&gt;&lt;strong&gt;The Pragmatic Programmer&lt;/strong&gt;&lt;/a&gt;
- Book review of this classic software development book&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/the-hacker-ethic/"&gt;&lt;strong&gt;The Hacker Ethic&lt;/strong&gt;&lt;/a&gt;
- Reflections on developer culture and values&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/stepping-outside-your-comfort-zone/"&gt;&lt;strong&gt;Stepping Outside Your Comfort Zone&lt;/strong&gt;&lt;/a&gt;
- Personal growth and career development&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/volunteering-at-ndc/"&gt;&lt;strong&gt;Volunteering at NDC London&lt;/strong&gt;&lt;/a&gt;
- My experience at this major .NET conference&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/periodic-table-devops-2025/"&gt;&lt;strong&gt;Periodic Table of DevOps 2025&lt;/strong&gt;&lt;/a&gt;
- A visual guide to the DevOps ecosystem&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fun-projects"&gt;Fun Projects&lt;a class="anchor ms-1" href="#fun-projects" aria-label="Permalink: Fun Projects"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/festive-naughty-or-nice-checker/"&gt;&lt;strong&gt;Festive Naughty or Nice Checker&lt;/strong&gt;&lt;/a&gt;
- A seasonal AI-powered fun project&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you to everyone who read, commented, and shared my posts throughout the year. Your engagement and feedback mean the world to me!&lt;/p&gt;
&lt;h2 id="2025-by-the-numbers"&gt;2025 by the Numbers&lt;a class="anchor ms-1" href="#2025-by-the-numbers" aria-label="Permalink: 2025 by the Numbers"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;24 blog posts&lt;/strong&gt; published&lt;/li&gt;
&lt;li&gt;Major topics: Kubernetes, .NET, OpenTelemetry, AI&lt;/li&gt;
&lt;li&gt;New skills acquired: Helm, Kubernetes, observability tools&lt;/li&gt;
&lt;li&gt;Conferences attended: NDC London (as a volunteer) and DDD North&lt;/li&gt;
&lt;li&gt;Submitted content to &lt;a href="https://festivetechcalendar.com" target="_blank" rel="noopener noreferrer"&gt;https://festivetechcalendar.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="goals-for-2026"&gt;Goals for 2026&lt;a class="anchor ms-1" href="#goals-for-2026" aria-label="Permalink: Goals for 2026"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Looking ahead to 2026, I&amp;rsquo;m excited to build on this momentum. Here are my blogging and technical goals:&lt;/p&gt;
&lt;h3 id="content-goals"&gt;Content Goals&lt;a class="anchor ms-1" href="#content-goals" aria-label="Permalink: Content Goals"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Publish at least 24 posts&lt;/strong&gt; - Maintain the pace from 2025&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deep dive into AI/ML&lt;/strong&gt; - Go beyond experimentation to practical implementations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More hands-on tutorials&lt;/strong&gt; - Provide step-by-step guides that readers can follow along with&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="technical-skills"&gt;Technical Skills&lt;a class="anchor ms-1" href="#technical-skills" aria-label="Permalink: Technical Skills"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Master Kubernetes&lt;/strong&gt; - Move from beginner to intermediate proficiency&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced observability&lt;/strong&gt; - Implement comprehensive monitoring across distributed systems&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud-native patterns&lt;/strong&gt; - Explore microservices, event-driven architectures, and service mesh&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI integration&lt;/strong&gt; - Build practical AI-powered features into applications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platform engineering&lt;/strong&gt; - Create better developer experiences and internal platforms&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="walking"&gt;Walking&lt;a class="anchor ms-1" href="#walking" aria-label="Permalink: Walking"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At the end of 2024 I made the following goal:&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2024 took an unusual turn. In June, I walked a half marathon across the Peak District, and since then,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;I have been doing lots of walks. Walking is good for my physical and mental health,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;so I intend to do more of it in 2025. I have a 5k scheduled for January,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;which should be lots of fun as it is around the wildlife park.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well I enjoyed my walk in January 2025, which then led to two 10k walks (in July and September) and a 7.5k night walk (in Blackpool to see the Illuminations). This led me to explore &lt;a href="https://www.parkrun.com/" target="_blank" rel="noopener noreferrer"&gt;parkrun&lt;/a&gt;
and I completed my 8th run this morning. I say run, not walk as I am slowly becoming more of a runner and less of a walker.&lt;/p&gt;
&lt;p&gt;So my goal here is to keep doing this, as I am so far enjoying getting out and about.&lt;/p&gt;
&lt;h2 id="what-would-you-like-to-see"&gt;What Would You Like to See?&lt;a class="anchor ms-1" href="#what-would-you-like-to-see" aria-label="Permalink: What Would You Like to See?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;d love to hear from you! What topics would you like me to cover in 2026? Are there specific technologies, patterns, or problems you&amp;rsquo;d like to see explored?&lt;/p&gt;
&lt;p&gt;Drop a comment below, reach out on social media, or send me a message. Your feedback helps shape the content direction for the year ahead.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s to a fantastic 2026 filled with learning, building, and sharing! 🚀&lt;/p&gt;</description></item><item><title>Events 2026</title><link>https://blog-test.funkysi1701.com/posts/events/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 01 Jan 2026 01:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/events/</guid><description>&lt;h2 id="2026"&gt;2026&lt;a class="anchor ms-1" href="#2026" aria-label="Permalink: 2026"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Talk&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.steelcon.info/" target="_blank" rel="noopener noreferrer"&gt;SteelCon&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;11 July 2026&lt;/td&gt;
&lt;td&gt;Sheffield&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.meetup.com/dotnetyork/events/315057011" target="_blank" rel="noopener noreferrer"&gt;dotNet York - EF Core Architecture, Document Databases, and MongoDB&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;2 July 2026&lt;/td&gt;
&lt;td&gt;York&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.developersupnorth.co.uk/" target="_blank" rel="noopener noreferrer"&gt;Developers Up North&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;18 June 2026&lt;/td&gt;
&lt;td&gt;Hull&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.meetup.com/leeds-sharp/events/314103187" target="_blank" rel="noopener noreferrer"&gt;Leeds Sharp - AI Observability as the Engine of Production-Ready AI&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;21 May 2026&lt;/td&gt;
&lt;td&gt;Leeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.meetup.com/leeds-sharp/events/314033186" target="_blank" rel="noopener noreferrer"&gt;Leeds Sharp - How I tamed Claude&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;30 April 2026&lt;/td&gt;
&lt;td&gt;Leeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.dddnorth.co.uk/" target="_blank" rel="noopener noreferrer"&gt;DDD North&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;28 February 2026&lt;/td&gt;
&lt;td&gt;Hull&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.meetup.com/leeds-sharp/events/312231723" target="_blank" rel="noopener noreferrer"&gt;Leeds Sharp - Ditch the Drudge Work: Agentic SDLC for .NET&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;26 February 2026&lt;/td&gt;
&lt;td&gt;Leeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2026/ndc-london-2026/"&gt;NDC London&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;28-30 January 2026&lt;/td&gt;
&lt;td&gt;London&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For my parkrun results see &lt;a href="https://blog-test.funkysi1701.com/parkrun"&gt;parkrun&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>A festive naughty or nice checker</title><link>https://blog-test.funkysi1701.com/posts/2025/festive-naughty-or-nice-checker/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 12 Dec 2025 10:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/festive-naughty-or-nice-checker/</guid><category term=".NET">.NET</category><category term="SemanticKernel">SemanticKernel</category><category term="AI">AI</category><category term="Christmas">Christmas</category><category term="festive">festive</category><category term="naughtyornice">naughtyornice</category><category term="C-Sharp">C-Sharp</category><category term="MachineLearning">MachineLearning</category><category term="tutorial">tutorial</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2025/festive-tech-calendar.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Festive Tech Calendar" src="https://blog-test.funkysi1701.com/images/2025/festive-tech-calendar.png" loading="lazy"
width="817" height="545"
/&gt;
&lt;/p&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;a class="anchor ms-1" href="#introduction" aria-label="Permalink: Introduction"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m excited to be taking part in this year&amp;rsquo;s &lt;a href="https://festivetechcalendar.com/" target="_blank" rel="noopener noreferrer"&gt;Festive Tech Calendar&lt;/a&gt;
, a community-driven advent calendar showcasing amazing technical content throughout December. Make sure to check out the other excellent posts created by developers from around the world!&lt;/p&gt;
&lt;p&gt;In this festive tutorial, we&amp;rsquo;ll build a fun &amp;ldquo;Naughty or Nice&amp;rdquo; checker using Microsoft&amp;rsquo;s Semantic Kernel and .NET. This playful AI-powered tool analyzes text descriptions and delivers a verdict on whether someone has been naughty or nice this year—perfect for adding some holiday cheer to your portfolio! Whether you&amp;rsquo;re new to AI integration or looking to explore Semantic Kernel, this beginner-friendly guide will walk you through creating a complete working application from scratch. By the end, you&amp;rsquo;ll have a deployable web app and understand how to integrate large language models into your .NET projects.&lt;/p&gt;
&lt;h2 id="my-take-on-ai"&gt;My Take on AI&lt;a class="anchor ms-1" href="#my-take-on-ai" aria-label="Permalink: My Take on AI"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving into code, I want to share a quick perspective on using AI in development. While building this demo, I used &lt;a href="https://github.com/copilot" target="_blank" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;
to transform a basic UI into something more festive.&lt;/p&gt;
&lt;p&gt;Starting with a simple, functional interface:&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="boring looking application" src="https://blog-test.funkysi1701.com/images/2025/before.png" loading="lazy"
width="1487" height="347"
/&gt;
&lt;/p&gt;
&lt;p&gt;After a few prompts to Copilot, I had a Christmas-themed demo with loading spinners and festive icons:&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Christmas version" src="https://blog-test.funkysi1701.com/images/2025/after.png" loading="lazy"
width="1128" height="432"
/&gt;
&lt;/p&gt;
&lt;p&gt;Could I have coded this myself? Absolutely. But I&amp;rsquo;d rather focus my energy on the backend Semantic Kernel integration than wrestling with CSS animations. &lt;strong&gt;This is where AI shines—handling the tedious parts so you can focus on the interesting problems.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="the-reality-check"&gt;The Reality Check&lt;a class="anchor ms-1" href="#the-reality-check" aria-label="Permalink: The Reality Check"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;That said, AI isn&amp;rsquo;t magic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hallucinations happen&lt;/strong&gt; - I&amp;rsquo;ve lost time chasing incorrect suggestions, so don&amp;rsquo;t retire your search engine just yet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ownership questions remain&lt;/strong&gt; - Who owns AI-generated code? This is still being figured out&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It&amp;rsquo;s a tool, not a replacement&lt;/strong&gt; - AI augments developers; it doesn&amp;rsquo;t replace critical thinking&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My approach: Use AI as a productivity multiplier, but always verify, understand, and own what you ship.&lt;/p&gt;
&lt;h2 id="what-is-semantic-kernel"&gt;What is Semantic Kernel?&lt;a class="anchor ms-1" href="#what-is-semantic-kernel" aria-label="Permalink: What is Semantic Kernel?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Semantic Kernel is an open-source SDK from Microsoft that makes it easy to integrate AI models into your .NET applications. It allows you to use large language models (LLMs) for tasks like text analysis, summarization, and more.&lt;/p&gt;
&lt;h2 id="project-overview"&gt;Project Overview&lt;a class="anchor ms-1" href="#project-overview" aria-label="Permalink: Project Overview"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll create a simple web app that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Accepts a name or short description of someone&amp;rsquo;s behaviour&lt;/li&gt;
&lt;li&gt;Uses Semantic Kernel to analyze the input&lt;/li&gt;
&lt;li&gt;Returns a festive verdict: Naughty or Nice&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor ms-1" href="#prerequisites" aria-label="Permalink: Prerequisites"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;.NET 10 (I am not using any .NET 10 specific features so could probably be rewritten with older versions)&lt;/li&gt;
&lt;li&gt;Semantic Kernel (NuGet package)&lt;/li&gt;
&lt;li&gt;An OpenAI API key - ⚠️ &lt;strong&gt;Note&lt;/strong&gt;: API usage costs ~$0.01-0.05 per request&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="openai-and-costs"&gt;OpenAI and Costs&lt;a class="anchor ms-1" href="#openai-and-costs" aria-label="Permalink: OpenAI and Costs"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For this example I have used an OpenAI API Key. This is not free, however while writing this example I have only spent a few pounds in tokens. For more information about OpenAI head over to &lt;a href="https://platform.openai.com/" target="_blank" rel="noopener noreferrer"&gt;https://platform.openai.com/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;For this reason I have not provided a live demo, (I don&amp;rsquo;t want you all using my API key), and no API keys are included in my example code.&lt;/p&gt;
&lt;h2 id="step-1-setting-up-the-project"&gt;Step 1: Setting Up the Project&lt;a class="anchor ms-1" href="#step-1-setting-up-the-project" aria-label="Permalink: Step 1: Setting Up the Project"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a new Blazor Web App:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dotnet new blazor -n NaughtyOrNiceChecker
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd NaughtyOrNiceChecker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Install the required NuGet packages: (Microsoft.SemanticKernel.Connectors.OpenAI Version 1.67.1 as I write 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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dotnet add package Microsoft.SemanticKernel.Connectors.OpenAI
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add your OpenAI configuration to appsettings.json:&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-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;OpenAI&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Key&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;your-api-key-here&amp;#34;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Head over to https://platform.openai.com/settings/organization/api-keys
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Model&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;gpt-5&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;// I am using gpt-5 but feel free to experiment with other models
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;🔒 &lt;strong&gt;Security&lt;/strong&gt;: Never commit API keys to GitHub. Use user secrets or environment variables.&lt;/p&gt;
&lt;p&gt;The code for my project can be found on GitHub at &lt;a href="https://github.com/funkysi1701/FestiveTechCalendar2025" target="_blank" rel="noopener noreferrer"&gt;https://github.com/funkysi1701/FestiveTechCalendar2025&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="step-2-integrate-semantic-kernel"&gt;Step 2: Integrate Semantic Kernel&lt;a class="anchor ms-1" href="#step-2-integrate-semantic-kernel" aria-label="Permalink: Step 2: Integrate Semantic Kernel"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Configure Semantic Kernel to use your LLM provider (OpenAI). In the &lt;code&gt;Program.cs&lt;/code&gt; file you will see the following code, this loads the OpenAI key and model from your &lt;code&gt;appsettings.json&lt;/code&gt; config file, and allows it to be used by Semantic Kernel.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; key = builder.Configuration.GetValue&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;OpenAI:Key&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; model = builder.Configuration.GetValue&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;OpenAI:Model&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (!&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(key))
&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; builder.Services.AddOpenAIChatCompletion(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; modelId: model ?? &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ApplicationException(&lt;span style="color:#e6db74"&gt;&amp;#34;Missing OpenAI Config&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; apiKey: key
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.Services.AddKernel();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-3-create-the-blazor-component"&gt;Step 3: Create the Blazor Component&lt;a class="anchor ms-1" href="#step-3-create-the-blazor-component" aria-label="Permalink: Step 3: Create the Blazor Component"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a new file &lt;code&gt;Components/Pages/NaughtyOrNice.razor&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@page &lt;span style="color:#e6db74"&gt;&amp;#34;/naughty-or-nice&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@inject Kernel _kernel
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@rendermode InteractiveServer
&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;&amp;lt;PageTitle&amp;gt;Naughty or Nice Checker&amp;lt;/PageTitle&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;h3&amp;gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;🎅&lt;/span&gt; Naughty or Nice Checker&amp;lt;/h3&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;div class=&lt;span style="color:#e6db74"&gt;&amp;#34;card&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div class=&lt;span style="color:#e6db74"&gt;&amp;#34;card-body&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;input @bind=&lt;span style="color:#e6db74"&gt;&amp;#34;input&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; placeholder=&lt;span style="color:#e6db74"&gt;&amp;#34;Describe their behavior...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; class=&lt;span style="color:#e6db74"&gt;&amp;#34;form-control mb-3&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;button @onclick=&lt;span style="color:#e6db74"&gt;&amp;#34;CheckStatus&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; class=&lt;span style="color:#e6db74"&gt;&amp;#34;btn btn-primary&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Check Status
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @if (!&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(response))
&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; &amp;lt;div class=&lt;span style="color:#e6db74"&gt;&amp;#34;alert alert-@alertClass mt-3&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;h4&amp;gt;@response&amp;lt;/h4&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@code {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; childsName = &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; response = &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; alertClass =&amp;gt; response == &lt;span style="color:#e6db74"&gt;&amp;#34;Naughty&amp;#34;&lt;/span&gt; ? &lt;span style="color:#e6db74"&gt;&amp;#34;danger&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; isLoading = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; Task CheckStatus()
&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; isLoading = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; InvokeAsync(StateHasChanged);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response = &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; input = (childsName).Trim();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(input))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; var cts = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; CancellationTokenSource(TimeSpan.FromSeconds(&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; prompt = &lt;span style="color:#e6db74"&gt;&amp;#34;You are Santa&amp;#39;s assistant. Given the child&amp;#39;s name or short description, &amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;decide if they are Naughty or Nice for Christmas. &amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Respond only with one word: Naughty or Nice. &amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;No punctuation, no explanation. Input: {{$input}}&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; classifyFunc = _kernel.CreateFunctionFromPrompt(prompt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; aiResponse = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; _kernel.InvokeAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; classifyFunc,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [&amp;#34;input&amp;#34;]&lt;/span&gt; = input
&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; cts.Token
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; text = aiResponse.GetValue&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt;()?.Trim();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Normalize and enforce strict output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Equals(text, &lt;span style="color:#e6db74"&gt;&amp;#34;naughty&amp;#34;&lt;/span&gt;, StringComparison.OrdinalIgnoreCase))
&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; response = &lt;span style="color:#e6db74"&gt;&amp;#34;Naughty&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Equals(text, &lt;span style="color:#e6db74"&gt;&amp;#34;nice&amp;#34;&lt;/span&gt;, StringComparison.OrdinalIgnoreCase))
&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; response = &lt;span style="color:#e6db74"&gt;&amp;#34;Nice&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Fallback: default to Naughty to avoid leaking other content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response = &lt;span style="color:#e6db74"&gt;&amp;#34;Naughty&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;finally&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isLoading = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; InvokeAsync(StateHasChanged);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: The _kernel is injected automatically because we registered it in Program.cs with builder.Services.AddKernel().&lt;/p&gt;
&lt;h2 id="step-4-crafting-the-perfect-prompt"&gt;Step 4: Crafting the Perfect Prompt&lt;a class="anchor ms-1" href="#step-4-crafting-the-perfect-prompt" aria-label="Permalink: Step 4: Crafting the Perfect Prompt"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Getting AI to return exactly what you want requires iteration. I&amp;rsquo;ll walk you through my prompt engineering journey from verbose outputs to production-ready responses.&lt;/p&gt;
&lt;h3 id="iteration-1-too-verbose"&gt;Iteration 1: Too Verbose&lt;a class="anchor ms-1" href="#iteration-1-too-verbose" aria-label="Permalink: Iteration 1: Too Verbose"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; aiResponse = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; _kernel.InvokePromptAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;$&amp;#34;You are a tool to help Santa identify if children have been naughty or nice. &amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;$&amp;#34;Has {input} been naughty or nice this year?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cancellationToken: cancellationToken.Token
&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;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Santa&lt;/td&gt;
&lt;td&gt;Short answer: Nice. Why: - Spreads joy and generosity globally - Works hard with his team, treats elves and reindeer well - Answers letters and keeps promises (on-time deliveries) Minor demerits (lighthearted): - Excess cookie consumption - Occasional chimney soot prints Verdict: Firmly on the Nice List. Want a fun “Official Nice Report” for Santa you can share?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Darth Vader&lt;/td&gt;
&lt;td&gt;Not exactly a child, but Santa checks everyone. Darth Vader’s record this year includes Force-choking subordinates and aiding Imperial oppression—firmly Naughty. Mitigating note: he did protect his son and turn against the Emperor, which earns a small mercy. Final verdict: Naughty list (with a tiny redemption candy cane).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;James&lt;/td&gt;
&lt;td&gt;I don’t have access to Santa’s list or personal data, so I can’t say for sure about James. But I can help you decide with a quick Naughty/Nice check: Score each item: - Kind and helpful to family/classmates most of the time? (Yes +2, Sometimes +1, No 0) - Tells the truth and takes responsibility? (Yes +2, Sometimes +1, No 0) - Apologizes and makes things right after mistakes? (Yes +2, Sometimes +1, No 0) - Respects rules and others (no bullying or deliberate harm)? (Yes +2, Sometimes +1, No 0; deduct 2 if there’s repeated serious harm) - Does generous things (sharing, chores, helping the community)? (Yes +2, Sometimes +1, No 0) Totals: - 8–10: Nice List - 5–7: Mostly Nice (keep it up) - 2–4: Mixed (needs a December boost) - 0–1 or repeated serious harm: Naughty-for-now (with room to improve) If James needs a boost: make amends where needed, do one unprompted kindness or chore daily, be honest about mistakes right away, and share/donate something or help someone weekly. Share a few examples of James’s year and I’ll help you make the call.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skeletor&lt;/td&gt;
&lt;td&gt;Verdict: Naughty. Why: - Repeated attempts to conquer Eternia and seize Castle Grayskull - Habitual scheming, lying, and bullying his own minions - Frequent unleashing of dangerous magic on innocents Path back to the Nice List: - Call a truce with He-Man and protect Eternia for a season - Return stolen artifacts and undo harmful spells - Treat his minions fairly and do a few good deeds without expecting power in return&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is far too wordy, I really just want a Naughty or Nice response.&lt;/p&gt;
&lt;h3 id="iteration-2-constraining-the-output"&gt;Iteration 2: Constraining the Output&lt;a class="anchor ms-1" href="#iteration-2-constraining-the-output" aria-label="Permalink: Iteration 2: Constraining the Output"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Then I tried:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; aiResponse = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; _kernel.InvokePromptAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;$&amp;#34;Given the following description, decide if the person is Naughty or Nice for Christmas. &amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;$&amp;#34;Respond only with &amp;#39;Naughty&amp;#39; or &amp;#39;Nice&amp;#39;. &amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;$&amp;#34;Description: {input}&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cancellationToken: cancellationToken.Token
&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;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Santa&lt;/td&gt;
&lt;td&gt;Nice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Darth Vader&lt;/td&gt;
&lt;td&gt;Naughty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;James&lt;/td&gt;
&lt;td&gt;Nice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skeletor&lt;/td&gt;
&lt;td&gt;Naughty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is better but every name I tried is giving me a Nice, so let&amp;rsquo;s see if we can try something a bit more clever. However if instead of only including a name, we include some naughty or nice actions we get some interesting results.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Santa delivered some presents&lt;/td&gt;
&lt;td&gt;Nice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Darth Vader destroyed Alderaan&lt;/td&gt;
&lt;td&gt;Naughty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;James tidied his room&lt;/td&gt;
&lt;td&gt;Nice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skeletor got cross with Evil Lynn&lt;/td&gt;
&lt;td&gt;Naughty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="version-3-non-ai-approach-plugin-example"&gt;Version 3: Non-AI Approach (Plugin Example)&lt;a class="anchor ms-1" href="#version-3-non-ai-approach-plugin-example" aria-label="Permalink: Version 3: Non-AI Approach (Plugin Example)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This version demonstrates Semantic Kernel&amp;rsquo;s plugin system without using AI. While it doesn&amp;rsquo;t actually help Santa (it just generates a hash-based result), it shows how you can integrate traditional .NET code into Semantic Kernel workflows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why show this?&lt;/strong&gt; To illustrate that Semantic Kernel isn&amp;rsquo;t just for AI—you can mix AI calls with regular code execution in the same pipeline.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; aiResponse = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; _kernel.InvokeAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pluginName,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;GenerateHash&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; KernelArguments
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [&amp;#34;input&amp;#34;]&lt;/span&gt; = input
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This version invokes a semantic kernel plugin function called GenerateHash. The function itself is defined in a separate class with a KernelFunction attribute, it is really simple just generates a hash from the input string. This is just an example of how you can call .NET code from Semantic Kernel. The kernel function requires an extra line to wire up correctly I have placed this in the OnInitialized method.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; OnInitialized()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; rngPlugin = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ExamplePlugin();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _kernel.ImportPluginFromObject(rngPlugin, pluginName);
&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;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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ExamplePlugin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [KernelFunction]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; GenerateHash(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; input)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (input == &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ArgumentNullException(nameof(input));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; hash = input.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; hash &amp;gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ? &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; : &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&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;h3 id="final-version-production-ready-implementation"&gt;Final Version: Production-Ready Implementation&lt;a class="anchor ms-1" href="#final-version-production-ready-implementation" aria-label="Permalink: Final Version: Production-Ready Implementation"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;My last example is very similar to Version 2 but let&amp;rsquo;s have a look at it.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; prompt = &lt;span style="color:#e6db74"&gt;&amp;#34;You are Santa&amp;#39;s assistant. Given the child&amp;#39;s name or short description, &amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;decide if they are Naughty or Nice for Christmas. Respond only with one word: Naughty or Nice. &amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;No punctuation, no explanation. Input: {{$input}}&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; classifyFunc = _kernel.CreateFunctionFromPrompt(prompt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; aiResponse = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; _kernel.InvokeAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; classifyFunc,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt; [&amp;#34;input&amp;#34;]&lt;/span&gt; = input
&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; cancellationToken.Token
&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;Here we have a bit more error checking to make sure we have entered a valid string before calling OpenAI. This time we use the CreateFunctionFromPrompt method to pass in a prompt, we then invoke the prompt along with the string that has been entered.&lt;/p&gt;
&lt;p&gt;This time we check for naughty or nice in the response before returning that to the user, if neither is returned we return Naughty.&lt;/p&gt;
&lt;p&gt;This works quite well if we enter a more descriptive input.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Santa delivered some presents&lt;/td&gt;
&lt;td&gt;Nice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Darth Vader destroyed Alderaan&lt;/td&gt;
&lt;td&gt;Naughty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;James tidied his room&lt;/td&gt;
&lt;td&gt;Nice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skeletor got cross with Evil Lynn&lt;/td&gt;
&lt;td&gt;Naughty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As you can see if we describe the actions of someone we can categorize them as naughty or nice, which is basically what Santa does, so this tool should be a great help to him.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Is Santa Naughty or Nice?" src="https://blog-test.funkysi1701.com/images/2025/working-naughty-nice.png" loading="lazy"
width="1169" height="618"
/&gt;
&lt;/p&gt;
&lt;h3 id="comparing-all-versions"&gt;Comparing All Versions&lt;a class="anchor ms-1" href="#comparing-all-versions" aria-label="Permalink: Comparing All Versions"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Open-ended prompt&lt;/td&gt;
&lt;td&gt;Rich explanations&lt;/td&gt;
&lt;td&gt;Too verbose&lt;/td&gt;
&lt;td&gt;Learning/debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Constrained output&lt;/td&gt;
&lt;td&gt;Concise&lt;/td&gt;
&lt;td&gt;Needs context&lt;/td&gt;
&lt;td&gt;Simple classifications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Hash-based (no AI)&lt;/td&gt;
&lt;td&gt;No API costs&lt;/td&gt;
&lt;td&gt;Not intelligent&lt;/td&gt;
&lt;td&gt;Plugin example only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Validated prompts&lt;/td&gt;
&lt;td&gt;Reliable, safe&lt;/td&gt;
&lt;td&gt;More code&lt;/td&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this tutorial, we built a festive AI-powered application using Semantic Kernel and .NET. Here&amp;rsquo;s what we accomplished:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Integrated OpenAI with Semantic Kernel in a Blazor app&lt;/li&gt;
&lt;li&gt;✅ Learned prompt engineering through iteration (4 versions!)&lt;/li&gt;
&lt;li&gt;✅ Implemented proper error handling and output validation&lt;/li&gt;
&lt;li&gt;✅ Created a fun, interactive holiday application&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have tried to highlight some of the different ways that you can use Semantic Kernel that you could use in your own projects. Some of my examples could be accomplished without the use of Semantic Kernel, for example randomly generating Naughty and Nice doesn&amp;rsquo;t need AI, however hopefully you can see that getting results from AI can then be augmented using traditional .NET code to execute other functions.&lt;/p&gt;
&lt;h3 id="key-takeaways"&gt;Key Takeaways&lt;a class="anchor ms-1" href="#key-takeaways" aria-label="Permalink: Key Takeaways"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt engineering matters&lt;/strong&gt; - Notice how Version 4&amp;rsquo;s explicit instructions produced better results&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation is essential&lt;/strong&gt; - Always sanitize LLM outputs before displaying to users&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep it simple&lt;/strong&gt; - Complex doesn&amp;rsquo;t mean better (Version 3&amp;rsquo;s random approach was overkill)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cost-considerations"&gt;Cost Considerations&lt;a class="anchor ms-1" href="#cost-considerations" aria-label="Permalink: Cost Considerations"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;During development, I spent only a few pounds on API tokens. For production:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Azure OpenAI for predictable pricing&lt;/li&gt;
&lt;li&gt;Implement caching for common queries&lt;/li&gt;
&lt;li&gt;Set up rate limiting to prevent abuse&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="deployment-options"&gt;Deployment Options&lt;a class="anchor ms-1" href="#deployment-options" aria-label="Permalink: Deployment Options"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This Blazor app can be deployed to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Azure Static Web Apps&lt;/strong&gt; (free tier includes 2 custom domains)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure App Service&lt;/strong&gt; (full .NET hosting)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker containers&lt;/strong&gt; (run anywhere)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="next-steps"&gt;Next Steps&lt;a class="anchor ms-1" href="#next-steps" aria-label="Permalink: Next Steps"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Want to extend this project? Try:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a database to track naughty/nice history&lt;/li&gt;
&lt;li&gt;Implement user authentication&lt;/li&gt;
&lt;li&gt;Deploy to Azure Static Web Apps&lt;/li&gt;
&lt;li&gt;Add more context (age, location) for better AI decisions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy coding and Merry Christmas! 🎄&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/microsoft/semantic-kernel" target="_blank" rel="noopener noreferrer"&gt;Semantic Kernel GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/" target="_blank" rel="noopener noreferrer"&gt;Microsoft Semantic Kernel Docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.openai.com/docs/api-reference" target="_blank" rel="noopener noreferrer"&gt;OpenAI API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/openai/" target="_blank" rel="noopener noreferrer"&gt;Azure OpenAI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Blazor and .NET 10 breaking changes</title><link>https://blog-test.funkysi1701.com/posts/2025/blazor-and-dotnet10/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 17 Nov 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/blazor-and-dotnet10/</guid><category term="Blazor">Blazor</category><category term=".NET10">.NET10</category><category term="WebAssembly">WebAssembly</category><category term="Wasm">Wasm</category><category term="HttpClient">HttpClient</category><category term="breakingchange">breakingchange</category><category term="DotNet">DotNet</category><category term="VisualStudio">VisualStudio</category><category term="release">release</category><category term="streamingresponse">streamingresponse</category><category term="C-Sharp">C-Sharp</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2025/Android%20Small.png"/><description>&lt;h2 id="whats-new-in-net-10"&gt;What’s New in .NET 10?&lt;a class="anchor ms-1" href="#whats-new-in-net-10" aria-label="Permalink: What’s New in .NET 10?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.NET 10 was released this week and it is full of awesome new features. Check it out at &lt;a href="https://dotnet.microsoft.com/download/dotnet/10.0" target="_blank" rel="noopener noreferrer"&gt;.NET Download&lt;/a&gt;
, there is also a new version of &lt;a href="https://visualstudio.microsoft.com/" target="_blank" rel="noopener noreferrer"&gt;Visual Studio&lt;/a&gt;
which you should also check out.&lt;/p&gt;
&lt;p&gt;I quickly upgraded my .NET projects to take advantage of the new version, but my Blazor WebAssembly (Wasm) project encountered the following error in the browser console:&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;System.NotSupportedException: net_http_synchronous_reads_not_supported
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at System.Net.Http.BrowserHttpReadStream.Read(Byte[] buffer, Int32 offset, Int32 count)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at System.IO.DelegatingStream.Read(Byte[] buffer, Int32 offset, Int32 count)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at System.IO.StreamReader.ReadBuffer(Span`1 userBuffer, Boolean&amp;amp; readToUserBuffer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at System.IO.StreamReader.ReadSpan(Span`1 buffer)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at System.IO.StreamReader.Read(Char[] buffer, Int32 index, Int32 count)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonTextReader.ReadData(Boolean append, Int32 charsRequired)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonTextReader.ReadData(Boolean append)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonTextReader.ParseValue()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonTextReader.Read()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonReader.ReadAndMoveToContent()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at Newtonsoft.Json.JsonSerializer.Deserialize[MyResult](JsonReader reader)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at MyAPI.Client.MyClient.&amp;lt;ReadObjectResponseAsync&amp;gt;d__57`1[[MyAPI.Client.MyResult, MyAPI.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at MyAPI.Client.MyClient.MyAsync(MyRequest body, CancellationToken cancellationToken)
&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;This error was getting thrown on a Blazor Wasm page when it tried to make a call to my API. This worked fine in .NET 9 so my suspicion was this might be a breaking change.&lt;/p&gt;
&lt;p&gt;The list of new features for .NET 10 can be found &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-10.0?view=aspnetcore-9.0" target="_blank" rel="noopener noreferrer"&gt;.NET 10 Release Notes&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="httpclient-response-streaming-breaking-change-in-blazor"&gt;HttpClient Response Streaming: Breaking Change in Blazor&lt;a class="anchor ms-1" href="#httpclient-response-streaming-breaking-change-in-blazor" aria-label="Permalink: HttpClient Response Streaming: Breaking Change in Blazor"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I found the following new feature which I suspect is related to my issue:&lt;/p&gt;
&lt;p&gt;HttpClient response streaming enabled by default&lt;/p&gt;
&lt;p&gt;In prior Blazor releases, response streaming for HttpClient requests was opt-in. Now, response streaming is enabled by default.&lt;/p&gt;
&lt;p&gt;This is a breaking change because calling &lt;code&gt;HttpContent.ReadAsStreamAsync&lt;/code&gt; for an &lt;code&gt;HttpResponseMessage.Content&lt;/code&gt; (&lt;code&gt;response.Content.ReadAsStreamAsync()&lt;/code&gt;) returns a &lt;code&gt;BrowserHttpReadStream&lt;/code&gt; and no longer a &lt;code&gt;MemoryStream&lt;/code&gt;. &lt;code&gt;BrowserHttpReadStream&lt;/code&gt; doesn&amp;rsquo;t support synchronous operations, such as &lt;code&gt;Stream.Read(Span&amp;lt;Byte&amp;gt;)&lt;/code&gt;. If your code uses synchronous operations, you can opt-out of response streaming or copy the &lt;code&gt;Stream&lt;/code&gt; into a &lt;code&gt;MemoryStream&lt;/code&gt; yourself.&lt;/p&gt;
&lt;p&gt;To opt-out of response streaming globally, use either of the following approaches:&lt;/p&gt;
&lt;p&gt;Add the &amp;lt;WasmEnableStreamingResponse&amp;gt; property to the project file with a value of false:&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;WasmEnableStreamingResponse&amp;gt;&lt;/span&gt;false&lt;span style="color:#f92672"&gt;&amp;lt;/WasmEnableStreamingResponse&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set the DOTNET_WASM_ENABLE_STREAMING_RESPONSE environment variable to false or 0.&lt;/p&gt;
&lt;p&gt;To opt-out of response streaming for an individual request, set &lt;code&gt;SetBrowserResponseStreamingEnabled&lt;/code&gt; to false on the &lt;code&gt;HttpRequestMessage&lt;/code&gt; (&lt;code&gt;requestMessage&lt;/code&gt; in the following example):&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;requestMessage.SetBrowserResponseStreamingEnabled(&lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For more information, see HttpClient and HttpRequestMessage with Fetch API request options (Call web API article).&lt;/p&gt;
&lt;h2 id="how-to-fix-the-streaming-issue-in-blazor"&gt;How to Fix the Streaming Issue in Blazor&lt;a class="anchor ms-1" href="#how-to-fix-the-streaming-issue-in-blazor" aria-label="Permalink: How to Fix the Streaming Issue in Blazor"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To test out if this was the culprit I added &lt;code&gt;&amp;lt;WasmEnableStreamingResponse&amp;gt;false&amp;lt;/WasmEnableStreamingResponse&amp;gt;&lt;/code&gt; to my csproj file and sure enough this fixed my issue.&lt;/p&gt;
&lt;p&gt;Do check out the docs for a complete list of new features and any other potential breaking changes. &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-10.0?view=aspnetcore-10.0" target="_blank" rel="noopener noreferrer"&gt;.NET 10 Release Notes&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Periodic Table of DevOps 2025</title><link>https://blog-test.funkysi1701.com/posts/2025/periodic-table-devops-2025/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 29 Sep 2025 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/periodic-table-devops-2025/</guid><category term="DevOps">DevOps</category><category term="Tools">Tools</category><category term="Cloud">Cloud</category><category term="containerization">containerization</category><category term="SourceControl">SourceControl</category><category term="Automation">Automation</category><category term="2025">2025</category><category term="2016">2016</category><category term="comparison">comparison</category><category term="trends">trends</category><category term="SoftwareDevelopment">SoftwareDevelopment</category><category term="periodictable">periodictable</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2025/periodic-table-devops-2025.png"/><description>&lt;p&gt;DevOps has transformed the way teams build, deploy, and manage software. Over the years, the tools we use have evolved rapidly—some have become industry standards, while others have faded away or emerged to solve new challenges. In this post, I revisit the concept of a &amp;ldquo;Periodic Table of DevOps&amp;rdquo; to compare the landscape in 2016 with 2025, highlight key changes, and reflect on what these shifts mean for developers, IT professionals, and organizations embracing modern workflows.&lt;/p&gt;
&lt;p&gt;The periodic table lists all the chemical elements and groups them together based on some key properties. In 2016 I found an article about the &lt;a href="https://digital.ai/periodic-table-of-devops-tools/" target="_blank" rel="noopener noreferrer"&gt;periodic table of DevOps&lt;/a&gt;
and wrote a blog &lt;a href="https://blog-test.funkysi1701.com/posts/2016/periodic-table-devops/"&gt;post&lt;/a&gt;
about it.&lt;/p&gt;
&lt;h2 id="periodic-table-of-devops-tools-2025"&gt;Periodic Table of DevOps Tools 2025&lt;a class="anchor ms-1" href="#periodic-table-of-devops-tools-2025" aria-label="Permalink: Periodic Table of DevOps Tools 2025"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Periodic Table of DevOps 2025" src="https://blog-test.funkysi1701.com/images/2025/periodic-table-devops-2025.png" loading="lazy"
width="1386" height="879"
/&gt;
&lt;/p&gt;
&lt;h2 id="periodic-table-of-devops-tools-2016"&gt;Periodic Table of DevOps Tools 2016&lt;a class="anchor ms-1" href="#periodic-table-of-devops-tools-2016" aria-label="Permalink: Periodic Table of DevOps Tools 2016"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Periodic Table of DevOps 2016" src="https://blog-test.funkysi1701.com/images/2016/periodic-table-of-devops-v2.png" loading="lazy"
width="4896" height="2734"
/&gt;
&lt;/p&gt;
&lt;p&gt;I thought it might be interesting to see what tools are still in use, and what are new.&lt;/p&gt;
&lt;h2 id="source-control"&gt;Source Control&lt;a class="anchor ms-1" href="#source-control" aria-label="Permalink: Source Control"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Git, the most popular source control system, is on both charts, in 2016 it was at position 3, and in 2025 it is at 2.
GitHub, the most widely used web-based git repository, is also on both charts, moving from 1 to 10.
Bitbucket (now owned by Atlassian) was a hosted git repository I used to use and is still on the chart, moving from 11 to 36.
Subversion, a source control system I started my career with, has vanished off the chart in 2025. Not really a surprise due to the popularity of git now.&lt;/p&gt;
&lt;h2 id="cloud-platforms"&gt;Cloud Platforms&lt;a class="anchor ms-1" href="#cloud-platforms" aria-label="Permalink: Cloud Platforms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2016 we had a whole column of Cloud Platforms, including Rackspace and OpenShift, in 2025 this has been reduced to the big three (Azure, AWS and GCP) plus OpenShift.&lt;/p&gt;
&lt;h2 id="containerization"&gt;Containerization&lt;a class="anchor ms-1" href="#containerization" aria-label="Permalink: Containerization"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2016 we had a column of tools like Docker, Docker Swarm and Kubernetes. In 2025 there are far more tools in this space, with the addition of tools like Helm and the various ways you can host containers on cloud platforms (like Azure AKS).&lt;/p&gt;
&lt;h2 id="build-and-deploy-tools"&gt;Build and Deploy tools&lt;a class="anchor ms-1" href="#build-and-deploy-tools" aria-label="Permalink: Build and Deploy tools"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2016 Azure DevOps was still called Team Foundation Server, so this has spread out into the various ways you can use Azure DevOps, such as Pipelines and Code. Also since 2016 GitHub Actions has appeared on the market.&lt;/p&gt;
&lt;p&gt;In 2016 I was also dabbling with TeamCity, this is no longer used that much so isn&amp;rsquo;t on the chart in 2025. Jenkins is still around on both charts.&lt;/p&gt;
&lt;h2 id="comms-tools"&gt;Comms Tools&lt;a class="anchor ms-1" href="#comms-tools" aria-label="Permalink: Comms Tools"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2025 Slack and MS Teams are the go-to tools for communicating with distributed teams, Slack was around in 2016, but Teams wasn&amp;rsquo;t a thing back then.&lt;/p&gt;
&lt;h2 id="new-tools"&gt;New Tools&lt;a class="anchor ms-1" href="#new-tools" aria-label="Permalink: New Tools"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;New tools for monitoring like Grafana have appeared; back in 2016 I was exclusively using Application Insights from Azure.&lt;/p&gt;
&lt;h2 id="conclusion--key-takeaways"&gt;Conclusion &amp; Key Takeaways&lt;a class="anchor ms-1" href="#conclusion--key-takeaways" aria-label="Permalink: Conclusion &amp;amp; Key Takeaways"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The DevOps landscape has changed dramatically over the past decade. Some tools have stood the test of time, while others have faded or emerged to meet new challenges. Here are the key takeaways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Git remains the backbone of source control&lt;/strong&gt;, with platforms like GitHub and Bitbucket continuing to thrive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud platforms (Azure, AWS, GCP) have become central&lt;/strong&gt;, reflecting the shift to cloud-native development and operations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Containerization and orchestration (Docker, Kubernetes, Helm) are now essential&lt;/strong&gt;, enabling scalable, flexible deployments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring and collaboration tools have evolved&lt;/strong&gt;, with newcomers like Grafana and MS Teams joining established solutions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Legacy tools are disappearing&lt;/strong&gt;, showing the importance of adaptability in tech.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As DevOps continues to evolve, staying curious and open to new tools is key. The periodic table analogy reminds us that the right mix of technologies can empower teams to build, deploy, and manage software more effectively. What tools will shape the next decade? Only time will tell.&lt;/p&gt;</description></item><item><title>The Mandelbrot Set</title><link>https://blog-test.funkysi1701.com/posts/2025/mandelbrot-set/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 15 Sep 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/mandelbrot-set/</guid><category term="mandelbrotset">mandelbrotset</category><category term="fractals">fractals</category><category term="mathematics">mathematics</category><category term="chaostheory">chaostheory</category><category term="complexnumbers">complexnumbers</category><category term="art">art</category><category term="visualization">visualization</category><category term="mathart">mathart</category><category term="self-similarity">self-similarity</category><category term="complexdynamics">complexdynamics</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/mandelbrot.png"/><description>&lt;h2 id="the-mandelbrot-set-beauty-chaos-and-mathematical-art"&gt;The Mandelbrot Set: Beauty, Chaos, and Mathematical Art&lt;a class="anchor ms-1" href="#the-mandelbrot-set-beauty-chaos-and-mathematical-art" aria-label="Permalink: The Mandelbrot Set: Beauty, Chaos, and Mathematical Art"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="The Mandelbrot set" src="https://blog-test.funkysi1701.com/images/mandelbrot.png" loading="lazy"
width="800" height="600"
/&gt;
&lt;/p&gt;
&lt;p&gt;The Mandelbrot set is one of the most iconic images in mathematics—a mesmerizing swirl of fractal patterns, infinite complexity, and unexpected beauty. But what exactly is the Mandelbrot set, and why has it captured the imagination of mathematicians, artists, and curious minds alike?&lt;/p&gt;
&lt;h2 id="what-is-the-mandelbrot-set"&gt;What Is the Mandelbrot Set?&lt;a class="anchor ms-1" href="#what-is-the-mandelbrot-set" aria-label="Permalink: What Is the Mandelbrot Set?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At its core, the Mandelbrot set is a collection of complex numbers. It’s defined by a simple equation, but the results are anything but simple. The definition is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A complex number &lt;strong&gt;c&lt;/strong&gt; is in the Mandelbrot set if, when you start with &lt;strong&gt;z = 0&lt;/strong&gt; and repeatedly apply the function &lt;code&gt;z = z² + c&lt;/code&gt;, the value of &lt;strong&gt;z&lt;/strong&gt; remains bounded (does not go to infinity), no matter how many times you iterate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, for each point &lt;strong&gt;c&lt;/strong&gt; on the complex plane, you check: if you keep plugging it into this formula, does it stay small, or does it spiral out of control? If it stays small forever, it&amp;rsquo;s in the Mandelbrot set.&lt;/p&gt;
&lt;h2 id="from-simple-formula-to-stunning-images"&gt;From Simple Formula to Stunning Images&lt;a class="anchor ms-1" href="#from-simple-formula-to-stunning-images" aria-label="Permalink: From Simple Formula to Stunning Images"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The real magic happens when you visualize the Mandelbrot set on a computer. Each point in the complex plane is coloured based on whether it belongs to the set or how quickly it escapes to infinity. The result is a black, bulbous shape surrounded by intricate, infinitely detailed patterns that resemble swirling galaxies, seahorses, or lightning bolts—the Mandelbrot set and its &amp;ldquo;fractal boundary.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Zooming in on the edge reveals ever more complexity, with shapes that are reminiscent of the original set at different scales. This property, a form of self-similarity, is a hallmark of fractals.&lt;/p&gt;
&lt;h2 id="why-is-the-mandelbrot-set-important"&gt;Why Is the Mandelbrot Set Important?&lt;a class="anchor ms-1" href="#why-is-the-mandelbrot-set-important" aria-label="Permalink: Why Is the Mandelbrot Set Important?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Mandelbrot set is more than just a pretty picture. It’s a window into the world of &lt;strong&gt;complex dynamics&lt;/strong&gt; and &lt;strong&gt;chaos theory&lt;/strong&gt;. The set’s boundary is infinitely complex, showing how simple mathematical rules can generate unexpected and beautiful complexity.&lt;/p&gt;
&lt;p&gt;It also has deep implications in mathematics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fractals:&lt;/strong&gt; The Mandelbrot set is the most famous example of a fractal—a shape that shows similar, though not identical, patterns at every scale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chaos Theory:&lt;/strong&gt; It illustrates sensitive dependence on initial conditions, where tiny changes can lead to drastically different outcomes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex Numbers:&lt;/strong&gt; It brings to life the beauty of complex numbers, which are usually abstract concepts in math classes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-mandelbrot-set-in-art-and-culture"&gt;The Mandelbrot Set in Art and Culture&lt;a class="anchor ms-1" href="#the-mandelbrot-set-in-art-and-culture" aria-label="Permalink: The Mandelbrot Set in Art and Culture"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thanks to its stunning visuals, the Mandelbrot set has become a cultural icon. It’s inspired digital art, music, and even jewellery. It also serves as a symbol for how complexity and order can emerge from simple rules, a concept that resonates in fields from biology to computer science.&lt;/p&gt;
&lt;h2 id="try-it-yourself"&gt;Try It Yourself&lt;a class="anchor ms-1" href="#try-it-yourself" aria-label="Permalink: Try It Yourself"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many websites and software tools let you explore the Mandelbrot set interactively. Try zooming in and discover new shapes and patterns emerging at every level. It’s a fantastic way to experience the intersection of math, art, and chaos.&lt;/p&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;a class="anchor ms-1" href="#final-thoughts" aria-label="Permalink: Final Thoughts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have been fascinated by fractals since I was young. I remember seeing them generated on a &lt;a href="https://blog-test.funkysi1701.com/posts/2021/back-to-basic/"&gt;Lynx computer&lt;/a&gt;
and the process was slow, one pixel at a time, after a few hours you would see a complete Mandelbrot set. More recently I have looked at generating them in the browser (using .NET&amp;rsquo;s Blazor WebAssembly technology), and the image at the start of this post took only a few seconds to generate.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also created an &lt;a href="https://mandelbrot.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;interactive Mandelbrot set generator&lt;/a&gt;
. It&amp;rsquo;s a work in progress, but you can already generate a set and zoom in using the buttons at the top or by clicking with your mouse. I plan to add more features in the coming weeks.&lt;/p&gt;
&lt;p&gt;The Mandelbrot set reminds us that even the simplest equations can produce infinite complexity and beauty. It stands as an enduring inspiration—proof that mathematics is not just about numbers, but about wonder, creativity, and the endless possibilities hidden within the fabric of reality.&lt;/p&gt;</description></item><item><title>The Hacker Ethic</title><link>https://blog-test.funkysi1701.com/posts/2025/the-hacker-ethic/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Sep 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/the-hacker-ethic/</guid><category term="hacking">hacking</category><category term="ethics">ethics</category><category term="hackerculture">hackerculture</category><category term="Technology">Technology</category><category term="innovation">innovation</category><category term="curiosity">curiosity</category><category term="Security">Security</category><category term="digitalrights">digitalrights</category><category term="OpenSource">OpenSource</category><category term="mindset">mindset</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/hacker.jpg"/><description>&lt;h2 id="the-hacker-ethic-principles-that-shaped-the-digital-age"&gt;The Hacker Ethic: Principles That Shaped the Digital Age&lt;a class="anchor ms-1" href="#the-hacker-ethic-principles-that-shaped-the-digital-age" aria-label="Permalink: The Hacker Ethic: Principles That Shaped the Digital Age"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When most people hear the word “hacker,” they imagine shadowy figures breaking into computer systems. But the original meaning of “hacker” is far richer, rooted in curiosity, creativity, and a set of values that have profoundly shaped technology and culture. This philosophy, known as the &lt;strong&gt;hacker ethic&lt;/strong&gt;, remains a powerful force driving innovation and openness in our digital world.&lt;/p&gt;
&lt;h2 id="what-is-the-hacker-ethic"&gt;What Is the Hacker Ethic?&lt;a class="anchor ms-1" href="#what-is-the-hacker-ethic" aria-label="Permalink: What Is the Hacker Ethic?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The term “hacker ethic” was popularized by Steven Levy in his book &lt;em&gt;Hackers: Heroes of the Computer Revolution&lt;/em&gt; (I have just finished listening to the audio version and highly recommend it). The book describes a set of beliefs and practices developed by early computer enthusiasts at places like MIT, Stanford, and the Homebrew Computer Club. Far from criminality, the hacker ethic is about playful exploration, sharing knowledge, and questioning limits.&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/hacker.jpg" alt="Hackers: Heroes of the Computer Revolution" width="300" height="400" class="img-fluid float-end ms-2" /&gt;
&lt;h2 id="the-core-principles"&gt;The Core Principles&lt;a class="anchor ms-1" href="#the-core-principles" aria-label="Permalink: The Core Principles"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The hacker ethic can be distilled into several key tenets:&lt;/p&gt;
&lt;h3 id="1-access-to-computers-should-be-unlimited-and-total"&gt;1. Access to Computers Should Be Unlimited and Total&lt;a class="anchor ms-1" href="#1-access-to-computers-should-be-unlimited-and-total" aria-label="Permalink: 1. Access to Computers Should Be Unlimited and Total"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hackers believe that information and tools for learning should be open to all. They value environments where curiosity is encouraged and barriers to entry are low. This spirit led to the creation of open-source software, free educational resources, and collaborative online communities.&lt;/p&gt;
&lt;h3 id="2-all-information-wants-to-be-free"&gt;2. All Information Wants to Be Free&lt;a class="anchor ms-1" href="#2-all-information-wants-to-be-free" aria-label="Permalink: 2. All Information Wants to Be Free"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While not advocating for stealing proprietary data, hackers champion the free flow of information. They believe that sharing code, knowledge, and discoveries accelerates progress and empowers individuals. This principle underlies movements like open data, Creative Commons, and Wikipedia.&lt;/p&gt;
&lt;h3 id="3-mistrust-authoritypromote-decentralization"&gt;3. Mistrust Authority—Promote Decentralization&lt;a class="anchor ms-1" href="#3-mistrust-authoritypromote-decentralization" aria-label="Permalink: 3. Mistrust Authority—Promote Decentralization"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hackers are skeptical of gatekeepers and centralized control. They prefer systems that empower individuals and distribute power. This mindset has influenced everything from peer-to-peer networks to blockchain technology.&lt;/p&gt;
&lt;h3 id="4-hackers-should-be-judged-by-their-hacking-not-bogus-criteria"&gt;4. Hackers Should Be Judged by Their Hacking, Not Bogus Criteria&lt;a class="anchor ms-1" href="#4-hackers-should-be-judged-by-their-hacking-not-bogus-criteria" aria-label="Permalink: 4. Hackers Should Be Judged by Their Hacking, Not Bogus Criteria"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hackers value skill, creativity, and contribution over credentials or status. In hacker culture, what matters is what you build, solve, or improve—not your job title, age, or background. This meritocratic ideal helped shape the egalitarian ethos of the internet.&lt;/p&gt;
&lt;h3 id="5-you-can-create-art-and-beauty-on-a-computer"&gt;5. You Can Create Art and Beauty on a Computer&lt;a class="anchor ms-1" href="#5-you-can-create-art-and-beauty-on-a-computer" aria-label="Permalink: 5. You Can Create Art and Beauty on a Computer"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hackers see computers not only as tools, but as canvases for creativity. From elegant code to digital art, they celebrate the artistry inherent in technology and design.&lt;/p&gt;
&lt;h3 id="6-computers-can-change-your-life-for-the-better"&gt;6. Computers Can Change Your Life for the Better&lt;a class="anchor ms-1" href="#6-computers-can-change-your-life-for-the-better" aria-label="Permalink: 6. Computers Can Change Your Life for the Better"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hackers believe in the transformative potential of technology. They see computers as instruments of empowerment, education, and community—tools that can solve meaningful problems and improve lives.&lt;/p&gt;
&lt;h2 id="why-the-hacker-ethic-matters-today"&gt;Why the Hacker Ethic Matters Today&lt;a class="anchor ms-1" href="#why-the-hacker-ethic-matters-today" aria-label="Permalink: Why the Hacker Ethic Matters Today"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The hacker ethic is alive in open-source communities, maker spaces, and digital activism. It challenges us to question closed systems, embrace sharing, and use technology for good. In a world increasingly shaped by algorithms and artificial intelligence, the hacker ethic reminds us that human creativity, curiosity, and collaboration are still at the heart of progress.&lt;/p&gt;
&lt;p&gt;After listening to the book, it&amp;rsquo;s clear that many of today&amp;rsquo;s security problems stem from this ethic. Early computers and software were built by design without security in mind. The hackers featured in the book strongly disliked passwords and locks; they believed information and systems should be open to all. I had incorrectly assumed this was merely an oversight, or that security wasn&amp;rsquo;t considered necessary at the time.&lt;/p&gt;
&lt;p&gt;The growth of open source software can clearly be seen as an extension to the sharing of code started by these early hackers, instead of looking in a drawer for paper tape containing the code you want to improve, we go to GitHub, but the principle is the same.&lt;/p&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;a class="anchor ms-1" href="#final-thoughts" aria-label="Permalink: Final Thoughts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The hacker ethic is far more than a technical mindset—it’s a philosophy of openness, empowerment, and playful problem-solving. By understanding and embracing these principles, we can build a digital future that is more inclusive, innovative, and free.&lt;/p&gt;
&lt;p&gt;The more I think about my career with computers, the more I identify as a hacker rather than a programmer or any other job title. I started hacking together simple web pages, I then hacked away at networks and Active Directory, now I hack at .NET and Kubernetes.&lt;/p&gt;
&lt;p&gt;Sponsored Link: &lt;a href="https://amzn.to/49NwGHF" target="_blank" rel="noopener noreferrer"&gt;Hackers: Heroes of the Computer Revolution (book)&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Kubernetes SSL with Let's Encrypt</title><link>https://blog-test.funkysi1701.com/posts/2025/kubernetes-and-letsencrypt/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 07 Jul 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/kubernetes-and-letsencrypt/</guid><category term="Kubernetes">Kubernetes</category><category term="LetsEncrypt">LetsEncrypt</category><category term="SSL">SSL</category><category term="cert-manager">cert-manager</category><category term="Helm">Helm</category><category term="Cloudflare">Cloudflare</category><category term="DevOps">DevOps</category><category term="Security">Security</category><category term="Automation">Automation</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/cert-manager.png"/><description>&lt;p&gt;I have blogged before about how cool &lt;a href="https://blog-test.funkysi1701.com/posts/2018/lets-encrypt-is-awesome/"&gt;Let&amp;rsquo;s Encrypt&lt;/a&gt;
is for getting your web things running under https. However I have just got myself a local kubernetes cluster and it is super easy to spin up new web services with SSL certs.&lt;/p&gt;
&lt;p&gt;The basic instructions can be found &lt;a href="https://www.slingacademy.com/article/how-to-set-up-ssl-with-lets-encrypt-in-kubernetes/" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
but let&amp;rsquo;s look at what was involved.&lt;/p&gt;
&lt;p&gt;First of all lets get Cert Manager installed on kubernetes.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.1/cert-manager.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the cert manager pods are up, you need to create an issuer which communicates with the lets encrypt API. The first code snippet uses the lets encrypt staging environment to avoid any API limits, the second uses production and uses the cloudflare API to authorize SSL requests.&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ClusterIssuer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt-staging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;acme&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;server&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://acme-staging-v02.api.letsencrypt.org/directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;email&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;your-email@example.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;privateKeySecretRef&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt-staging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;solvers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;http01&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ingress&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ingressClassName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;nginx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ClusterIssuer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt-prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;acme&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;server&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://acme-v02.api.letsencrypt.org/directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;email&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;your-email@example.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;privateKeySecretRef&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt-prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;solvers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;dns01&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cloudflare&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;apiTokenSecretRef&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;key&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;api-key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cloudflare-api-token-secret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;email&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;your-email@example.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that is all configured all I need to do is update my helm chart and any pod I like can have a sub domain of funkysi1701.com with a lets encrypt SSL cert.&lt;/p&gt;
&lt;p&gt;This is a section from my helm chart which defines the domain name to use and what issuer to use for the certificate.&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;ingress&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;enabled&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;className&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;nginx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;annotations&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cert-manager.io/cluster-issuer&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;letsencrypt-prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;devHost&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;helloworld-dev.funkysi1701.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;testHost&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;helloworld-test.funkysi1701.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tls&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;secretName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;helloworld-dev.funkysi1701.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;hosts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;helloworld-dev.funkysi1701.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;secretName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;helloworld-test.funkysi1701.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;hosts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;helloworld-test.funkysi1701.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All I need to do now is add similar code like this to every helm chart I publish and my pod will request a SSL certificate. The only manual step I have is to set up a DNS record pointing to the IP address of my cluster for any domain I want to use.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Setting up Let&amp;rsquo;s Encrypt with Kubernetes and Cert Manager has made it incredibly easy to secure my web services with SSL certificates. With just a few YAML configurations and some simple Helm chart updates, I can automatically provision and renew certificates for any subdomain I need. This approach not only saves time but also ensures my services are always protected with up-to-date encryption. If you&amp;rsquo;re running Kubernetes, I highly recommend giving Cert Manager and Let&amp;rsquo;s Encrypt a try for hassle-free SSL management.&lt;/p&gt;</description></item><item><title>Stepping outside my comfort zone</title><link>https://blog-test.funkysi1701.com/posts/2025/stepping-outside-your-comfort-zone/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 02 Jun 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/stepping-outside-your-comfort-zone/</guid><category term="Adventure">Adventure</category><category term="Family">Family</category><category term="PersonalGrowth">PersonalGrowth</category><category term="Travel">Travel</category><category term="Holiday">Holiday</category><category term="Outdoors">Outdoors</category><category term="Parenting">Parenting</category><category term="Experiences">Experiences</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/high-adventure.jpg"/><description>&lt;p&gt;Stepping outside my comfort zone doesn’t come naturally to me. I’m happiest behind my laptop, but every now and then, I know it’s important to try something new. This year, my family and I decided to do just that—and it turned out to be one of our most memorable weeks ever. Curious about what happens when you swap routine for adventure? Read on!&lt;/p&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;a class="anchor ms-1" href="#introduction" aria-label="Permalink: Introduction"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This week was our family holiday. Normally, we’d book a cottage somewhere nice and explore at our own pace. But this often leads to disagreements—everyone wants something different, and sometimes the places we visit aren’t as exciting as we hoped (especially for two kids aged 7 and 9 who get bored easily).&lt;/p&gt;
&lt;p&gt;This time, we chose a different path: a family adventure holiday with &lt;a href="https://www.highadventureholidays.co.uk/" target="_blank" rel="noopener noreferrer"&gt;High Adventure&lt;/a&gt;
. The itinerary was packed: climbing, caving, hiking, water sports, archery, zip wires, and countless other activities. All meals, accommodation, equipment, and expert instructors were included, making it feel both safe and exciting.&lt;/p&gt;
&lt;p&gt;I’ll admit, I was anxious before we set off. I’m not an adventurous person—I like &lt;a href="https://blog-test.funkysi1701.com/posts/2024/charity-hike"&gt;walking&lt;/a&gt;
, but I’d never tried anything like this. My nine-year-old son was dreading it, while my more adventurous seven-year-old was quietly excited. I worried that if the kids hated it, it would be a waste of money. But as soon as we arrived, those fears melted away.&lt;/p&gt;
&lt;h2 id="saturday"&gt;Saturday&lt;a class="anchor ms-1" href="#saturday" aria-label="Permalink: Saturday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We arrived on Saturday afternoon and were shown to our room. My only real complaint from the whole week: the room was tiny. With two bunk beds and four of us plus a week’s worth of clothes, it was a challenge to keep things tidy. Thankfully, the rest of the facility was spacious, and our room was right next to the games room—a bonus.&lt;/p&gt;
&lt;p&gt;Dinner was served at 6pm every evening, always a home-cooked meal. While I enjoyed the food, my fussy eaters weren’t always convinced, but there was usually something for everyone. We met the other family we’d be doing activities with.&lt;/p&gt;
&lt;p&gt;After dinner, we explored the Games Room and took on the Labyrinth—a tight, dark maze constructed under the floor. Helmets were required! I found it a bit tight, but my boys absolutely loved it.&lt;/p&gt;
&lt;h2 id="sunday"&gt;Sunday&lt;a class="anchor ms-1" href="#sunday" aria-label="Permalink: Sunday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/abseiling.jpg" alt="Abseiling" width="250px" style="padding-right: 15px; float: left; margin-bottom: 0.5rem;" /&gt;
&lt;p&gt;Every day began with a cooked breakfast and a make-your-own sandwich station for lunch. Sunday morning kicked off with climbing and abseiling. I’d never climbed before, so I was surprised—and proud—to make it all the way to the top of the 8-meter wall. My boys didn’t quite reach the top, but they pushed themselves higher than I expected. Abseiling was fun too, and a great way to come down after the climb.&lt;/p&gt;
&lt;p&gt;After lunch, we tried archery. I’d done it once before at my boys’ Scout group, but it took a while to hit the target consistently. Then came bushcraft: foraging for wood, using a knife to make kindling, and lighting a fire with a ferrocerium rod. My nine-year-old and I managed to get a fire going—definitely a memorable moment, especially when we roasted marshmallows.&lt;/p&gt;
&lt;p&gt;The evening’s activity was Nightline: a blindfolded obstacle course. This was a bit much for me, but the boys loved it. My job was to guide them through the course, describing what to climb over, under, or through, and when to stop.&lt;/p&gt;
&lt;h2 id="monday"&gt;Monday&lt;a class="anchor ms-1" href="#monday" aria-label="Permalink: Monday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Monday started with a walk up the hill to Wainman’s Pinnacle and some “weaseling” through the rocks—a favourite for the boys, especially since they’d done it before with Scouts. I skipped most of the weaseling but enjoyed the walk.&lt;/p&gt;
&lt;p&gt;In the afternoon, it was time for high ropes and a zip wire. We were safely roped in at all times, but stepping off a high ledge still required a leap of faith. My eldest was nervous and had to climb down at first, but after watching me try, he gave it another go—and loved it. That’s what this week was about: encouraging all of us to try new things.&lt;/p&gt;
&lt;p&gt;The evening activity was Eggbert: designing a contraption to protect an egg dropped from a height. We worked as a family, but failed to consider that the weight would flip the egg so it landed the wrong way up. Oops! We didn’t win, but it was great fun seeing everyone’s creative designs.&lt;/p&gt;
&lt;h2 id="tuesday"&gt;Tuesday&lt;a class="anchor ms-1" href="#tuesday" aria-label="Permalink: Tuesday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/caves.jpg" alt="Caving" width="250px" style="padding-left: 15px; float: right; margin-bottom: 0.5rem;" /&gt;
&lt;p&gt;Tuesday was our first full day offsite. The instructors drove us in a minibus to the Yorkshire Three Peaks area, where we explored underground caves. Wearing cave suits, wellies, and helmets, we were ready for adventure. I foolishly thought I wouldn’t need a change of clothes—turns out, crawling through water-filled tunnels means your wellies fill up fast! I wasn’t the biggest fan of being soaked, but the boys loved climbing and sliding through the narrow passages. We finished the day with ice cream and hot chocolate in Settle—a well-deserved treat.&lt;/p&gt;
&lt;p&gt;That evening, we tried circus skills and gathered around a campfire. The boys were entertained for ages, trying juggling and balance activities. I didn’t master anything, but I enjoyed relaxing by the fire with my wife and the other parents.&lt;/p&gt;
&lt;h2 id="wednesday"&gt;Wednesday&lt;a class="anchor ms-1" href="#wednesday" aria-label="Permalink: Wednesday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By Wednesday, tiredness was catching up with me! We tackled a five-mile walk around Malham Cove, taking in stunning views and great weather. The route included Gordale Scar and Janet’s Foss, a lovely waterfall where many people swam or paddled. We hadn’t brought towels, but that didn’t stop my boys from getting soaked. It’s a holiday—why not?&lt;/p&gt;
&lt;p&gt;Wednesday evening was supposed to be a parents’ night off, but we had to cut it short due to a family emergency.&lt;/p&gt;
&lt;h2 id="thursday"&gt;Thursday&lt;a class="anchor ms-1" href="#thursday" aria-label="Permalink: Thursday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thursday was water sports day, but we decided on a quieter option and visited Haworth instead. The town is famous for the Brontë sisters, and we enjoyed its picturesque streets, a museum, and a play area for the kids—a great way to wind down after so much activity.&lt;/p&gt;
&lt;p&gt;The final evening was a quiz night, complete with questions about the week’s adventures.&lt;/p&gt;
&lt;h2 id="friday"&gt;Friday&lt;a class="anchor ms-1" href="#friday" aria-label="Permalink: Friday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Friday was going-home day, but not before one last challenge: orienteering. As a former university orienteering club member, I couldn’t resist joining in!&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This week was truly about stepping outside my comfort zone and embracing new experiences. From climbing and caving to bushcraft and zip lines, every activity challenged me and helped me grow. I discovered that pushing your boundaries can be both exciting and rewarding—and creates memories that last a lifetime. If you ever get the chance to try something new, even if it feels a bit daunting, I highly recommend taking the leap. You might just surprise yourself!&lt;/p&gt;</description></item><item><title>Deploy this blog with Helm charts</title><link>https://blog-test.funkysi1701.com/posts/2025/deploying-hugo-with-helm/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 26 May 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/deploying-hugo-with-helm/</guid><category term="Kubernetes">Kubernetes</category><category term="Helm">Helm</category><category term="DevOps">DevOps</category><category term="Hugo">Hugo</category><category term="Blog">Blog</category><category term="Deployment">Deployment</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/helm-hugo.png"/><description>&lt;p&gt;Helm allows you to package your Kubernetes resources, manage configuration, and deploy updates with a single command.&lt;/p&gt;
&lt;p&gt;In this post, I’ll share how I used Helm to deploy my Hugo blog, making it easy to manage updates and spin up new environments. Full disclosure: My blog currently runs on an Azure Static Web App, but now that I know how to deploy to a Kubernetes cluster, I have the option to switch if needed.&lt;/p&gt;
&lt;h2 id="why-use-helm"&gt;Why Use Helm?&lt;a class="anchor ms-1" href="#why-use-helm" aria-label="Permalink: Why Use Helm?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Helm is the package manager for Kubernetes. It lets you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Template&lt;/strong&gt; your Kubernetes YAML files for reuse and configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version&lt;/strong&gt; your deployments for easy rollbacks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Share&lt;/strong&gt; your charts with others or use community charts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="creating-a-helm-chart-for-hugo"&gt;Creating a Helm Chart for Hugo&lt;a class="anchor ms-1" href="#creating-a-helm-chart-for-hugo" aria-label="Permalink: Creating a Helm Chart for Hugo"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, I scaffolded a new Helm chart:&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-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm create hugo-blog
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates a directory structure with templates for deployments, services, and ingress.&lt;/p&gt;
&lt;h3 id="customizing-the-chart"&gt;Customizing the Chart&lt;a class="anchor ms-1" href="#customizing-the-chart" aria-label="Permalink: Customizing the Chart"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I edited &lt;code&gt;values.yaml&lt;/code&gt; to set my image and service details:&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;image&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;repository&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;mydockerhubusername/hugo-blog&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Docker image repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tag&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;latest&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Use the latest tag for the image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;pullPolicy&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;IfNotPresent&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Pull the image only if it’s not already present&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;service&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;type&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;NodePort&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Expose the service on a specific port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;port&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Internal port for the service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;nodePort&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30081&lt;/span&gt; &lt;span style="color:#75715e"&gt;# External port for accessing the service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="deploying-the-blog"&gt;Deploying the Blog&lt;a class="anchor ms-1" href="#deploying-the-blog" aria-label="Permalink: Deploying the Blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To deploy the blog, I ran:&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-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install my-hugo-blog ./hugo-blog
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Helm rendered the templates and created the necessary Kubernetes resources.&lt;/p&gt;
&lt;h3 id="updating-the-blog"&gt;Updating the Blog&lt;a class="anchor ms-1" href="#updating-the-blog" aria-label="Permalink: Updating the Blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When I rebuild and push a new Docker image, I can upgrade my deployment with:&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-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm upgrade my-hugo-blog ./hugo-blog
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This triggers a rolling update in Kubernetes.&lt;/p&gt;
&lt;h3 id="creating-a-docker-image-of-my-blog"&gt;Creating a Docker Image of my Blog&lt;a class="anchor ms-1" href="#creating-a-docker-image-of-my-blog" aria-label="Permalink: Creating a Docker Image of my Blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This all assumes that I have a container image of my Hugo blog. Creating this was half the work.&lt;/p&gt;
&lt;p&gt;I had been using a docker-compose file to build my blog; however, this doesn&amp;rsquo;t copy my files into the container it creates a volume to share my files with the container. I needed a Dockerfile that would copy my source code into a container and then save it into a container registry.&lt;/p&gt;
&lt;p&gt;This is the Dockerfile I created. As you can see, it is a two-stage build. First, it takes the Hugo base image, copies my files into it, and builds Hugo. Then the NGINX web server is run, and the default web port 80 is exposed.&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-Dockerfile" data-lang="Dockerfile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 1: Build the Hugo site&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;floryn90/hugo:0.119.0&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;builder&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Set working directory inside the container&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;WORKDIR&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/src&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Copy site files to the container&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COPY&lt;/span&gt; . .&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Build the Hugo site&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;RUN&lt;/span&gt; hugo --minify --config config.toml&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 2: Serve with nginx&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;nginx:alpine&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Remove the default nginx static files&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;RUN&lt;/span&gt; rm -rf /usr/share/nginx/html/*&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Copy the generated site from the builder stage&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COPY&lt;/span&gt; --from&lt;span style="color:#f92672"&gt;=&lt;/span&gt;builder /src/public /usr/share/nginx/html&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Expose port 80&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;EXPOSE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;80&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Start nginx&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CMD&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;nginx&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;-g&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;daemon off;&amp;#34;&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="benefits"&gt;Benefits&lt;a class="anchor ms-1" href="#benefits" aria-label="Permalink: Benefits"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repeatable Deployments:&lt;/strong&gt; Easily spin up new environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration Management:&lt;/strong&gt; Override values for different clusters or environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy Updates:&lt;/strong&gt; Upgrade with a single command.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Helm charts have made deploying my Hugo blog to Kubernetes a seamless and efficient process. With features like templating, versioning, and easy updates, Helm is a must-have tool for Kubernetes deployments.&lt;/p&gt;
&lt;p&gt;If you’re managing static sites or microservices, give Helm a try and see how it can simplify your workflow!&lt;/p&gt;
&lt;p&gt;Have you used Helm for static sites or blogs? Share your experience in the comments below!&lt;/p&gt;</description></item><item><title>Learning Kubernetes: A Beginner's Journey</title><link>https://blog-test.funkysi1701.com/posts/2025/learning-kubernetes/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 12 May 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/learning-kubernetes/</guid><category term="Kubernetes">Kubernetes</category><category term="Docker">Docker</category><category term="Grafana">Grafana</category><category term="ContainerOrchestration">ContainerOrchestration</category><category term="DevOps">DevOps</category><category term="Microservices">Microservices</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/kubernetes.png"/><description>&lt;p&gt;I know nothing (or very little) about Kubernetes. It is high time I do something to learn more about it. Kubernetes is a powerful tool for managing containerized applications, and it&amp;rsquo;s becoming a must-have skill for developers and DevOps engineers. In this blog, I&amp;rsquo;ll share my journey as a beginner exploring Kubernetes, from running a simple Grafana pod to understanding the basics of &lt;code&gt;kubectl&lt;/code&gt;. Let&amp;rsquo;s dive in!&lt;/p&gt;
&lt;h2 id="what-is-kubernetes"&gt;What is Kubernetes?&lt;a class="anchor ms-1" href="#what-is-kubernetes" aria-label="Permalink: What is Kubernetes?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Kubernetes is an open-source container orchestration platform that automates the deployment, scaling, and management of containerized applications. If you want to run your containerized applications, you probably want to learn Kubernetes.&lt;/p&gt;
&lt;p&gt;I have worked at least two companies so far in my career that have made use of Kubernetes to run their microservice architecture. Let&amp;rsquo;s take a look at how to use it.&lt;/p&gt;
&lt;h3 id="why-learn-kubernetes"&gt;Why Learn Kubernetes?&lt;a class="anchor ms-1" href="#why-learn-kubernetes" aria-label="Permalink: Why Learn Kubernetes?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Kubernetes is widely used in modern software development for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Microservices&lt;/strong&gt;: Manage and scale multiple services independently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI/CD Pipelines&lt;/strong&gt;: Automate deployments and rollbacks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Handle traffic spikes by scaling pods up or down.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="docker-desktop"&gt;Docker Desktop&lt;a class="anchor ms-1" href="#docker-desktop" aria-label="Permalink: Docker Desktop"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.docker.com/products/docker-desktop/" target="_blank" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt;
is a tool for running containers, but it also allows running of Kubernetes.&lt;/p&gt;
&lt;p&gt;I am not going to talk through installing docker desktop and getting a Kubernetes cluster set up, for that check out the &lt;a href="https://docs.docker.com/desktop/use-desktop/kubernetes/" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;
however I found it very straightforward.&lt;/p&gt;
&lt;h2 id="kubectl"&gt;kubectl&lt;a class="anchor ms-1" href="#kubectl" aria-label="Permalink: kubectl"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;kubectl is the command line tool for doing everything with Kubernetes.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This prints out basic version information, if this works you know Kubernetes must be working.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl config get-contexts
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl config use-context docker-desktop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command allows you to switch contexts, to use with docker desktop you want to use the docker-desktop context. At work we have dev and test contexts that can be selected in a similar way.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Context&lt;/strong&gt;: A Kubernetes context is a set of access parameters for a cluster. It allows you to switch between different clusters or environments (e.g., dev, test, production).&lt;/li&gt;
&lt;/ul&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get all
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives you a list of everything that is running in the default namespace, pods, services, deployments etc For a complete list, you can add the &amp;ndash;all-namespaces flag.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Namespace&lt;/strong&gt;: A namespace is a way to organize resources in a Kubernetes cluster, providing isolation between different projects or teams.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hello-world"&gt;Hello World&lt;a class="anchor ms-1" href="#hello-world" aria-label="Permalink: Hello World"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now what is the equivalent of &amp;ldquo;Hello World&amp;rdquo; for Kubernetes? I think getting a container to run in Kubernetes is a pretty good test.&lt;/p&gt;
&lt;p&gt;Open up VS Code and create a yaml file called grafana.yaml&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;v1&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Specifies the API version for the resource&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Pod&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Defines the resource type as a Pod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;grafana&lt;/span&gt; &lt;span style="color:#75715e"&gt;# The name of the pod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;containers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;grafana&lt;/span&gt; &lt;span style="color:#75715e"&gt;# The name of the container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;grafana/grafana:12.0.0&lt;/span&gt; &lt;span style="color:#75715e"&gt;# The container image to use&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;containerPort&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt; &lt;span style="color:#75715e"&gt;# The port exposed by the container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This file uses the Grafana container image, which I am familiar with (see &lt;a href="https://blog-test.funkysi1701.com/posts/2025/setting-up-grafana/"&gt;my previous blog posts&lt;/a&gt;
) It&amp;rsquo;s default port is 3000 which you can see is defined in this file.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl apply &lt;span style="color:#f92672"&gt;-f&lt;/span&gt; grafana.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This deploys a pod, using the above yaml file.&lt;/p&gt;
&lt;p&gt;You can run the following to find out more about the pod.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl describe pod grafana
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From what I have discovered so far, Kubernetes runs in its own network. So going to localhost:3000 won&amp;rsquo;t work. But you can use port forward to get round this issue.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Port-Forwarding&lt;/strong&gt;: This allows you to access a pod&amp;rsquo;s service on your local machine by forwarding a port from the pod to your localhost.&lt;/li&gt;
&lt;/ul&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl port-forward pod/grafana &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if I try http://localhost:3000/login I see the login page for the Grafana container. A pretty good first test of using Kubernetes.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;Whats next?&lt;a class="anchor ms-1" href="#whats-next" aria-label="Permalink: Whats next?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I want to replace my local deployment of containers that is currently using a docker compose file with Kubernetes. I also want to learn more about &lt;a href="https://helm.sh/" target="_blank" rel="noopener noreferrer"&gt;Helm charts&lt;/a&gt;
as I believe these are an excellent way of packaging up changes to Kubernetes.&lt;/p&gt;
&lt;p&gt;Have you tried running a pod in Kubernetes? What challenges did you face, and how did you overcome them? Share your thoughts in the comments below!&lt;/p&gt;</description></item><item><title>Getting started with OpenTelemetry</title><link>https://blog-test.funkysi1701.com/posts/2025/getting-started-with-opentelemetry/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 05 May 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/getting-started-with-opentelemetry/</guid><category term="OpenTelemetry">OpenTelemetry</category><category term="Observability">Observability</category><category term="Tracing">Tracing</category><category term="Metrics">Metrics</category><category term="Logging">Logging</category><category term="DotNet">DotNet</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/open-telemetry.png"/><description>&lt;h2 id="what-is-opentelemetry"&gt;What is OpenTelemetry?&lt;a class="anchor ms-1" href="#what-is-opentelemetry" aria-label="Permalink: What is OpenTelemetry?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OpenTelemetry is an open-source observability framework that provides a unified way to collect, process, and export telemetry data such as &lt;strong&gt;traces&lt;/strong&gt;, &lt;strong&gt;metrics&lt;/strong&gt;, and &lt;strong&gt;logs&lt;/strong&gt;. It is designed to help developers monitor and debug distributed systems by providing insights into application performance and behavior.&lt;/p&gt;
&lt;p&gt;With OpenTelemetry, you can instrument your applications to gain visibility into how requests flow through your system, identify bottlenecks, and troubleshoot issues effectively.&lt;/p&gt;
&lt;h2 id="why-use-opentelemetry"&gt;Why Use OpenTelemetry?&lt;a class="anchor ms-1" href="#why-use-opentelemetry" aria-label="Permalink: Why Use OpenTelemetry?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here are some key benefits of using OpenTelemetry:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Unified Observability&lt;/strong&gt;: Collect traces, metrics, and logs using a single framework.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vendor-Neutral&lt;/strong&gt;: Export telemetry data to any backend, such as Azure Monitor, Grafana, or Prometheus.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standardized APIs&lt;/strong&gt;: Use consistent APIs and SDKs across multiple programming languages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;: Easily extend OpenTelemetry to meet your specific observability needs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Community-Driven&lt;/strong&gt;: Backed by a large and active open-source community.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="key-components-of-opentelemetry"&gt;Key Components of OpenTelemetry&lt;a class="anchor ms-1" href="#key-components-of-opentelemetry" aria-label="Permalink: Key Components of OpenTelemetry"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OpenTelemetry consists of the following core components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Traces&lt;/strong&gt;: Capture the lifecycle of a request as it flows through your system. Traces help you understand dependencies and latency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metrics&lt;/strong&gt;: Collect numerical data, such as request counts, CPU usage, and memory consumption, to monitor system health.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logs&lt;/strong&gt;: Record discrete events, such as errors or state changes, to provide additional context for debugging.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="setting-up-opentelemetry-in-net"&gt;Setting Up OpenTelemetry in .NET&lt;a class="anchor ms-1" href="#setting-up-opentelemetry-in-net" aria-label="Permalink: Setting Up OpenTelemetry in .NET"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here’s how you can get started with OpenTelemetry in a .NET application:&lt;/p&gt;
&lt;h3 id="step-1-install-the-required-nuget-packages"&gt;Step 1: Install the Required NuGet Packages&lt;a class="anchor ms-1" href="#step-1-install-the-required-nuget-packages" aria-label="Permalink: Step 1: Install the Required NuGet Packages"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run the following commands to install the OpenTelemetry libraries:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dotnet add package OpenTelemetry
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dotnet add package OpenTelemetry.Extensions.Hosting
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dotnet add package OpenTelemetry.Exporter.Console
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="step-2-configure-opentelemetry-in-your-application"&gt;Step 2: Configure OpenTelemetry in Your Application&lt;a class="anchor ms-1" href="#step-2-configure-opentelemetry-in-your-application" aria-label="Permalink: Step 2: Configure OpenTelemetry in Your Application"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add the following code to your Program.cs or Startup.cs file:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; OpenTelemetry;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; OpenTelemetry.Trace;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; OpenTelemetry.Metrics;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; builder = WebApplication.CreateBuilder(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Add OpenTelemetry tracing and metrics&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.Services.AddOpenTelemetry()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithTracing(tracerProviderBuilder =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tracerProviderBuilder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddAspNetCoreInstrumentation()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddHttpClientInstrumentation()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddConsoleExporter(); &lt;span style="color:#75715e"&gt;// Export traces to the console&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithMetrics(metricsProviderBuilder =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; metricsProviderBuilder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddAspNetCoreInstrumentation()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddRuntimeInstrumentation()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddConsoleExporter(); &lt;span style="color:#75715e"&gt;// Export metrics to the console&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; app = builder.Build();
&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;app.MapGet(&lt;span style="color:#e6db74"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, () =&amp;gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Hello, OpenTelemetry!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.Run();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="step-3-run-your-application"&gt;Step 3: Run Your Application&lt;a class="anchor ms-1" href="#step-3-run-your-application" aria-label="Permalink: Step 3: Run Your Application"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Start your application and observe the telemetry data in the console. You’ll see traces and metrics being logged as requests are processed.&lt;/p&gt;
&lt;h2 id="aspire-and-how-to-view-telemetry"&gt;Aspire and how to view Telemetry&lt;a class="anchor ms-1" href="#aspire-and-how-to-view-telemetry" aria-label="Permalink: Aspire and how to view Telemetry"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If your .NET code is .Net 8 or higher you can use Aspire which configures OpenTelemetry for free! Check out &lt;a href="https://blog-test.funkysi1701.com/posts/2024/aspire"&gt;Getting started with .Net Aspire&lt;/a&gt;
. Once Aspire is setup, you will be able to see Logs, Traces and Metrics in the Aspire Dashboard.&lt;/p&gt;
&lt;p&gt;Another popular way to view your data is Grafana, where you can create custom dashboards. I have talked about adding &lt;a href="https://blog-test.funkysi1701.com/posts/2025/opentelemetry-logs/"&gt;Logs&lt;/a&gt;
to Grafana recently.&lt;/p&gt;
&lt;p&gt;There are lots of other ways to view your data, like Application Insights, DataDog, Jaeger, New Relic and many more.&lt;/p&gt;
&lt;p&gt;But you are not tied to one solution, you can send your data to more than one of these if you wish.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OpenTelemetry simplifies observability by providing a unified framework for collecting traces, metrics, and logs. Whether you&amp;rsquo;re building microservices, monitoring distributed systems, or debugging performance issues, OpenTelemetry is a powerful tool to have in your arsenal.&lt;/p&gt;
&lt;p&gt;Start using OpenTelemetry today and gain deeper insights into your applications!&lt;/p&gt;
&lt;p&gt;Have you tried OpenTelemetry? Share your experiences and tips in the comments below!&lt;/p&gt;</description></item><item><title>New in .NET Aspire 9.2: diagrams</title><link>https://blog-test.funkysi1701.com/posts/2025/aspire-9.2/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 21 Apr 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/aspire-9.2/</guid><category term="DotNet">DotNet</category><category term="Aspire">Aspire</category><category term="InfrastructureDiagrams">InfrastructureDiagrams</category><category term="VisualStudio">VisualStudio</category><category term="Docker">Docker</category><category term="Microservices">Microservices</category><category term="Grafana">Grafana</category><category term="Programming">Programming</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/work.PNG"/><description>&lt;p&gt;.NET Aspire 9.2 is here, bringing exciting new features to simplify infrastructure visualization. Whether you&amp;rsquo;re managing microservices or exploring Docker-based architectures, this release makes it easier than ever to create detailed infrastructure diagrams with minimal effort. Let’s dive into the highlights and see how you can use these tools to streamline your workflow.&lt;/p&gt;
&lt;p&gt;For details of what .NET Aspire is, check out my &lt;a href="https://blog-test.funkysi1701.com/posts/2024/aspire"&gt;post&lt;/a&gt;
from last year. For the official announcement see &lt;a href="https://aspire.dev/whats-new/aspire-13-1/" target="_blank" rel="noopener noreferrer"&gt;What&amp;rsquo;s new in .NET Aspire 9.2&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;My favourite feature from this release is the ability to quickly and easily spin up infrastructure diagrams like this:&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Aspire Diagram" src="https://blog-test.funkysi1701.com/images/aspire-9.2.jpg" loading="lazy"
width="764" height="675"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;An example infrastructure diagram created using .NET Aspire 9.2.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I also created one last week for my blog about &lt;a href="https://blog-test.funkysi1701.com/posts/2025/opentelemetry-logs/"&gt;Grafana&lt;/a&gt;
:&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Grafana Example" src="https://blog-test.funkysi1701.com/images/grafana-loki-arch.png" loading="lazy"
width="811" height="593"
/&gt;
&lt;/p&gt;
&lt;h2 id="so-what-code-is-needed-to-create-one-of-these-diagrams"&gt;So what code is needed to create one of these diagrams?&lt;a class="anchor ms-1" href="#so-what-code-is-needed-to-create-one-of-these-diagrams" aria-label="Permalink: So what code is needed to create one of these diagrams?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Open Visual Studio and create a new project of type &amp;ldquo;.NET Aspire App Host&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Edit the Program.cs and add docker containers for anything you want to display on the diagram&lt;/li&gt;
&lt;li&gt;The syntax for this is is shown in my Grafana example:&lt;/li&gt;
&lt;/ol&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; builder = DistributedApplication.CreateBuilder(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Add a .NET application container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; dotnet = builder.AddContainer(&lt;span style="color:#e6db74"&gt;&amp;#34;dotnet-application&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;anyimage&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithHttpEndpoint(port: &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;, targetPort: &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// Expose HTTP port 80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Add a Loki container for log aggregation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; loki = builder.AddContainer(&lt;span style="color:#e6db74"&gt;&amp;#34;loki&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;grafana/loki&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;3.4.3&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithHttpEndpoint(port: &lt;span style="color:#ae81ff"&gt;3100&lt;/span&gt;, targetPort: &lt;span style="color:#ae81ff"&gt;3100&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// Expose HTTP port 3100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Add an Alloy container for telemetry processing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; alloy = builder.AddContainer(&lt;span style="color:#e6db74"&gt;&amp;#34;alloy&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;grafana/alloy&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;v1.8.1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithHttpEndpoint(port: &lt;span style="color:#ae81ff"&gt;12345&lt;/span&gt;, targetPort: &lt;span style="color:#ae81ff"&gt;12345&lt;/span&gt;, name: &lt;span style="color:#e6db74"&gt;&amp;#34;UI&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// Expose UI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithHttpEndpoint(port: &lt;span style="color:#ae81ff"&gt;4317&lt;/span&gt;, targetPort: &lt;span style="color:#ae81ff"&gt;4317&lt;/span&gt;, name: &lt;span style="color:#e6db74"&gt;&amp;#34;gRPC&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// Expose gRPC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithHttpEndpoint(port: &lt;span style="color:#ae81ff"&gt;4318&lt;/span&gt;, targetPort: &lt;span style="color:#ae81ff"&gt;4318&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;http&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// Expose HTTP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Add a Grafana container for visualization&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; grafana = builder.AddContainer(&lt;span style="color:#e6db74"&gt;&amp;#34;grafana&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;grafana/grafana&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;11.6.0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithHttpEndpoint(port: &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;, targetPort: &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// Expose HTTP port 3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Define relationships between containers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dotnet.WithReferenceRelationship(alloy); &lt;span style="color:#75715e"&gt;// Logs flow from .NET app to Alloy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alloy.WithReferenceRelationship(loki); &lt;span style="color:#75715e"&gt;// Logs flow from Alloy to Loki&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loki.WithReferenceRelationship(grafana); &lt;span style="color:#75715e"&gt;// Logs flow from Loki to Grafana&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.Build().Run();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The parameters for &lt;strong&gt;AddContainer()&lt;/strong&gt; are a name that gets displayed on the diagram, the docker image name, and the tag. The tag is optional and it will use latest if omitted. For my Grafana example, the first docker container I added is for any dotnet application. I can use any docker image for this, as all I want is a container labelled &amp;ldquo;dotnet-application&amp;rdquo;. The &lt;strong&gt;.WithHttpEndpoint&lt;/strong&gt; is for public ports to be displayed so you can see how communication is flowing between containers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;.WithReferenceRelationship()&lt;/strong&gt; is how you define what calls what. So dotnet.WithReferenceRelationship(alloy) adds an arrow pointing from my dotnet application to alloy, suggesting that open telemetry logs flow from my application to alloy. You can also add calls in both directions by adding alloy.WithReferenceRelationship(dotnet) this will change the arrow to point in both directions.&lt;/p&gt;
&lt;p&gt;At my work we use a microservice architecture so I thought it might be fun to try and map out what calls what:&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Work Architecture" src="https://blog-test.funkysi1701.com/images/work.PNG" loading="lazy"
width="2622" height="1869"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A simplified view of a microservices architecture at work (service names anonymized).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I made a start mapping a few of our services, but this doesn&amp;rsquo;t cover everything and I have replaced the names of the services so no commerical secrets can be identified. I was surprised at how complex the system is.&lt;/p&gt;
&lt;h3 id="real-world-applications"&gt;Real-World Applications&lt;a class="anchor ms-1" href="#real-world-applications" aria-label="Permalink: Real-World Applications"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The ability to generate infrastructure diagrams is invaluable for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Microservices Architecture&lt;/strong&gt;: Visualize how services interact and identify bottlenecks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debugging&lt;/strong&gt;: Quickly understand communication flows to troubleshoot issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation&lt;/strong&gt;: Create up-to-date diagrams for team collaboration and onboarding.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.NET Aspire 9.2 makes it easier than ever to create detailed infrastructure diagrams, saving time and improving collaboration. Whether you&amp;rsquo;re managing microservices or exploring Docker-based architectures, these tools can help you visualize and optimize your systems. Give it a try and see how it can enhance your workflow!&lt;/p&gt;
&lt;p&gt;Have you tried .NET Aspire 9.2? What features are you most excited about? Share your thoughts and experiences in the comments below!&lt;/p&gt;</description></item><item><title>OpenTelemetry logs via Grafana Loki</title><link>https://blog-test.funkysi1701.com/posts/2025/opentelemetry-logs/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 14 Apr 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/opentelemetry-logs/</guid><category term="OpenTelemetry">OpenTelemetry</category><category term="Grafana">Grafana</category><category term="Loki">Loki</category><category term="Alloy">Alloy</category><category term="Logging">Logging</category><category term="Monitoring">Monitoring</category><category term="Docker">Docker</category><category term="DotNet">DotNet</category><category term="Tech">Tech</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/grafana-loki-arch.png"/><description>&lt;p&gt;Logs are a critical part of monitoring and debugging modern applications. By integrating OpenTelemetry logs with Grafana using Loki and Alloy, you can centralize your log data, making it easier to analyze and monitor your .NET applications. In this blog, I&amp;rsquo;ll walk you through the setup process and share how these tools work together to streamline log aggregation and visualization.&lt;/p&gt;
&lt;p&gt;I have blogged about &lt;a href="https://blog-test.funkysi1701.com/posts/2025/setting-up-grafana/"&gt;Grafana&lt;/a&gt;
before but until now I haven&amp;rsquo;t added logs to Grafana let&amp;rsquo;s have a look at how that works.&lt;/p&gt;
&lt;p&gt;My dotnet application makes use of OpenTelemetry. I have been sending this telemetry to an Aspire Dashboard running in Docker. This allows me to view logs, metrics and traces.&lt;/p&gt;
&lt;p&gt;Grafana has several tools that can help with logs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Loki&lt;/strong&gt;: A log aggregation system designed to store and query logs from applications and infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alloy&lt;/strong&gt;: An OpenTelemetry collector that processes and forwards telemetry data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt;: A set of APIs, libraries, and tools for collecting and exporting telemetry data like logs, metrics, and traces.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am using Alloy to collect OpenTelemetry from my application and send it to Loki, The logs in Loki can then be read by Grafana.&lt;/p&gt;
&lt;h2 id="setting-up-loki-and-alloy-with-docker-compose"&gt;Setting Up Loki and Alloy with Docker Compose&lt;a class="anchor ms-1" href="#setting-up-loki-and-alloy-with-docker-compose" aria-label="Permalink: Setting Up Loki and Alloy with Docker Compose"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To start off let&amp;rsquo;s add Alloy and Loki to my docker compose file.&lt;/p&gt;
&lt;h3 id="docker-compose-configuration"&gt;Docker Compose Configuration&lt;a class="anchor ms-1" href="#docker-compose-configuration" aria-label="Permalink: Docker Compose Configuration"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;docker-compose.yml&lt;/code&gt; file defines the services for Loki and Alloy. Here&amp;rsquo;s what each section does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Loki&lt;/strong&gt;: Runs the Loki container on port 3100 and uses a local configuration file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alloy&lt;/strong&gt;: Runs the Alloy container, exposing ports for receiving telemetry data and processing logs.&lt;/li&gt;
&lt;/ul&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-docker-compose.yml" data-lang="docker-compose.yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Docker Compose configuration for Loki and Alloy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;command&lt;/span&gt;: -&lt;span style="color:#ae81ff"&gt;config.file=/etc/loki/local-config.yaml&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Specifies the configuration file for Loki&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;alloy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;grafana/alloy:v1.8.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;monitoring_alloy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;12345&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;12345&lt;/span&gt; &lt;span style="color:#75715e"&gt;# HTTP server for Alloy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;4317&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4317&lt;/span&gt; &lt;span style="color:#75715e"&gt;# gRPC endpoint for OpenTelemetry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;4319&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4318&lt;/span&gt; &lt;span style="color:#75715e"&gt;# HTTP endpoint for OpenTelemetry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;./config.alloy:/etc/alloy/config.alloy&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Mount Alloy configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;command&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;loki&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here is the config file for Alloy.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-alloy.config" data-lang="alloy.config"&gt;otelcol.receiver.otlp &amp;#34;default&amp;#34; {
http {}
grpc {}
output {
logs = [otelcol.processor.batch.default.input]
}
}
otelcol.processor.batch &amp;#34;default&amp;#34; {
output {
logs = [
otelcol.exporter.otlphttp.loki.input,
]
}
}
otelcol.exporter.otlphttp &amp;#34;loki&amp;#34; {
client {
endpoint = &amp;#34;http://loki:3100/otlp&amp;#34;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="how-the-components-work-together"&gt;How the Components Work Together&lt;a class="anchor ms-1" href="#how-the-components-work-together" aria-label="Permalink: How the Components Work Together"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Application Logs&lt;/strong&gt;: The .NET application generates logs and sends them to Alloy on port 4317.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alloy Processing&lt;/strong&gt;: Alloy processes the logs and forwards them to Loki on port 3100.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loki Storage&lt;/strong&gt;: Loki stores the logs, making them available for querying.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grafana Visualization&lt;/strong&gt;: Grafana connects to Loki as a data source, allowing you to visualize and analyze the logs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Architecture Diagram" src="https://blog-test.funkysi1701.com/images/grafana-loki-arch.png" loading="lazy"
width="811" height="593"
/&gt;
&lt;/p&gt;
&lt;h3 id="handling-aspire-dashboard-logs"&gt;Handling Aspire Dashboard Logs&lt;a class="anchor ms-1" href="#handling-aspire-dashboard-logs" aria-label="Permalink: Handling Aspire Dashboard Logs"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default, sending logs to Alloy and Loki means Aspire Dashboard will no longer receive them. To resolve this, you can configure the &lt;code&gt;AddOpenTelemetryExporters&lt;/code&gt; method in your .NET application to send logs to multiple destinations.&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-Extensions.cs" data-lang="Extensions.cs"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (useOtlpExporter)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// The following lines enable the OTLP exporter (requires the OpenTelemetry.Exporter.OpenTelemetryProtocol package)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; builder.Services.AddOpenTelemetry()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithLogging(logging =&amp;gt; logging.AddOtlpExporter(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.Endpoint = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Uri(builder.Configuration[&lt;span style="color:#e6db74"&gt;&amp;#34;OTEL_EXPORTER_OTLP_ENDPOINT&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithLogging(logging =&amp;gt; logging.AddOtlpExporter(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.Endpoint = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Uri(builder.Configuration[&lt;span style="color:#e6db74"&gt;&amp;#34;GrafanaExporter&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithMetrics(metrics =&amp;gt; metrics.AddOtlpExporter(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.Endpoint = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Uri(builder.Configuration[&lt;span style="color:#e6db74"&gt;&amp;#34;OTEL_EXPORTER_OTLP_ENDPOINT&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithTracing(tracing =&amp;gt; tracing.AddOtlpExporter(options =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.Endpoint = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Uri(builder.Configuration[&lt;span style="color:#e6db74"&gt;&amp;#34;OTEL_EXPORTER_OTLP_ENDPOINT&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If I update the AddOpenTelemetryExporters method in my Extensions.cs file in my .Net Aspire ServiceDefaults project, I can get my logs (or traces/metrics) to be sent to as many different places as I want. In my case I am sending to Allot and Aspire Dashboard.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Integrating OpenTelemetry logs with Grafana using Loki and Alloy provides a powerful solution for centralized log aggregation and monitoring. This setup simplifies debugging and enhances visibility into your application&amp;rsquo;s behaviour. If you haven&amp;rsquo;t tried it yet, give it a go and let me know your thoughts in the comments!&lt;/p&gt;</description></item><item><title>Exploring ChatGPT image generation</title><link>https://blog-test.funkysi1701.com/posts/2025/fun-with-ai/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 07 Apr 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/fun-with-ai/</guid><category term="AI">AI</category><category term="ChatGPT">ChatGPT</category><category term="ImageGeneration">ImageGeneration</category><category term="FunwithAI">FunwithAI</category><category term="Technology">Technology</category><category term="Creativity">Creativity</category><category term="MachineLearning">MachineLearning</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/ai-version-of-me.png"/><description>&lt;h2 id="fun-with-ai"&gt;Fun with AI&lt;a class="anchor ms-1" href="#fun-with-ai" aria-label="Permalink: Fun with AI"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AI tools like &lt;a href="https://chatgpt.com/" target="_blank" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;
are evolving rapidly, and their creative capabilities are nothing short of amazing. Recently, I decided to test its image generation features with a fun and quirky prompt. The results? A personalized action figure concept that blew my mind! Let me walk you through the process and share the results.&lt;/p&gt;
&lt;p&gt;I used the following prompt:&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Draw an action figure toy of the person in this photo.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The action figure should be full-figure and displayed in its original blister pack packaging.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;On top of the box is the name of the toy &amp;#34;Software Developer&amp;#34; across a single line of text.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;In the blister pack packaging, next to the figure, show the toy&amp;#39;s accessories,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;including a Microsoft laptop,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cup of coffee,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;the Visual Studio app,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GitHub app,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;and the Azure app.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There should be a label on the corner of the box that says &amp;#34;Limited Edition&amp;#34;.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;This figure should look like a premium toy and everything should be inside the plastic!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table border="0" cellpadding="0" cellspacing="0" &gt;
&lt;tr style="border-width:0px 0px 0px 0px"&gt;
&lt;td style="border-width:0px 0px 0px 0px"&gt;
and I supplied the following image:
&lt;/td&gt;
&lt;td style="border-width:0px 0px 0px 0px"&gt;
and this is the result:
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-width:0px 0px 0px 0px"&gt;
&lt;td style="border-width:0px 0px 0px 0px"&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/ndc-simon.jpg" alt="A picture of me as the source image" width="300" height="400" class="img-fluid" /&gt;
&lt;/td&gt;
&lt;td style="border-width:0px 0px 0px 0px"&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/ai-version-of-me.png" alt="AI generated version of me" width="300" height="400" class="img-fluid" /&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Pretty cool, right? Well I can&amp;rsquo;t take the credit for the prompt, It comes from &lt;a href="https://www.linkedin.com/posts/amyru_out-of-all-the-chatgpt-image-generation-capabilities-activity-7312549043610521601-BPqJ?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAAOBLj4B-Ls737kwBrHA1oRvkACb_CoRCQw2X0v1gk7q4r3w8Q9x5a6b0h4j2c1nqZz7g&amp;amp;lipi=urn%3Ali%3Apage%3Ad_flagship3_profile_view_base_post_primary%3B5JdYtG6mQeKx%2FfWl8V9jNQ%3D%3D" target="_blank" rel="noopener noreferrer"&gt;Amy Ru&lt;/a&gt;
on LinkedIn.&lt;/p&gt;
&lt;p&gt;Have you tried ChatGPT&amp;rsquo;s image generation features? What creative prompts have you used? Share your experiences in the comments below!&lt;/p&gt;</description></item><item><title>Automate social posts with AI in .NET</title><link>https://blog-test.funkysi1701.com/posts/2025/using-ai/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 17 Mar 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/using-ai/</guid><category term="AI">AI</category><category term="OpenAI">OpenAI</category><category term="SemanticKernel">SemanticKernel</category><category term="DotNet">DotNet</category><category term="RSS">RSS</category><category term="SocialMedia">SocialMedia</category><category term="Automation">Automation</category><category term="Programming">Programming</category><category term="Tech">Tech</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/social-ai.png"/><description>&lt;p&gt;Automating repetitive tasks is one of the best ways to save time and focus on what matters most. In this blog, I&amp;rsquo;ll show you how I used AI with .NET to automate the creation of social media posts for my blog. By leveraging my blog&amp;rsquo;s RSS feed, OpenAI, and Semantic Kernel, I was able to generate engaging posts effortlessly. Let&amp;rsquo;s dive in!&lt;/p&gt;
&lt;h2 id="using-openai-for-social-media-posts"&gt;Using OpenAI for Social Media Posts&lt;a class="anchor ms-1" href="#using-openai-for-social-media-posts" aria-label="Permalink: Using OpenAI for Social Media Posts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at a way to use AI for a practical use. For the last few weeks I have been using AI to help me write social media posts to promote my latest blog posts, let&amp;rsquo;s look at how I might automate this using .NET code.&lt;/p&gt;
&lt;p&gt;My blog publishes new posts to a rss feed, I can consume this from .NET code and pass it to AI, and create social media posts from them.&lt;/p&gt;
&lt;p&gt;My blog is written in Hugo and it is already generating an rss feed, however I have made a slight tweak to it. I want the tags from the blog article to be used as hashtags in any social media posts. I am storing the tags in the rss field category.&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;category&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;term=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;tagname&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;tagname&lt;span style="color:#f92672"&gt;&amp;lt;/category&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here is the section of code that generates my rss feed, the key tags I will be using are title, link, category and description.&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{ .Title }}&lt;span style="color:#f92672"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&amp;gt;&lt;/span&gt;{{ .Permalink }}&lt;span style="color:#f92672"&gt;&amp;lt;/link&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;author&amp;gt;&lt;/span&gt;{{ with .Params.author }}{{ . }}{{ else }}{{ with $.Site.Author.name }}{{.}}{{end}}{{end}}&lt;span style="color:#f92672"&gt;&amp;lt;/author&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;pubDate&amp;gt;&lt;/span&gt;{{ .Date.Format &amp;#34;Mon, 02 Jan 2006 15:04:05 -0700&amp;#34; | safeHTML }}&lt;span style="color:#f92672"&gt;&amp;lt;/pubDate&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {{ with .Site.Author.email }}&lt;span style="color:#f92672"&gt;&amp;lt;author&amp;gt;&lt;/span&gt;{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}&lt;span style="color:#f92672"&gt;&amp;lt;/author&amp;gt;&lt;/span&gt;{{end}}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;guid&amp;gt;&lt;/span&gt;{{ .Permalink }}&lt;span style="color:#f92672"&gt;&amp;lt;/guid&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {{- range .Params.tags -}}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;category&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;term=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;{{ replace . &amp;#34;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;}}&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{{ replace . &amp;#34; &amp;#34; &amp;#34;&amp;#34; }}&lt;span style="color:#f92672"&gt;&amp;lt;/category&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {{ end }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;{{ .Content | html }}&lt;span style="color:#f92672"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I am using the nuget package &lt;a href="https://github.com/arminreiter/FeedReader/" target="_blank" rel="noopener noreferrer"&gt;CodeHollow.FeedReader&lt;/a&gt;
, this allows me to pass in a URL to my rss feed, and get an object out which contains all the items in the feed. Using a nuget package saves me doing a lot of parsing of XML. The method I am using takes an input string something like &lt;a href="https://www.funkysi1701.com/index.xml" target="_blank" rel="noopener noreferrer"&gt;https://www.funkysi1701.com/index.xml&lt;/a&gt;
, and gives me an object I can query and do things with.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; RSSFeed = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; FeedReader.ReadAsync(FeedStringValue);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;RSS feed contains the following properties I want to use: Title, Link, Categories and Description. All are strings, except Categories which is an ICollection&amp;lt;string&amp;gt; This matches what I said I wanted to use from the rss feed.&lt;/p&gt;
&lt;p&gt;I want to pass the description to AI, and then combine the Response from AI with URL of the blog post and a comma separated list of &amp;lsquo;hashtags&amp;rsquo; (the categories in my rss feed).&lt;/p&gt;
&lt;p&gt;Initially I thought about using &lt;a href="https://ollama.com/" target="_blank" rel="noopener noreferrer"&gt;ollama&lt;/a&gt;
, this is an example of a LLM (Large Language Model) that you can install on your laptop, sometimes called a Small Language Model (SLM). However, I found this to be unreliable with my laptop and caused several system wide crashes. I assume this is due to memory usage and the size of the model. LLMs or SLMs do require a lot of system resources so this is not completely surprising. I will revisit this at some point as I would like to learn more about ollama.&lt;/p&gt;
&lt;p&gt;I already have an account on &lt;a href="https://platform.openai.com/" target="_blank" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;
and some credit so let&amp;rsquo;s try that instead. I have made a fair few requests using OpenAI and so far it has cost me 11p, I don&amp;rsquo;t think for my usage it is going to break the bank. If I was going to put something on the public internet I may have to reconsider but for my own personal use I think this should be fine.&lt;/p&gt;
&lt;p&gt;Next step, how do I talk to OpenAI from .NET. I know of two approaches, &lt;a href="https://github.com/microsoft/semantic-kernel" target="_blank" rel="noopener noreferrer"&gt;Semantic Kernel&lt;/a&gt;
and the new Microsoft.Extensions.AI libraries introduces in .NET 9 &lt;a href="https://devblogs.microsoft.com/dotnet/introducing-microsoft-extensions-ai-preview/" target="_blank" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/dotnet/introducing-microsoft-extensions-ai-preview/&lt;/a&gt;
. Semantic Kernel is what I am using here, however I do want to explore the newer libraries at some point.&lt;/p&gt;
&lt;p&gt;Semantic Kernel with OpenAI needs the following Nuget package: Microsoft.SemanticKernel.Connectors.OpenAI&lt;/p&gt;
&lt;p&gt;In my Program.cs I had the following to register and add to dependency injection.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (builder.Configuration.GetValue&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;OpenAI:Key&amp;#34;&lt;/span&gt;) != &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty)
&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; builder.Services.AddOpenAIChatCompletion(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; modelId: builder.Configuration.GetValue&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;OpenAI:Model&amp;#34;&lt;/span&gt;) ?? &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; apiKey: builder.Configuration.GetValue&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;OpenAI:Key&amp;#34;&lt;/span&gt;) ?? &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.Services.AddTransient((serviceProvider) =&amp;gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Kernel(serviceProvider));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OpenAI:Key is your API Key, which can be found from the OpenAI site, &lt;a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer"&gt;https://platform.openai.com/api-keys&lt;/a&gt;
OpenAI:Model is the model I am using, in my case &amp;ldquo;gpt-4o&amp;rdquo;, I&amp;rsquo;ve added it as a config option as I may find I want to change it.&lt;/p&gt;
&lt;p&gt;Now in the code where I want to call OpenAI I can just inject SemanticKernel and call its async methods. I am a backend developer, so I created a simple API that allows me to call it.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AIHandler&lt;/span&gt;(Kernel kernel)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; Task Handle(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; request, CancellationToken cancellationToken)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; response = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; kernel.InvokePromptAsync(request, cancellationToken);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Do something with the response...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the only step I am missing is what string or prompt do I want to pass to OpenAI?&lt;/p&gt;
&lt;p&gt;I want a social media post that will fit into a facebook/twitter/bluesky etc post, some of these services are character limited so I have included a character limit in my &amp;ldquo;prompt&amp;rdquo;, however I am being clever and counting the number of characters taken up by the URL and hashtags and subtracting that first.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; socialMediaPrompt = &lt;span style="color:#e6db74"&gt;$&amp;#34;write a social media post under {240 - length} characters, excluding hash tags about {feedItem.Description}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now once I put is all together I have a page that loads my rss feed, and I can click a button to generate a social media post.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Ai Example" src="https://blog-test.funkysi1701.com/images/ai-example.png" loading="lazy"
width="1843" height="432"
/&gt;
&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By combining .NET, Semantic Kernel, and OpenAI, I was able to automate the creation of social media posts, saving time and effort. This approach can be adapted for other use cases, such as summarizing content or generating marketing copy.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want to get a monthly email with all my latest articles, please sign up to my &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. If you have any questions or want to share your own experiences, feel free to leave a comment below!&lt;/p&gt;</description></item><item><title>Merge two Git projects, keep history</title><link>https://blog-test.funkysi1701.com/posts/2025/merge-two-projects-into-one/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 10 Mar 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/merge-two-projects-into-one/</guid><category term="Git">Git</category><category term="VersionControl">VersionControl</category><category term="RepositoryManagement">RepositoryManagement</category><category term="Development">Development</category><category term="Tech">Tech</category><category term="Programming">Programming</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/git-merge.png"/><description>&lt;p&gt;I needed to merge two separate projects into one repository while keeping the full commit history from both sides. Copy-paste would have worked for the files, but history would have stayed trapped in the old remotes.&lt;/p&gt;
&lt;p&gt;This approach adds the second repo as a remote, fetches it, and merges with &lt;code&gt;--allow-unrelated-histories&lt;/code&gt; so Git keeps both lineages. I still refer to the repos as &lt;code&gt;project1&lt;/code&gt; and &lt;code&gt;project2&lt;/code&gt;, with remotes at &lt;code&gt;project1Url&lt;/code&gt; and &lt;code&gt;project2Url&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="step-1-clone-the-original-repository"&gt;Step 1: Clone the original repository&lt;a class="anchor ms-1" href="#step-1-clone-the-original-repository" aria-label="Permalink: Step 1: Clone the original repository"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, clone the repository of &lt;code&gt;project1&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone project1Url
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-2-add-the-new-repository-as-a-remote"&gt;Step 2: Add the new repository as a remote&lt;a class="anchor ms-1" href="#step-2-add-the-new-repository-as-a-remote" aria-label="Permalink: Step 2: Add the new repository as a remote"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next, add the repository of &lt;code&gt;project2&lt;/code&gt; as a remote:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git remote add project2 project2Url
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-3-fetch-the-commits-from-the-new-repository"&gt;Step 3: Fetch the commits from the new repository&lt;a class="anchor ms-1" href="#step-3-fetch-the-commits-from-the-new-repository" aria-label="Permalink: Step 3: Fetch the commits from the new repository"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fetch the commits from the &lt;code&gt;project2&lt;/code&gt; repository:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git fetch project2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-4-merge-the-commits-from-the-new-repository"&gt;Step 4: Merge the commits from the new repository&lt;a class="anchor ms-1" href="#step-4-merge-the-commits-from-the-new-repository" aria-label="Permalink: Step 4: Merge the commits from the new repository"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Merge the commits from the &lt;code&gt;project2&lt;/code&gt; repository into &lt;code&gt;project1&lt;/code&gt;. Point at the branch that holds the code you want (often &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git merge project2/develop --allow-unrelated-histories
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-5-fix-merge-conflicts"&gt;Step 5: Fix merge conflicts&lt;a class="anchor ms-1" href="#step-5-fix-merge-conflicts" aria-label="Permalink: Step 5: Fix merge conflicts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If there are conflicts, you will need to resolve them. In my case, this was mainly build files and scripts in the root of the repository. Most of the important code was in subfolders, so this was minimal.&lt;/p&gt;
&lt;h2 id="step-6-push-the-changes-to-the-original-repository"&gt;Step 6: Push the changes to the original repository&lt;a class="anchor ms-1" href="#step-6-push-the-changes-to-the-original-repository" aria-label="Permalink: Step 6: Push the changes to the original repository"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Push the changes to a new branch for review before merging into the main branch:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git checkout -b feature/merge-project2-into-project1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push origin feature/merge-project2-into-project1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-7-clean-up"&gt;Step 7: Clean up&lt;a class="anchor ms-1" href="#step-7-clean-up" aria-label="Permalink: Step 7: Clean up"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Test your code to ensure everything builds and runs as expected now that it is all in one repository. Create a pull request and review all the changes to ensure nothing gets changed that shouldn&amp;rsquo;t be.&lt;/p&gt;
&lt;p&gt;When you look at your PR, it will look like a lot of code has been added. However, if you look closely at the Git history of those files, you will see that the history has been preserved from the original repository. You can remove the temporary &lt;code&gt;project2&lt;/code&gt; remote once you no longer need it (&lt;code&gt;git remote remove project2&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is still one of the simplest ways to combine two codebases without throwing away history. Use it when consolidating services or folding a spike repo into the main project; open a PR so reviewers can see the merge conflicts and folder layout before it lands on the default branch.&lt;/p&gt;
&lt;h3 id="related-on-this-blog"&gt;Related on this blog&lt;a class="anchor ms-1" href="#related-on-this-blog" aria-label="Permalink: Related on this blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once the histories live in one repo, automated promotion helps: see &lt;a href="https://blog-test.funkysi1701.com/posts/2024/automatic-pull-requests/"&gt;automatic pull requests&lt;/a&gt;
for GitHub Actions and Azure DevOps patterns, and &lt;a href="https://blog-test.funkysi1701.com/posts/2022/using-github-actions/"&gt;using GitHub Actions&lt;/a&gt;
if you are wiring CI around the merge.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want to get a monthly email with all my latest articles, please sign up for my &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. If you have any questions or comments, please feel free to reach out or leave a comment below.&lt;/p&gt;</description></item><item><title>The Pragmatic Programmer</title><link>https://blog-test.funkysi1701.com/posts/2025/pragmatic-programmer/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 24 Feb 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/pragmatic-programmer/</guid><category term="PragmaticProgrammer">PragmaticProgrammer</category><category term="BookReview">BookReview</category><category term="Programming">Programming</category><category term="SoftwareDevelopment">SoftwareDevelopment</category><category term="BestPractices">BestPractices</category><category term="Tech">Tech</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/tpp.jpg"/><description>&lt;p&gt;I have been reading &lt;a href="https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/" target="_blank" rel="noopener noreferrer"&gt;The Pragmatic Programmer&lt;/a&gt;
and I have to say it is a fantastic book. It is full of great advice and tips for programmers. I highly recommend it to anyone who is a programmer at any level.&lt;/p&gt;
&lt;p&gt;Lots of the advice is common sense and things I already do, but there are also lots of things I know in the back of my mind that I should be doing. So reading it has been a great reminder of those things.&lt;/p&gt;
&lt;p&gt;Here is the complete list of tips that can be found in the book (I am reading the 20th anniversary edition, so these might be slightly different if you are looking at the original edition):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Care About Your Craft&lt;/li&gt;
&lt;li&gt;Think! About Your Work&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="a-pragmatic-philosophy"&gt;A Pragmatic Philosophy&lt;a class="anchor ms-1" href="#a-pragmatic-philosophy" aria-label="Permalink: A Pragmatic Philosophy"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="3"&gt;
&lt;li&gt;You Have Agency&lt;/li&gt;
&lt;li&gt;Provide Options, Don’t Make Lame Excuses&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2015/pragmatic-programmer-broken-windows/"&gt;Don’t Live with Broken Windows&lt;/a&gt;
(I blogged about this in 2015)&lt;/li&gt;
&lt;li&gt;Be a Catalyst for Change&lt;/li&gt;
&lt;li&gt;Remember the Big Picture&lt;/li&gt;
&lt;li&gt;Make Quality a Requirements Issue&lt;/li&gt;
&lt;li&gt;Invest Regularly in Your Knowledge Portfolio&lt;/li&gt;
&lt;li&gt;Critically Analyze What You Read and Hear&lt;/li&gt;
&lt;li&gt;English is Just Another Programming Language&lt;/li&gt;
&lt;li&gt;It’s Both What You Say and the Way You Say It&lt;/li&gt;
&lt;li&gt;Build Documentation In, Don’t Bolt It On&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="a-pragmatic-approach"&gt;A Pragmatic Approach&lt;a class="anchor ms-1" href="#a-pragmatic-approach" aria-label="Permalink: A Pragmatic Approach"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="14"&gt;
&lt;li&gt;Good Design Is Easier to Change Than Bad Design&lt;/li&gt;
&lt;li&gt;DRY - Don’t Repeat Yourself&lt;/li&gt;
&lt;li&gt;Make It Easy to Reuse&lt;/li&gt;
&lt;li&gt;Eliminate Effects Between Unrelated Things&lt;/li&gt;
&lt;li&gt;There Are No Final Decisions&lt;/li&gt;
&lt;li&gt;Forgo Following Fads&lt;/li&gt;
&lt;li&gt;Use Tracer Bullets to Find the Target&lt;/li&gt;
&lt;li&gt;Prototype to Learn&lt;/li&gt;
&lt;li&gt;Program Close to the Problem Domain&lt;/li&gt;
&lt;li&gt;Estimate to Avoid Surprises&lt;/li&gt;
&lt;li&gt;Iterate the Schedule with the Code&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-basic-tools"&gt;The Basic Tools&lt;a class="anchor ms-1" href="#the-basic-tools" aria-label="Permalink: The Basic Tools"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="25"&gt;
&lt;li&gt;Keep Knowledge in Plain Text&lt;/li&gt;
&lt;li&gt;Use the Power of Command Shells&lt;/li&gt;
&lt;li&gt;Achieve Editor Fluency&lt;/li&gt;
&lt;li&gt;Always Use Version Control&lt;/li&gt;
&lt;li&gt;Fix the Problem, Not the Blame&lt;/li&gt;
&lt;li&gt;Don’t Panic&lt;/li&gt;
&lt;li&gt;Failing Test Before Fixing Code&lt;/li&gt;
&lt;li&gt;Read the Damn Error Message&lt;/li&gt;
&lt;li&gt;&amp;ldquo;select&amp;rdquo; Isn&amp;rsquo;t Broken&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t Assume It - Prove it&lt;/li&gt;
&lt;li&gt;Learn a Text Manipulation Language&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="pragmatic-paranoia"&gt;Pragmatic Paranoia&lt;a class="anchor ms-1" href="#pragmatic-paranoia" aria-label="Permalink: Pragmatic Paranoia"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="36"&gt;
&lt;li&gt;You Can&amp;rsquo;t Write Perfect Software&lt;/li&gt;
&lt;li&gt;Design with Contracts&lt;/li&gt;
&lt;li&gt;Crash Early&lt;/li&gt;
&lt;li&gt;Use Assertions to Prevent the Impossible&lt;/li&gt;
&lt;li&gt;Finish What You Start&lt;/li&gt;
&lt;li&gt;Act Locally&lt;/li&gt;
&lt;li&gt;Take Small Steps - Always&lt;/li&gt;
&lt;li&gt;Avoid Fortune Telling&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="bend-or-break"&gt;Bend, or Break&lt;a class="anchor ms-1" href="#bend-or-break" aria-label="Permalink: Bend, or Break"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="44"&gt;
&lt;li&gt;Decoupled Code is Easy to Change&lt;/li&gt;
&lt;li&gt;Tell, Don&amp;rsquo;t Ask&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t Chain Method Calls&lt;/li&gt;
&lt;li&gt;Avoid Global Data&lt;/li&gt;
&lt;li&gt;If it&amp;rsquo;s Important Enough to be Global, Wrap It in an API&lt;/li&gt;
&lt;li&gt;Programming is About Code, But Programs Are About Data&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t Hoard State; Pass It Around&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t Pay Inheritance Tax&lt;/li&gt;
&lt;li&gt;Prefer Interfaces to Express Polymorphism&lt;/li&gt;
&lt;li&gt;Delegate to Services: Has-A Trumps Is-A&lt;/li&gt;
&lt;li&gt;Use Mixins to Share Functionality&lt;/li&gt;
&lt;li&gt;Parameterize Your App Using External Configuration&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="concurrency"&gt;Concurrency&lt;a class="anchor ms-1" href="#concurrency" aria-label="Permalink: Concurrency"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="56"&gt;
&lt;li&gt;Analyze Workflow to Improve Concurrency&lt;/li&gt;
&lt;li&gt;Shared State is Incorrect State&lt;/li&gt;
&lt;li&gt;Random Failures Are Often Concurrency Issues&lt;/li&gt;
&lt;li&gt;Use Actors for Concurrency Without Shared State&lt;/li&gt;
&lt;li&gt;Use Blackboards to Coordinate Workflow&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="while-you-are-coding"&gt;While You Are Coding&lt;a class="anchor ms-1" href="#while-you-are-coding" aria-label="Permalink: While You Are Coding"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="61"&gt;
&lt;li&gt;Listen to Your Inner Lizard&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t Program by Coincidence&lt;/li&gt;
&lt;li&gt;Estimate the Order of Your Algorithms&lt;/li&gt;
&lt;li&gt;Test Your Estimates&lt;/li&gt;
&lt;li&gt;Refactor Early, Refactor Often&lt;/li&gt;
&lt;li&gt;Testing is Not About Finding Bugs&lt;/li&gt;
&lt;li&gt;A Test is the First User of Your Code&lt;/li&gt;
&lt;li&gt;Build End-to-End, Not Top-Down or Bottom-Up&lt;/li&gt;
&lt;li&gt;Design To Test&lt;/li&gt;
&lt;li&gt;Test Your Software, or Your Users Will&lt;/li&gt;
&lt;li&gt;Use Property-Based Tests to Validate your Assumptions&lt;/li&gt;
&lt;li&gt;Keep it Simple and Minimize Attack Surfaces&lt;/li&gt;
&lt;li&gt;Apply Security Patches Quickly&lt;/li&gt;
&lt;li&gt;Name well; Rename When Needed&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="before-the-project"&gt;Before the Project&lt;a class="anchor ms-1" href="#before-the-project" aria-label="Permalink: Before the Project"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="75"&gt;
&lt;li&gt;No One Knows Exactly What They Want&lt;/li&gt;
&lt;li&gt;Programmers Help People Understand What They Want&lt;/li&gt;
&lt;li&gt;Requirements are Learned in a Feedback Loop&lt;/li&gt;
&lt;li&gt;Work with a User to Think Like a User&lt;/li&gt;
&lt;li&gt;Policy is Metadata&lt;/li&gt;
&lt;li&gt;Use a Project Glossary&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t Think Outside the Box - Find the Box&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t Go into the Code Alone&lt;/li&gt;
&lt;li&gt;Agile is Not a Noun; Agile is How You Do Things&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="pragmatic-projects"&gt;Pragmatic Projects&lt;a class="anchor ms-1" href="#pragmatic-projects" aria-label="Permalink: Pragmatic Projects"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="84"&gt;
&lt;li&gt;Maintain Small, Stable Teams&lt;/li&gt;
&lt;li&gt;Schedule It to Make it Happen&lt;/li&gt;
&lt;li&gt;Organize Fully Functional Teams&lt;/li&gt;
&lt;li&gt;Do What Works, Not What&amp;rsquo;s Fashionable&lt;/li&gt;
&lt;li&gt;Deliver When Users Need It&lt;/li&gt;
&lt;li&gt;Use Version Control to Drive Builds, Tests and Releases&lt;/li&gt;
&lt;li&gt;Test Early, Test Often, Test Automatically&lt;/li&gt;
&lt;li&gt;Coding Ain&amp;rsquo;t Done &amp;lsquo;Til All the Tests Run&lt;/li&gt;
&lt;li&gt;Use Saboteurs to Test Your Testing&lt;/li&gt;
&lt;li&gt;Test State Coverage, Not Code Coverage&lt;/li&gt;
&lt;li&gt;Find Bugs Once&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t use Manual Procedures&lt;/li&gt;
&lt;li&gt;Delight Users, Don&amp;rsquo;t Just Deliver Code&lt;/li&gt;
&lt;li&gt;Sign your Work&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="professional-ethics"&gt;Professional Ethics&lt;a class="anchor ms-1" href="#professional-ethics" aria-label="Permalink: Professional Ethics"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol start="98"&gt;
&lt;li&gt;First, Do No Harm&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t Enable Scumbags&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s Your Life&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Understand and handle .NET exceptions</title><link>https://blog-test.funkysi1701.com/posts/2025/exceptions/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 17 Feb 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/exceptions/</guid><category term="Exceptions">Exceptions</category><category term="DotNet">DotNet</category><category term="ErrorHandling">ErrorHandling</category><category term="Programming">Programming</category><category term="Development">Development</category><category term="Tech">Tech</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/exceptions.png"/><description>&lt;p&gt;While at &lt;a href="https://blog-test.funkysi1701.com/posts/2025/volunteering-at-ndc/"&gt;NDC London&lt;/a&gt;
I heard a great talk by &lt;a href="https://mattburke.dev/talks/youre-doing-exceptions-wrong/" target="_blank" rel="noopener noreferrer"&gt;Matt Burke&lt;/a&gt;
about exceptions. I will share some of the points here.&lt;/p&gt;
&lt;p&gt;The talk was based in part on the blog post &lt;a href="https://ericlippert.com/2008/09/10/vexing-exceptions/" target="_blank" rel="noopener noreferrer"&gt;Vexing Exceptions&lt;/a&gt;
by Eric Lippert.&lt;/p&gt;
&lt;p&gt;It defined four types of exceptions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fatal Exceptions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Boneheaded Exceptions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vexing Exceptions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exogenous Exceptions&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="fatal-exceptions"&gt;Fatal Exceptions&lt;a class="anchor ms-1" href="#fatal-exceptions" aria-label="Permalink: Fatal Exceptions"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are exceptions that are thrown when the application is in an unrecoverable state. Examples of these are OutOfMemoryException and StackOverflowException. Don&amp;rsquo;t try and catch these kind of exceptions, just let the application crash.&lt;/p&gt;
&lt;h2 id="boneheaded-exceptions"&gt;Boneheaded Exceptions&lt;a class="anchor ms-1" href="#boneheaded-exceptions" aria-label="Permalink: Boneheaded Exceptions"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are exceptions that are caused by a bug in the code. These are the easiest to fix, as you just need to fix the bug. Examples of these are NullReferenceException and IndexOutOfRangeException. Boneheaded exceptions are a gift and it is the code telling you, that you have a bug to fix. Do throw these kind of exceptions, when someone messes up. They can be especially useful when someone else is consuming your API, you can throw an exception with a message that tells them what they did wrong.&lt;/p&gt;
&lt;h2 id="vexing-exceptions"&gt;Vexing Exceptions&lt;a class="anchor ms-1" href="#vexing-exceptions" aria-label="Permalink: Vexing Exceptions"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are exceptions that are thrown by the framework, and are hard to avoid. Examples of these are FormatException and InvalidOperationException. These are the hardest to fix, as they are thrown by the framework. You can&amp;rsquo;t fix the framework, so you have to work around them. You can&amp;rsquo;t avoid them, so you have to catch them. You can&amp;rsquo;t ignore them, so you have to handle them. You can&amp;rsquo;t fix them, so you have to work around them.&lt;/p&gt;
&lt;p&gt;One example of this is the int.Parse() method, it will throw a FormatException if the string is not a valid integer. You can&amp;rsquo;t avoid this, so you have to catch it. Of course a better way to do this is to use int.TryParse() which will return a boolean if the parse was successful.&lt;/p&gt;
&lt;h2 id="exogenous-exceptions"&gt;Exogenous Exceptions&lt;a class="anchor ms-1" href="#exogenous-exceptions" aria-label="Permalink: Exogenous Exceptions"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are exceptions that are thrown by external systems. Examples of these are IOException and SocketException. These are the hardest to fix, as they are thrown by external systems. You can&amp;rsquo;t fix the external system, so you have to work around them.&lt;/p&gt;
&lt;p&gt;A recent example is concurrency problems, if you are processing data in a database and other systems could update it at the same time, you could get a concurrency exception. The data you have in memory might not reflect the real state of that data. You can&amp;rsquo;t avoid this, so you have to catch it. You can&amp;rsquo;t ignore it, so you have to handle it.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Do something that could throw an exception&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (Exception ex)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Log the exception&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Log.Error(ex);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; ex; &lt;span style="color:#75715e"&gt;// Bad resets the stack trace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// Good keeps the stack trace &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also don&amp;rsquo;t hide Exogenous Exceptions, if you catch an exception and don&amp;rsquo;t rethrow it, you are hiding the exception from the caller. I have seen code that uses the mediator pattern, it will call a method and not return to the original caller that something went wrong. This is bad, as the original caller needs to know that something went wrong.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want to get a monthly email with all my latest articles, please sign up for my &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. If you have any questions or comments, please feel free to reach out or leave a comment below.&lt;/p&gt;</description></item><item><title>What is new with C#</title><link>https://blog-test.funkysi1701.com/posts/2025/whats-new-csharp/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 10 Feb 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/whats-new-csharp/</guid><category term="C-Sharp">C-Sharp</category><category term="Programming">Programming</category><category term="DotNet">DotNet</category><category term="LanguageFeatures">LanguageFeatures</category><category term="Development">Development</category><category term="Tech">Tech</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/mads-csharp.jpg"/><description>&lt;p&gt;I was lucky enough to hear Mads Torgersen (The Lead Designer of the C# language) speak at &lt;a href="https://blog-test.funkysi1701.com/posts/2025/volunteering-at-ndc/"&gt;NDC London&lt;/a&gt;
about some of the plans the team has for the next version of C#. Many of these new features are in the preview stage, and can be enabled by using the c# preview flag in your csproj file. The C# team welcomes feedback on the different use cases for new feature, especially during these early previews. As this is a preview of new language features, don&amp;rsquo;t blame me if this all changes before it all ships in Novembers release!&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;LangVersion&amp;gt;&lt;/span&gt;preview&lt;span style="color:#f92672"&gt;&amp;lt;/LangVersion&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="dictionary-expressions"&gt;Dictionary Expressions&lt;a class="anchor ms-1" href="#dictionary-expressions" aria-label="Permalink: Dictionary Expressions"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is an extension of the existing collection expressions that we have had since C# 12, but this time for dictionaries.&lt;/p&gt;
&lt;p&gt;The syntax is going to look a bit like&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IList&amp;lt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;&amp;gt; foo = [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IDictionary&amp;lt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt; bar = [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;one&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;two&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;three&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md" target="_blank" rel="noopener noreferrer"&gt;Dictionary Expressions&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="simple-lambda-parameters-with-modifiers"&gt;Simple lambda parameters with modifiers&lt;a class="anchor ms-1" href="#simple-lambda-parameters-with-modifiers" aria-label="Permalink: Simple lambda parameters with modifiers"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WithOut w1 = (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; s) =&amp;gt; s.Length;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WithOut w2 = (s) =&amp;gt; s.Length;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WithOut w3 = (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; s, &lt;span style="color:#66d9ef"&gt;out&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i) =&amp;gt; i = s.Length;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WithOut w4 = (s, &lt;span style="color:#66d9ef"&gt;out&lt;/span&gt; i) =&amp;gt; i = s.Length;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/simple-lambda-parameters-with-modifiers.md" target="_blank" rel="noopener noreferrer"&gt;Simple lambda parameters with modifiers&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="unbound-generic-types-in-nameof"&gt;Unbound generic types in nameof&lt;a class="anchor ms-1" href="#unbound-generic-types-in-nameof" aria-label="Permalink: Unbound generic types in nameof"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; t = &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(List&amp;lt;&amp;gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; n = nameof(List&amp;lt;&amp;gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/unbound-generic-types-in-nameof.md" target="_blank" rel="noopener noreferrer"&gt;Unbound generic types in nameof&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="null-conditional-assignment"&gt;Null conditional assignment&lt;a class="anchor ms-1" href="#null-conditional-assignment" aria-label="Permalink: Null conditional assignment"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; c = C.GetOne();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c.P = &lt;span style="color:#e6db74"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c.E += () =&amp;gt; { };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c?.P = &lt;span style="color:#e6db74"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c?.E += () =&amp;gt; { };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/null-conditional-assignment.md" target="_blank" rel="noopener noreferrer"&gt;Null conditional assignment&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="partial-events-and-constructors"&gt;Partial events and constructors&lt;a class="anchor ms-1" href="#partial-events-and-constructors" aria-label="Permalink: Partial events and constructors"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Partials&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; M(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; P { &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i] { &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;partial&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;event&lt;/span&gt; Handler? E;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;partial&lt;/span&gt; Partials();
&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;&lt;a href="https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/partial-events-and-constructors.md" target="_blank" rel="noopener noreferrer"&gt;Partial events and constructors&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="field-access-in-auto-properties"&gt;Field access in auto properties&lt;a class="anchor ms-1" href="#field-access-in-auto-properties" aria-label="Permalink: Field access in auto properties"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string?&lt;/span&gt; FirstName { &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string?&lt;/span&gt; LastName { &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt; =&amp;gt; field; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; =&amp;gt; field = &lt;span style="color:#66d9ef"&gt;value&lt;/span&gt;?.Trim(); }
&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;note the field keyword is a potential breaking change if you have field variables in your code.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/field-keyword.md" target="_blank" rel="noopener noreferrer"&gt;Field access in auto properties&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This last one revealed a couple of gems of information that I found interesting. Creating a class called var can essentially disable the var keyword, and if you declare a variable called _ it can disable the discard operator. Neither of these things I would want to do in production code, but interesting that the language allows them.&lt;/p&gt;
&lt;h2 id="extensions"&gt;Extensions&lt;a class="anchor ms-1" href="#extensions" aria-label="Permalink: Extensions"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We have had extension methods for a while, but what about extension members?&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/extensions.md" target="_blank" rel="noopener noreferrer"&gt;Extension members&lt;/a&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Enumerable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// New extension declaration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; extension(IEnumerable source) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Classic extension method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; IEnumerable&amp;lt;TResult&amp;gt; Cast&amp;lt;TResult&amp;gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; IEnumerable source) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Non-extension member&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;&amp;gt; Range(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; start, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; count) { ... }
&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;This was a fascinating look at what is coming up for C#, and it will be interesting to see how these new ways of writing code will get adopted.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want to get a monthly email with all my latest articles, please sign up for my &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. If you have any questions or comments, please feel free to reach out or leave a comment below.&lt;/p&gt;</description></item><item><title>Volunteering at NDC London</title><link>https://blog-test.funkysi1701.com/posts/2025/volunteering-at-ndc/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 03 Feb 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/volunteering-at-ndc/</guid><category term="NDCLondon">NDCLondon</category><category term="Volunteering">Volunteering</category><category term="Conference">Conference</category><category term="DotNet">DotNet</category><category term="TechEvents">TechEvents</category><category term="Networking">Networking</category><category term="SoftwareDevelopment">SoftwareDevelopment</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/ndc-simon.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="The NDC Volunteers" src="https://blog-test.funkysi1701.com/images/ndc-crew.jpg" loading="lazy"
width="2048" height="865"
/&gt;
&lt;/p&gt;
&lt;p&gt;I have just come home from volunteering at NDC London. It was a great experience and I learned a lot. I met some great people and had a lot of fun. I can&amp;rsquo;t wait to go back next year.&lt;/p&gt;
&lt;p&gt;You may have heard of &lt;a href="https://ndclondon.com/" target="_blank" rel="noopener noreferrer"&gt;NDC London&lt;/a&gt;
before. It is a conference for software developers. It is held in London every year and attracts people from all over the world. The conference covers a wide range of topics, with a strong focus on .NET. I have heard about the conference for years and always wanted to go, but with ticket prices in the thousands, it was out of reach for me.&lt;/p&gt;
&lt;p&gt;Late last year, I saw a contact on social media mention that &lt;a href="https://ndclondon.com/volunteer" target="_blank" rel="noopener noreferrer"&gt;volunteering at NDC&lt;/a&gt;
was a good way to go to the conference for free. I had heard that this was an option before, but hadn&amp;rsquo;t acted upon it. So I sent a quick email to the conference organizers. I didn&amp;rsquo;t expect I would get on the team, but they emailed back and said I was on the team, and asked what was my t-shirt size. I was so excited!&lt;/p&gt;
&lt;p&gt;The event is held at the &lt;a href="https://qeiicentre.london/" target="_blank" rel="noopener noreferrer"&gt;Queen Elizabeth II Centre&lt;/a&gt;
, which is a great venue, right next to Big Ben and Westminster Abbey. The conference is spread over a whole week, with 2 days of workshops and 3 days of talks. Volunteers are only needed for the 3 days of talks, however, there was an intro meeting the day before.&lt;/p&gt;
&lt;p&gt;As a volunteer, you don&amp;rsquo;t get paid, so I needed to arrange my own transport to London and accommodation. It being London, I knew the tube network was a quick and easy way to get around, so I could search for a reasonably priced hotel that was near the venue.&lt;/p&gt;
&lt;p&gt;The intro meeting was on Tuesday evening, at 5.30 pm. I arrived a bit early and unfortunately, I wasn&amp;rsquo;t very clear about why I was there so I was told to wait and the meetup would go upstairs soon. The London .NET user group was having a session at 5 pm with Mads Torgersen (the C# language designer), but luckily I double-checked and got to wait with the right people. However, this was not a bad thing, as I got to see some of the .NET team walk past, like Steve Sanderson and of course Mads Torgersen who was going to the meetup.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="London view" src="https://blog-test.funkysi1701.com/images/london.jpg" loading="lazy"
width="2000" height="900"
/&gt;
&lt;/p&gt;
&lt;p&gt;Once the intro meeting started, we unboxed the hoodies that every attendee was given. These ranged in size from XS to XXXL, we also learned how the registration process worked. Scan a QR code, print off the ticket, stick it to the lanyard, and issue it to the attendee. I also found out that there was a decent Yorkshire contingent, some I had met from York and Leeds user groups. We had a tour of the venue, the conference was on floors 3, 4, and 5. The top floor had a great view of Big Ben and Westminster Abbey. We were also issued our own T-shirt and hoodies, which were purple and said NDC Crew on them along with our lanyard passes.&lt;/p&gt;
&lt;p&gt;It was an early morning, we needed to be at the venue for 7 am, ready to welcome 900+ people to the conference when the doors opened at 8 am. I helped man the hoodies, handing out XXL to any attendees who wanted them. There was a steady stream of people registering, however, I didn&amp;rsquo;t feel overwhelmed. By the time we had finished at registration, the keynote with Scott Hanselman was about halfway through, so I went to get a coffee and some breakfast and had a look at the schedule for the day. I was assigned to help out with the afternoon sessions so I was free to attend any sessions I liked in the morning.&lt;/p&gt;
&lt;p&gt;For my afternoon duties, I needed to report back when the speaker had arrived and count up the number of green/amber/red cards for the session. At NDC feedback for the different speakers is submitted by the attendees by putting cards of different colours in a box. Green for good, amber for ok, red for bad. Throughout the different talks I attended there was always a good proportion of green cards, indicating the high quality of the speakers at NDC.&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/ndc-simon.jpg" alt="The NDC Volunteers" width="250px" style="float:left;padding-right: 15px; " /&gt;
&lt;p&gt;Wearing a purple NDC Crew hoodie, gave me a certain amount of confidence, I walked among many of the sponsors and chatted to a few. Elastic Search had a stall, and I mentioned my recent experience at work with them. At some conferences, I can feel a bit out of place, but at NDC being a volunteer, I had an automatic group of friends to chat to, the other volunteers, and this also helped me speak with one or two of the speakers. I enjoyed saying hello to Richard Campbell, who I had listened to on the .Net Rocks and RunAs Radio podcasts for years. I told him he had sent me a mug, and he mentioned it was a collector&amp;rsquo;s item now.&lt;/p&gt;
&lt;p&gt;At the end of the first day, I was invited to the speaker dinner, which was a great experience. I got to chat with some of the other volunteers. I had a great time and it was free food and drink so I can&amp;rsquo;t complain.&lt;/p&gt;
&lt;p&gt;While I was volunteering, I was often hanging out with the other volunteers. We had a great time, and I made some new friends. We had a lot of fun, and I learned a lot, which I hope to blog about soon. I can&amp;rsquo;t wait to go back next year.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want to get a monthly email with all my latest articles, please sign up for my &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. If you have any questions or comments, please feel free to reach out or leave a comment below.&lt;/p&gt;</description></item><item><title>Set up Grafana for .NET with Docker</title><link>https://blog-test.funkysi1701.com/posts/2025/setting-up-grafana/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 27 Jan 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/setting-up-grafana/</guid><category term="Grafana">Grafana</category><category term="Monitoring">Monitoring</category><category term="Analytics">Analytics</category><category term="Docker">Docker</category><category term="Prometheus">Prometheus</category><category term="DotNet">DotNet</category><category term="DevOps">DevOps</category><category term="Metrics">Metrics</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/grafana-dashboard.png"/><description>&lt;p&gt;Grafana is an open-source analytics and monitoring platform that lets you query, visualise, and alert on metrics. It pairs well with Prometheus for scraping application endpoints. This post walks through a Docker Compose stack that monitors a simple .NET API.&lt;/p&gt;
&lt;h2 id="setting-up-grafana"&gt;Setting up Grafana&lt;a class="anchor ms-1" href="#setting-up-grafana" aria-label="Permalink: Setting up Grafana"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To visualise metrics data, we need a few components. The .NET application exposes a &lt;code&gt;/metrics&lt;/code&gt; endpoint. Prometheus scrapes it on an interval and stores the samples. Grafana then queries Prometheus and renders dashboards.&lt;/p&gt;
&lt;h3 id="docker-compose-file"&gt;Docker Compose File&lt;a class="anchor ms-1" href="#docker-compose-file" aria-label="Permalink: Docker Compose File"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Start with a Compose file for Prometheus and Grafana. Pin image tags so rebuilds stay reproducible (bump them when you deliberately upgrade):&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;prometheus&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;prom/prometheus:v3.4.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;5431&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;9090&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;./prometheus/:/etc/prometheus/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;prometheus:/prometheus &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;grafana&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;grafana/grafana:11.6.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;expose&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;3000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;grafana:/var/lib/grafana&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;prometheus&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;grafana&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This brings up Grafana and Prometheus, maps ports, and mounts config/data volumes.&lt;/p&gt;
&lt;h3 id="prometheus-configuration"&gt;Prometheus Configuration&lt;a class="anchor ms-1" href="#prometheus-configuration" aria-label="Permalink: Prometheus Configuration"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next, create a &lt;strong&gt;prometheus.yml&lt;/strong&gt; file to configure Prometheus:&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;global&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;scrape_interval&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;15s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;evaluation_interval&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;15s &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;scrape_configs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;job_name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;api&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;scheme&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;https&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tls_config&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;insecure_skip_verify&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;scrape_interval&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;scrape_timeout&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;static_configs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;targets&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#39;api.example.com:443&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This configures how often the &lt;code&gt;/metrics&lt;/code&gt; endpoint should be scraped. By default Prometheus expects something like &lt;code&gt;http://api.example.com/metrics&lt;/code&gt;. Because my API ran under HTTPS I set &lt;code&gt;scheme&lt;/code&gt; to &lt;code&gt;https&lt;/code&gt; and skipped TLS verification in this lab setup. &lt;code&gt;scrape_interval&lt;/code&gt; is how often the endpoint is scraped; if &lt;code&gt;scrape_timeout&lt;/code&gt; is omitted the global value is used.&lt;/p&gt;
&lt;p&gt;More information about configuring Prometheus can be found &lt;a href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
.&lt;/p&gt;
&lt;h3 id="grafana-config"&gt;Grafana Config&lt;a class="anchor ms-1" href="#grafana-config" aria-label="Permalink: Grafana Config"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can now log into Grafana on &lt;a href="http://localhost:3000" target="_blank" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;
with the default username and password of &lt;code&gt;admin&lt;/code&gt;/&lt;code&gt;admin&lt;/code&gt;. You will be prompted to change the password. Add a Prometheus data source next. Prometheus is published on the host as &lt;a href="http://localhost:5431" target="_blank" rel="noopener noreferrer"&gt;http://localhost:5431&lt;/a&gt;
, but from another container you usually cannot use &lt;code&gt;localhost&lt;/code&gt; for a sibling service.&lt;/p&gt;
&lt;p&gt;If Grafana needs to reach Prometheus on the &lt;strong&gt;host&lt;/strong&gt; (for example when Prometheus is published only to the host network), use &lt;strong&gt;host.docker.internal&lt;/strong&gt; (Docker Desktop and many Linux setups with the host-gateway mapping): &lt;a href="http://host.docker.internal:5431" target="_blank" rel="noopener noreferrer"&gt;http://host.docker.internal:5431&lt;/a&gt;
. Prefer the Compose service name (&lt;code&gt;http://prometheus:9090&lt;/code&gt;) when both services share the same Compose network.&lt;/p&gt;
&lt;h3 id="dashboard"&gt;Dashboard&lt;a class="anchor ms-1" href="#dashboard" aria-label="Permalink: Dashboard"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The next thing we need to do is build a dashboard — the .NET team has done much of the hard work. They published a &lt;a href="https://devblogs.microsoft.com/dotnet/introducing-aspnetcore-metrics-and-grafana-dashboards-in-dotnet-8/" target="_blank" rel="noopener noreferrer"&gt;Grafana dashboard&lt;/a&gt;
you can import.&lt;/p&gt;
&lt;p&gt;You can also build panels yourself in the Grafana UI (graphs, gauges, and other visualisations).&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Dashboard" src="https://blog-test.funkysi1701.com/images/2025/dashboard-screenshot.png" loading="lazy"
width="2471" height="1238"
/&gt;
&lt;/p&gt;
&lt;h2 id="metrics-endpoint"&gt;Metrics endpoint&lt;a class="anchor ms-1" href="#metrics-endpoint" aria-label="Permalink: Metrics endpoint"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If your .NET application is using .NET Aspire, this &lt;code&gt;/metrics&lt;/code&gt; endpoint is often already set up for you. Look in &lt;code&gt;Extensions.cs&lt;/code&gt; in your ServiceDefaults project for something like the following (you need the NuGet package &lt;code&gt;OpenTelemetry.Exporter.Prometheus.AspNetCore&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; WebApplication MapDefaultEndpoints(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; WebApplication app)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// The following line enables the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app.MapPrometheusScrapingEndpoint();
&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;If you are not using .NET Aspire, you can add &lt;code&gt;app.MapPrometheusScrapingEndpoint()&lt;/code&gt; to your &lt;code&gt;Program.cs&lt;/code&gt; file (with the same package referenced).&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With Compose, Prometheus, and Grafana in place you can scrape a .NET &lt;code&gt;/metrics&lt;/code&gt; endpoint and watch live dashboards — useful for latency, exceptions, and ASP.NET Core built-in meters. Happy monitoring!&lt;/p&gt;
&lt;h3 id="related-on-this-blog"&gt;Related on this blog&lt;a class="anchor ms-1" href="#related-on-this-blog" aria-label="Permalink: Related on this blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Prefer classic host and service checks? Try &lt;a href="https://blog-test.funkysi1701.com/posts/2025/monitoring-with-nagios-docker/"&gt;monitoring with Nagios in Docker&lt;/a&gt;
. If Aspire already wires OpenTelemetry for you, &lt;a href="https://blog-test.funkysi1701.com/posts/2024/aspire/"&gt;getting started with Aspire&lt;/a&gt;
is a useful companion to the metrics endpoint notes above.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want to get a monthly email with all my latest articles, please sign up to my &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. If you have any questions or comments, please feel free to reach out or leave a comment below.&lt;/p&gt;</description></item><item><title>Adding Elasticsearch with .Net Aspire</title><link>https://blog-test.funkysi1701.com/posts/2025/adding-elasticsearch-with-aspire/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 20 Jan 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/adding-elasticsearch-with-aspire/</guid><category term="Elasticsearch">Elasticsearch</category><category term="DotNet">DotNet</category><category term="Aspire">Aspire</category><category term="Search">Search</category><category term="Indexing">Indexing</category><category term="Development">Development</category><category term="Tech">Tech</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/elastic-search.jpg"/><description>&lt;p&gt;A few weeks ago I talked about &lt;a href="https://blog-test.funkysi1701.com/posts/2024/aspire/"&gt;.Net Aspire&lt;/a&gt;
, well lets take a look at how we can use it with Elasticsearch. Elastic search is a powerful search engine that can be used to index and search data. It is built on top of Lucene and provides a powerful way to search through your data.&lt;/p&gt;
&lt;p&gt;Aspire allows dependencies like elasticsearch to be added to a project programmatically. Lets look at how this can work.&lt;/p&gt;
&lt;p&gt;Add this nuget package to your AppHost project (as of writing this is a preview package):&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Aspire.Hosting.Elasticsearch&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Version=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;9.0.0-preview.5.24551.3&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In your AppHost project, add the following code to your &lt;code&gt;Program.cs&lt;/code&gt; file:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; elasticsearch = builder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddElasticsearch(&lt;span style="color:#e6db74"&gt;&amp;#34;elasticsearch&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if you run your project it will add an elasticsearch containter to your project. A common way to administer elasticsearch is to use Kibana. You can add this to your project by adding the following code to your &lt;code&gt;Program.cs&lt;/code&gt; file:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; kibana = builder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddContainer(&lt;span style="color:#e6db74"&gt;&amp;#34;kibana&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;kibana&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;8.15.3&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// Add Kibana from the image kibana, and tag 8.15.3 and give it a name kibana&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithReference(elasticsearch) &lt;span style="color:#75715e"&gt;// Add a reference to the elasticsearch container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithEndpoint(&lt;span style="color:#ae81ff"&gt;5601&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5601&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// Expose a port so you can connect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if you run your project you will have an elasticsearch and kibana container running. You can access kibana by going to &lt;code&gt;http://localhost:5601&lt;/code&gt;, and elasticsearch by going to &lt;code&gt;http://localhost:9200&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="troubleshooting-kibana"&gt;Troubleshooting Kibana&lt;a class="anchor ms-1" href="#troubleshooting-kibana" aria-label="Permalink: Troubleshooting Kibana"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;However when I do that I get the error &lt;code&gt;Kibana server is not ready yet&lt;/code&gt;. Looking at the kibana container logs, I see the following error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-log" data-lang="log"&gt;2025-01-19T21:42:13 [2025-01-19T21:42:13.558+00:00][WARN ][plugins.security.config] Generating a random key for xpack.security.encryptionKey. To prevent sessions from being invalidated on restart, please set xpack.security.encryptionKey in the kibana.yml or use the bin/kibana-encryption-keys command.
Unable to retrieve version information from Elasticsearch nodes. security_exception
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is due to the security settings in Elasticsearch. To fix this, you can turn off this security feature by enabling an environment variable:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; elasticsearch = builder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddElasticsearch(&lt;span style="color:#e6db74"&gt;&amp;#34;elasticsearch&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithEnvironment(&lt;span style="color:#e6db74"&gt;&amp;#34;xpack.security.enabled&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;false&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As Aspire is only running locally, this is fine, but in a production environment, you would want to secure your Elasticsearch and Kibana instances.&lt;/p&gt;
&lt;h2 id="using-elasticsearch-in-your-project"&gt;Using Elasticsearch in Your Project&lt;a class="anchor ms-1" href="#using-elasticsearch-in-your-project" aria-label="Permalink: Using Elasticsearch in Your Project"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you have Elasticsearch added to your project, how can you use it? In the .NET project that wants to connect and interact with Elasticsearch, you can add the following NuGet package:&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Aspire.Elastic.Clients.Elasticsearch (version 9.0.0-preview.5.24551.3 as of writing)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;Program.cs&lt;/code&gt; file of your .NET project you can add the following code:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.AddElasticsearchClient(&lt;span style="color:#e6db74"&gt;&amp;#34;elasticsearch&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No need to specify any complex connection strings or settings, Aspire will handle all of that for you.&lt;/p&gt;
&lt;p&gt;This is pretty much all of the Aspire specific code you need, but lets have a quick look at indexing some data and returning it with a search. Elastic Search has extensive &lt;a href="https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/examples.html" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;
on how to do this with the dotnet libraries.&lt;/p&gt;
&lt;p&gt;To index some data you can use the following code:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; _client.Indices.CreateAsync(&lt;span style="color:#e6db74"&gt;&amp;#34;searchindex&amp;#34;&lt;/span&gt;, cancellationToken); &lt;span style="color:#75715e"&gt;// Create an index called searchindex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; documents = context.Episode.ToList(); &lt;span style="color:#75715e"&gt;// Get the documents you want to index from Entity Framework or any other source&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; _client.IndexManyAsync(documents, index: &lt;span style="color:#e6db74"&gt;&amp;#34;searchindex&amp;#34;&lt;/span&gt;, cancellationToken); &lt;span style="color:#75715e"&gt;// Index the documents into the searchindex index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ElasticsearchClient can be injected in via dependency injection, again no need to specify any connection strings or settings.&lt;/p&gt;
&lt;p&gt;To search for data you can use the following code:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Create a search request with a wildcard query which searches in the title field of your indexed documents.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; searchRequest = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ESSearchRequest(&lt;span style="color:#e6db74"&gt;&amp;#34;searchindex&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; From = &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; Size = &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Query = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; WildcardQuery(&lt;span style="color:#e6db74"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;) { Value = &lt;span style="color:#e6db74"&gt;$&amp;#34;*{SearchQuery}*&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Execute the search request and get the response.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; response = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; _client.SearchAsync&amp;lt;Episode&amp;gt;(searchRequest, cancellationToken);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (response.IsValidResponse)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Return the documents from the response.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; response.Documents.ToList();
&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;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By following these steps, you can successfully integrate Elasticsearch and Kibana into your .NET Aspire project. This setup allows you to leverage powerful search and analytics capabilities in your application. Remember to secure your instances in a production environment to ensure data safety.&lt;/p&gt;</description></item><item><title>NuGet central package management</title><link>https://blog-test.funkysi1701.com/posts/2025/nuget-central-package-management/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 13 Jan 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/nuget-central-package-management/</guid><category term="NuGet">NuGet</category><category term="PackageManagement">PackageManagement</category><category term="DotNet">DotNet</category><category term="Development">Development</category><category term="DevOps">DevOps</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/central-package-management-with-nuget.png"/><description>&lt;p&gt;Managing dependencies in .NET projects can become complex, especially when dealing with multiple projects that share common packages. NuGet Central Package Management (CPM) is a feature that simplifies this process by allowing you to manage package versions centrally.&lt;/p&gt;
&lt;h2 id="what-is-nuget-central-package-management"&gt;What is NuGet Central Package Management?&lt;a class="anchor ms-1" href="#what-is-nuget-central-package-management" aria-label="Permalink: What is NuGet Central Package Management?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;NuGet Central Package Management allows you to define and manage package versions in a central location, rather than specifying them individually in each project file. This approach ensures consistency across projects and simplifies the process of updating package versions.&lt;/p&gt;
&lt;h2 id="setting-up-central-package-management"&gt;Setting Up Central Package Management&lt;a class="anchor ms-1" href="#setting-up-central-package-management" aria-label="Permalink: Setting Up Central Package Management"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To get started with Central Package Management, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a Directory.Packages.props File&lt;/strong&gt;: This file will contain the central package version definitions. Create this file in the root directory of your solution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Define Package Versions&lt;/strong&gt;: In the &lt;code&gt;Directory.Packages.props&lt;/code&gt; file, define the package versions you want to manage centrally. For example:&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;Project&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;ManagePackageVersionsCentrally&amp;gt;&lt;/span&gt;true&lt;span style="color:#f92672"&gt;&amp;lt;/ManagePackageVersionsCentrally&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PackageVersion&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Newtonsoft.Json&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Version=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;13.0.1&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PackageVersion&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Serilog&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Version=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2.10.0&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PackageVersion&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft.EntityFrameworkCore&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Version=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;9.0.0&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PackageVersion&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft.EntityFrameworkCore.SqlServer&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Version=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;9.0.0&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Update all your csproj files&lt;/strong&gt;: In each project file (&lt;code&gt;.csproj&lt;/code&gt;), remove the version number information:&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Newtonsoft.Json&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Serilog&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft.EntityFrameworkCore&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Include=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft.EntityFrameworkCore.SqlServer&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="benefits-of-central-package-management"&gt;Benefits of Central Package Management&lt;a class="anchor ms-1" href="#benefits-of-central-package-management" aria-label="Permalink: Benefits of Central Package Management"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using Central Package Management offers several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consistency&lt;/strong&gt;: Ensures that all projects use the same package versions, reducing the risk of version conflicts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplified Updates&lt;/strong&gt;: Updating a package version in the central file automatically updates it across all projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced Maintenance&lt;/strong&gt;: Simplifies the process of managing package versions, especially in large solutions with many projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If for any reason you want to disable Central Package Management, you can set the &lt;code&gt;ManagePackageVersionsCentrally&lt;/code&gt; property to &lt;code&gt;false&lt;/code&gt; in the &lt;code&gt;Directory.Packages.props&lt;/code&gt; file, or in the csproj file if you only want to disable for a single project.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;NuGet Central Package Management simplifies the process of managing package versions across multiple projects in a .NET solution. By defining package versions in a central file, you can ensure consistency, simplify updates, and reduce maintenance efforts. Give it a try in your next .NET project to experience the benefits firsthand.&lt;/p&gt;
&lt;p&gt;For more information, visit the &lt;a href="https://learn.microsoft.com/en-us/nuget/consume-packages/Central-Package-Management" target="_blank" rel="noopener noreferrer"&gt;official NuGet documentation&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Setting Up Nagios Monitoring with Docker</title><link>https://blog-test.funkysi1701.com/posts/2025/monitoring-with-nagios-docker/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 06 Jan 2025 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2025/monitoring-with-nagios-docker/</guid><category term="Nagios">Nagios</category><category term="Docker">Docker</category><category term="Monitoring">Monitoring</category><category term="SysAdmin">SysAdmin</category><category term="DevOps">DevOps</category><category term="NetworkMonitoring">NetworkMonitoring</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/nagios.png"/><description>&lt;p&gt;A long time ago in my SysAdmin days, I was a big fan of &lt;a href="https://blog-test.funkysi1701.com/posts/2014/i-love-nagios/"&gt;Nagios&lt;/a&gt;
. Recently, I decided to revisit it and see if I could run it in a Docker container to monitor my local network. This guide will walk you through the process of setting up Nagios monitoring using Docker.&lt;/p&gt;
&lt;h2 id="finding-a-docker-image-for-nagios"&gt;Finding a Docker Image for Nagios&lt;a class="anchor ms-1" href="#finding-a-docker-image-for-nagios" aria-label="Permalink: Finding a Docker Image for Nagios"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, we need to find a suitable Docker image for Nagios. The &lt;a href="https://hub.docker.com/r/manios/nagios" target="_blank" rel="noopener noreferrer"&gt;manios/nagios&lt;/a&gt;
image looks like it should do the job.&lt;/p&gt;
&lt;h2 id="running-the-nagios-docker-container"&gt;Running the Nagios Docker Container&lt;a class="anchor ms-1" href="#running-the-nagios-docker-container" aria-label="Permalink: Running the Nagios Docker Container"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The basics of running this container are as follows:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run -d --name nagios -p 8080:80 manios/nagios
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command will pull the Nagios image from Docker Hub and run it in a container, mapping port 80 in the container to port 8080 on your host machine.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run -d --name nagios &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -v /path-to-nagios/etc/:/opt/nagios/etc/ &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -v /path-to-nagios/var:/opt/nagios/var/ &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -v /path-to-nagios/ssmtp.conf:/etc/ssmtp/ssmtp.conf &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -v /path-to-custom-plugins:/opt/Custom-Nagios-Plugins &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -p 8080:80 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manios/nagios
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I prefer running via docker compose, which looks like 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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;nagios&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;manios/nagios:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;monitoring_nagios&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;8081&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;restart&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;./nagios/localhost.cfg:/opt/nagios/etc/objects/localhost.cfg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;./nagios/windows.cfg:/opt/nagios/etc/objects/windows.cfg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;nagios_data:/opt/nagios/var/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;NAGIOSADMIN_USER=nagiosadmin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;NAGIOSADMIN_PASS=nagiosadmin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;NAGIOS_TIMEZONE=UTC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;NAGIOS_WEB_USER=nagiosadmin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;NAGIOS_WEB_PASS=nagiosadmin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="accessing-the-nagios-web-interface"&gt;Accessing the Nagios Web Interface&lt;a class="anchor ms-1" href="#accessing-the-nagios-web-interface" aria-label="Permalink: Accessing the Nagios Web Interface"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once the container is running, you can access the Nagios web interface by navigating to http://localhost:8080 in your web browser. You should see the Nagios login page.&lt;/p&gt;
&lt;h2 id="configuring-nagios"&gt;Configuring Nagios&lt;a class="anchor ms-1" href="#configuring-nagios" aria-label="Permalink: Configuring Nagios"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To configure Nagios, you&amp;rsquo;ll need to edit the configuration files located in the container. You can do this by accessing the container&amp;rsquo;s shell:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker exec -it nagios /bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From here, you can navigate to the Nagios configuration directory and make the necessary changes:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd /opt/nagios/etc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="adding-hosts-and-services"&gt;Adding Hosts and Services&lt;a class="anchor ms-1" href="#adding-hosts-and-services" aria-label="Permalink: Adding Hosts and Services"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To monitor your local network, you&amp;rsquo;ll need to add hosts and services to the Nagios configuration. This involves editing the configuration files and adding each host and service you want to monitor.&lt;/p&gt;
&lt;p&gt;I have added a few extra hosts to the localhost.cfg file to monitor my router, and a few other devices on my network. I have also added a Volume to store the nagios data, so after a restart of the container the data is still there.&lt;/p&gt;
&lt;p&gt;Lets have a look at how hosts and services are defined in the config files.&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-cfg" data-lang="cfg"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define host{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;use linux-server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;host_name router&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;alias router&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;parents localhost; Hosts that this host is dependent on &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;address 192.168.2.1; IP Address or DNS name of the host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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-cfg" data-lang="cfg"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define service{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;use local-service,graphed-service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;host_name localhost, router&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;service_description PING&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;check_command check_ping!100.0,20%!500.0,60%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When making changes to your config files it is useful to check the config is valid. To do this with the docker file you can run the following command:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker exec -it mynagioscontainer bin/nagios -v etc/nagios.cfg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It may have been 10 years since I last looked at Nagios, but the UI hasn&amp;rsquo;t changed much. Host are checked if they are Up or Down, and every Host can have a number of services associated with it and this are checked if they are Up or Down.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Nagios UI" src="https://blog-test.funkysi1701.com/images/nagios.png" loading="lazy"
width="1605" height="702"
/&gt;
&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By following these steps, you can set up Nagios monitoring using Docker to keep an eye on your local network. Nagios is a powerful tool for network monitoring, and running it in a Docker container makes it easy to deploy and manage. Happy monitoring!&lt;/p&gt;
&lt;h3 id="related-on-this-blog"&gt;Related on this blog&lt;a class="anchor ms-1" href="#related-on-this-blog" aria-label="Permalink: Related on this blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For application metrics and dashboards rather than host ping checks, see &lt;a href="https://blog-test.funkysi1701.com/posts/2025/setting-up-grafana/"&gt;setting up Grafana&lt;/a&gt;
with Prometheus. I also wrote about &lt;a href="https://blog-test.funkysi1701.com/posts/2014/i-love-nagios/"&gt;loving Nagios&lt;/a&gt;
the first time around — the UI has barely moved since.&lt;/p&gt;</description></item><item><title>Events 2025</title><link>https://blog-test.funkysi1701.com/posts/events/2025/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 01 Jan 2025 01:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/events/2025/</guid><description>&lt;h2 id="2025"&gt;2025&lt;a class="anchor ms-1" href="#2025" aria-label="Permalink: 2025"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Talk&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DDD North&lt;/td&gt;
&lt;td&gt;22 February 2025&lt;/td&gt;
&lt;td&gt;Hull&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.funkysi1701.com/posts/2025/volunteering-at-ndc/" target="_blank" rel="noopener noreferrer"&gt;NDC London&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;29-31 January 2025&lt;/td&gt;
&lt;td&gt;London&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For my parkrun results see &lt;a href="https://blog-test.funkysi1701.com/parkrun"&gt;parkrun&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Reflecting on 2024, goals for 2025</title><link>https://blog-test.funkysi1701.com/posts/2024/end-of-year/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 30 Dec 2024 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/end-of-year/</guid><category term="Reflection">Reflection</category><category term="Goals">Goals</category><category term="Learning">Learning</category><category term="Blogging">Blogging</category><category term="PersonalGrowth">PersonalGrowth</category><category term="Conferences">Conferences</category><category term="UserGroups">UserGroups</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/goals-for-2025.png"/><description>&lt;p&gt;It is that time of year again, time to reflect on the year that has passed and look forward to the year ahead. As with many years 2024 has been a mixed bag, some good stuff, and some not so good stuff. I did not make any goals at the start of 2024, but I am going to fix that for 2025.&lt;/p&gt;
&lt;p&gt;Goals for 2025&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blog Posts&lt;/li&gt;
&lt;li&gt;More Learning&lt;/li&gt;
&lt;li&gt;Drink More Water and Do More Walks&lt;/li&gt;
&lt;li&gt;Attend Conferences and User Groups&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="blog-posts"&gt;Blog Posts&lt;a class="anchor ms-1" href="#blog-posts" aria-label="Permalink: Blog Posts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For most of the year, I have &lt;strong&gt;not&lt;/strong&gt; been writing blog posts. However, the Scottish Summit conference reignited my blogging spark, and I have written seven posts since then. My goal is to write one post a week. I am sure I will miss the odd week, but the important thing is not to miss two in a row.&lt;/p&gt;
&lt;h2 id="more-learning"&gt;More Learning&lt;a class="anchor ms-1" href="#more-learning" aria-label="Permalink: More Learning"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Being a developer is a constant journey of learning, and I have not done enough of that this year. During December, I completed a few challenges from &lt;a href="https://adventofcode.com/" target="_blank" rel="noopener noreferrer"&gt;Advent of Code&lt;/a&gt;
, and I hope to do more of them. I have also discovered &lt;a href="https://exercism.org/" target="_blank" rel="noopener noreferrer"&gt;Exercism&lt;/a&gt;
and started working through the C# track. I am sure there will be more opportunities to learn new things in 2025.&lt;/p&gt;
&lt;h2 id="health"&gt;Health&lt;a class="anchor ms-1" href="#health" aria-label="Permalink: Health"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;2024 took an unusual turn. In June, I walked a &lt;a href="https://blog-test.funkysi1701.com/posts/2024/charity-hike"&gt;half marathon across the Peak District&lt;/a&gt;
, and since then, I have been doing lots of walks. Walking is good for my physical and mental health, so I intend to do more of it in 2025. I have a 5k scheduled for January, which should be lots of fun as it is around the wildlife park. On the same topic, I want to drink more water. Not sure how I am going to accomplish this as I am easily distracted by the current developer problem, instead of thinking about my health.&lt;/p&gt;
&lt;h2 id="conferences-and-user-groups"&gt;Conferences and User Groups&lt;a class="anchor ms-1" href="#conferences-and-user-groups" aria-label="Permalink: Conferences and User Groups"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I want to attend a conference or user group once a month in 2025. Conferences and user groups are great places to meet people, learn new things, and be encouraged by the community. I have signed up as a volunteer for NDC London in January, and DDD North is back in February. I am sure I will be able to fill the other months with events soon enough as well.&lt;/p&gt;
&lt;h2 id="what-happened-in-2024"&gt;What Happened in 2024&lt;a class="anchor ms-1" href="#what-happened-in-2024" aria-label="Permalink: What Happened in 2024"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I did something in 2024 that I thought I would never do. I signed up for a half marathon hike across the Peak District for charity. This was an amazing achievement for me, involving lots of training walks and raising over £600 for charity.&lt;/p&gt;
&lt;p&gt;My attendance at conferences and user groups has been a bit light this year. However, I did attend the Scottish Summit in October, which rekindled my blogging. I also attended DDD North with a couple of my work colleagues, which was great as usual.&lt;/p&gt;
&lt;p&gt;Family life has kept me busy this year and has been my focus for much of the year. Next year, I want the focus to shift more to my work and career. I attended a couple of code club sessions with my eldest son, and it was great to see his skills develop. Like me, he wanted to help others with the coding exercise.&lt;/p&gt;</description></item><item><title>Automate develop to main pull requests</title><link>https://blog-test.funkysi1701.com/posts/2024/automatic-pull-requests/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 16 Dec 2024 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/automatic-pull-requests/</guid><category term="AzureDevOps">AzureDevOps</category><category term="PullRequests">PullRequests</category><category term="Automation">Automation</category><category term="PowerShell">PowerShell</category><category term="CI/CD">CI/CD</category><category term="DevOps">DevOps</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/automatic-pull-requests.png"/><description>&lt;p&gt;Creating pull requests is part of day-to-day Git work: you propose changes, review them, and merge. Long-lived integration branches make that tedious if someone has to open the release PR by hand every time.&lt;/p&gt;
&lt;p&gt;Automatic pull requests keep a develop → main (or master) PR open and refreshed when develop moves. Below are two patterns I use: GitHub Actions with the GitHub CLI, and Azure DevOps with a PowerShell script against the REST API.&lt;/p&gt;
&lt;h2 id="github"&gt;GitHub&lt;a class="anchor ms-1" href="#github" aria-label="Permalink: GitHub"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;GitHub Actions can run whenever code is pushed to &lt;code&gt;develop&lt;/code&gt;. Prefer &lt;strong&gt;create or update&lt;/strong&gt; so a second push does not fail when the PR already exists — the same idea this site uses in &lt;a href="https://github.com/funkysi1701/funkysi1701.github.io/blob/main/.github/workflows/auto-pr.yml" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;.github/workflows/auto-pr.yml&lt;/code&gt;&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Auto PR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;push&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;branches&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;develop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;workflow_dispatch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;permissions&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;contents&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;pull-requests&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;create-pr&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Check out repository code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/checkout@v4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;fetch-depth&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ref&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;develop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Create or update pull request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;GITHUB_TOKEN&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; TITLE=&amp;#39;Merge develop into main&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; BODY=&amp;#39;Created by GitHub Actions.&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; if gh pr create -B main -H develop --title &amp;#34;$TITLE&amp;#34; --body &amp;#34;$BODY&amp;#34;; then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; exit 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; fi
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; PR=$(gh pr list --head develop --base main --state open --json number -q &amp;#39;.[0].number&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; if [ -n &amp;#34;$PR&amp;#34; ] &amp;amp;&amp;amp; [ &amp;#34;$PR&amp;#34; != &amp;#34;null&amp;#34; ]; then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; gh pr edit &amp;#34;$PR&amp;#34; --title &amp;#34;$TITLE&amp;#34; --body &amp;#34;$BODY&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; echo &amp;#34;No open PR found to update.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; exit 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This runs on push to &lt;code&gt;develop&lt;/code&gt;, checks out that branch, then creates a PR into &lt;code&gt;main&lt;/code&gt; or edits the existing open develop → main PR. Pin &lt;code&gt;actions/checkout&lt;/code&gt; to a major tag (or a full commit SHA in production workflows) and grant &lt;code&gt;pull-requests: write&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The workflow uses the &lt;a href="https://cli.github.com/" target="_blank" rel="noopener noreferrer"&gt;GitHub CLI&lt;/a&gt;
. &lt;code&gt;gh pr create&lt;/code&gt; opens the PR; &lt;code&gt;gh pr edit&lt;/code&gt; refreshes title and body when create fails because one already exists. You can also fold create-or-edit into a one-liner if you prefer:&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-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;run&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;gh pr create -B main -H develop --title &amp;#39;Merge develop into main&amp;#39; --body &amp;#39;Created by GitHub action&amp;#39; || gh pr edit -B main --title &amp;#34;Merge develop into main&amp;#34; --body &amp;#39;Created by GitHub action&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="azure-devops"&gt;Azure DevOps&lt;a class="anchor ms-1" href="#azure-devops" aria-label="Permalink: Azure DevOps"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Azure DevOps has a similar feature to GitHub Actions called Azure Pipelines. You can create pipelines that run on specific triggers, such as when code is pushed to a specific branch. For Azure DevOps I have a PowerShell script that does most of the work; let’s have a look at it:&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;param&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$repoName,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$sourceBranch,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$targetBranch,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$prTitle,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$prDescription
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Construct base URLs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$collectionUri = $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI.TrimEnd(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$projectName = $env:SYSTEM_TEAMPROJECT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$apisUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$collectionUri&lt;span style="color:#e6db74"&gt;/&lt;/span&gt;$projectName&lt;span style="color:#e6db74"&gt;/_apis&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$apiVersionQs = &lt;span style="color:#e6db74"&gt;&amp;#34;?api-version=7.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Create common headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$headers = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;Bearer &lt;/span&gt;$env:SYSTEM_ACCESSTOKEN&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 1: Fetch the repository GUID using its name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$repositoryUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$apisUrl&lt;span style="color:#e6db74"&gt;/git/repositories/&lt;/span&gt;$repoName$apiVersionQs&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$repositoryResponse = Invoke-RestMethod -Uri $repositoryUrl -Method GET -Headers $headers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$repoGuid = $repositoryResponse.id &lt;span style="color:#75715e"&gt;# Extract the repository GUID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;-not&lt;/span&gt; $repoGuid) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Failed to retrieve repository GUID for repository &amp;#39;&lt;/span&gt;$repoName&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Now construct the project URL using the repository GUID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$projectUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$apisUrl&lt;span style="color:#e6db74"&gt;/git/repositories/&lt;/span&gt;$repoGuid&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Construct full ref names&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sourceBranchRef = &lt;span style="color:#e6db74"&gt;&amp;#34;refs/heads/&lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$targetBranchRef = &lt;span style="color:#e6db74"&gt;&amp;#34;refs/heads/&lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 2: Prepare the body for the commit comparison using GetCommitsBatch API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$body = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;itemVersion&amp;#34;&lt;/span&gt; = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;version&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;versionType&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;branch&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;compareVersion&amp;#34;&lt;/span&gt; = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;version&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;versionType&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;branch&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} | ConvertTo-Json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 3: Call the Azure DevOps API to compare the branches using GetCommitsBatch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$diffUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$projectUrl&lt;span style="color:#e6db74"&gt;/commitsBatch&lt;/span&gt;$apiVersionQs&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$commitResponse = Invoke-RestMethod -Uri $diffUrl -Method POST -Headers $headers -Body $body
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 4: Check if there are any changes between the branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($commitResponse.count &lt;span style="color:#f92672"&gt;-gt&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;There are changes between &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; and &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;No changes between &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; and &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Check for existing active pull requests between source and target branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$encodedSourceBranchRef = [&lt;span style="color:#66d9ef"&gt;System.Web.HttpUtility&lt;/span&gt;]::UrlEncode($sourceBranchRef)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$encodedTargetBranchRef = [&lt;span style="color:#66d9ef"&gt;System.Web.HttpUtility&lt;/span&gt;]::UrlEncode($targetBranchRef)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$checkPrUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$projectUrl&lt;span style="color:#e6db74"&gt;/pullrequests&lt;/span&gt;$apiVersionQs&lt;span style="color:#e6db74"&gt;&amp;amp;searchCriteria.sourceRefName=&lt;/span&gt;$encodedSourceBranchRef&lt;span style="color:#e6db74"&gt;&amp;amp;searchCriteria.targetRefName=&lt;/span&gt;$encodedTargetBranchRef&lt;span style="color:#e6db74"&gt;&amp;amp;searchCriteria.status=active&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Checking for existing active pull requests between &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; and &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$existingPrs = Invoke-RestMethod -Method GET -Headers $headers -Uri $checkPrUrl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($existingPrs.count &lt;span style="color:#f92672"&gt;-gt&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# An active pull request already exists&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $existingPr = $existingPrs.value[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#75715e"&gt;# Assuming we take the first one if multiple exist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pullRequestId = $existingPr.pullRequestId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;An active pull request already exists between &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; and &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Pull Request ID: &lt;/span&gt;$pullRequestId&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;##vso[task.setvariable variable=prId]&lt;/span&gt;$pullRequestId&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Create a Pull Request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequestUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$projectUrl&lt;span style="color:#e6db74"&gt;/pullrequests&lt;/span&gt;$apiVersionQs&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequest = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sourceRefName&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$sourceBranchRef&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;targetRefName&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$targetBranchRef&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;title&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$prTitle&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$prDescription&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequestJson = ($pullRequest | ConvertTo-Json -Depth &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Sending a REST call to create a new pull request from &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; to &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# REST call to create a Pull Request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequestResult = Invoke-RestMethod -Method POST -Headers $headers -Body $pullRequestJson -Uri $pullRequestUrl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Ensure the pull request ID exists&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;-not&lt;/span&gt; $pullRequestResult.pullRequestId) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Pull request creation failed. No pull request ID returned.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequestId = $pullRequestResult.pullRequestId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Pull request created. Pull Request Id: &lt;/span&gt;$pullRequestId&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;##vso[task.setvariable variable=prId]&lt;/span&gt;$pullRequestId&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This uses the Azure DevOps REST API to create a PR. The script takes the repository name, source branch, target branch, PR title, and PR description. It compares the branches, creates a PR when there are commits to merge, and reuses an existing active PR when one is already open. Run it as a pipeline step.&lt;/p&gt;
&lt;p&gt;My pipeline has a step that looks a bit like:&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-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;task&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;PowerShell@2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;displayName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Create PR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;condition&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;eq(variables[&amp;#39;Build.SourceBranch&amp;#39;], &amp;#39;refs/heads/develop&amp;#39;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;targetType&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;inline&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;build/CreatePR.ps1 -repoName ProjectX -sourceBranch develop -targetBranch main -prTitle &amp;#34;Release $(Build.Number.Major).$(Build.Number.Minor).x&amp;#34; -prDescription &amp;#34;Dev to Prod&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;SYSTEM_ACCESSTOKEN&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;$(System.AccessToken)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I only run this step on the develop branch, and you can see I supply all the parameters that are defined in my PowerShell script. I include the &lt;code&gt;System.AccessToken&lt;/code&gt; so the step can call the REST APIs for the project.&lt;/p&gt;
&lt;h3 id="related-on-this-blog"&gt;Related on this blog&lt;a class="anchor ms-1" href="#related-on-this-blog" aria-label="Permalink: Related on this blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For combining repositories before you automate promotion, see &lt;a href="https://blog-test.funkysi1701.com/posts/2025/merge-two-projects-into-one/"&gt;merge two projects into one&lt;/a&gt;
. For a broader GitHub Actions walkthrough, start with &lt;a href="https://blog-test.funkysi1701.com/posts/2022/using-github-actions/"&gt;using GitHub Actions&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want to get a monthly email with all my latest articles, please sign up for my &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. If you have any questions or comments, please feel free to reach out or leave a comment below.&lt;/p&gt;</description></item><item><title>Common AI and Copilot Terms</title><link>https://blog-test.funkysi1701.com/posts/2024/common-ai-copilot-terms/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 09 Dec 2024 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/common-ai-copilot-terms/</guid><category term="AI">AI</category><category term="Copilot">Copilot</category><category term="RAG">RAG</category><category term="LLM">LLM</category><category term="GPT">GPT</category><category term="MachineLearning">MachineLearning</category><category term="NaturalLanguageProcessing">NaturalLanguageProcessing</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/ai.jpeg"/><description>&lt;p&gt;AI is everywhere at the moment, from chatbots to code completion tools like GitHub Copilot. Here are some common AI and Copilot terms with explanations.&lt;/p&gt;
&lt;h2 id="common-ai-and-copilot-terms"&gt;Common AI and Copilot Terms&lt;a class="anchor ms-1" href="#common-ai-and-copilot-terms" aria-label="Permalink: Common AI and Copilot Terms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="artificial-intelligence-ai"&gt;Artificial Intelligence (AI)&lt;a class="anchor ms-1" href="#artificial-intelligence-ai" aria-label="Permalink: Artificial Intelligence (AI)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Artificial Intelligence (AI) refers to the simulation of human intelligence in machines that are programmed to think and learn like humans. AI can be used for various applications, including natural language processing, image recognition, and decision-making. AI systems are designed to perform tasks that typically require human intelligence, such as visual perception, speech recognition, decision-making, and language translation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Artificial_intelligence" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Artificial Intelligence&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="machine-learning-ml"&gt;Machine Learning (ML)&lt;a class="anchor ms-1" href="#machine-learning-ml" aria-label="Permalink: Machine Learning (ML)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Machine Learning (ML) is a subset of AI that involves the use of algorithms and statistical models to enable machines to improve their performance on a specific task through experience. ML algorithms learn from data and make predictions or decisions without being explicitly programmed. Machine learning is used in a variety of applications, such as email filtering, fraud detection, and recommendation systems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Machine_learning" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Machine Learning&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="natural-language-processing-nlp"&gt;Natural Language Processing (NLP)&lt;a class="anchor ms-1" href="#natural-language-processing-nlp" aria-label="Permalink: Natural Language Processing (NLP)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Natural Language Processing (NLP) is a field of AI that focuses on the interaction between computers and humans through natural language. NLP enables machines to understand, interpret, and generate human language, making it possible for AI systems to communicate with users in a more natural way.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Natural_language_processing" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Natural Language Processing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="github-copilot"&gt;GitHub Copilot&lt;a class="anchor ms-1" href="#github-copilot" aria-label="Permalink: GitHub Copilot"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Copilot is an AI-powered code completion tool developed by GitHub in collaboration with OpenAI. It uses machine learning models to provide code suggestions and autocompletions based on the context of the code being written. Copilot helps developers write code faster and with fewer errors by offering relevant code snippets and completing lines of code as they type. It supports a wide range of programming languages and can be integrated into popular code editors like Visual Studio Code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/copilot/about-github-copilot" target="_blank" rel="noopener noreferrer"&gt;GitHub Copilot: Docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/features/copilot" target="_blank" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="retrieval-augmented-generation-rag"&gt;Retrieval-Augmented Generation (RAG)&lt;a class="anchor ms-1" href="#retrieval-augmented-generation-rag" aria-label="Permalink: Retrieval-Augmented Generation (RAG)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Retrieval-Augmented Generation (RAG) is a technique that combines retrieval-based and generation-based approaches to improve the performance of AI models in tasks such as question answering and text generation. RAG involves retrieving relevant documents or information from a large corpus and using that information to generate more accurate and contextually relevant responses.&lt;/p&gt;
&lt;h3 id="large-language-models-llm"&gt;Large Language Models (LLM)&lt;a class="anchor ms-1" href="#large-language-models-llm" aria-label="Permalink: Large Language Models (LLM)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Large Language Models (LLM) are a type of AI model that is trained on vast amounts of text data to understand and generate human language. These models, such as GPT-3, are capable of performing a wide range of language tasks, including translation, summarization, and question answering. LLMs leverage deep learning techniques to capture the nuances of language and provide highly accurate and contextually relevant outputs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Language_model" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Language Models&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="generative-pre-trained-transformer-gpt"&gt;Generative Pre-trained Transformer (GPT)&lt;a class="anchor ms-1" href="#generative-pre-trained-transformer-gpt" aria-label="Permalink: Generative Pre-trained Transformer (GPT)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Generative Pre-trained Transformer (GPT) is a type of large language model developed by OpenAI. GPT models, such as GPT-3, are pre-trained on a diverse range of internet text and fine-tuned for specific tasks. GPT models are known for their ability to generate coherent and contextually relevant text, making them useful for applications such as chatbots, content creation, and code generation.&lt;/p&gt;
&lt;h3 id="deep-learning"&gt;Deep Learning&lt;a class="anchor ms-1" href="#deep-learning" aria-label="Permalink: Deep Learning"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Deep Learning is a subset of machine learning that involves the use of neural networks with many layers (deep neural networks) to model complex patterns in data. Deep learning has been particularly successful in tasks such as image and speech recognition, natural language processing, and game playing.&lt;/p&gt;
&lt;h3 id="neural-networks"&gt;Neural Networks&lt;a class="anchor ms-1" href="#neural-networks" aria-label="Permalink: Neural Networks"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Neural Networks are a series of algorithms that attempt to recognize underlying relationships in a set of data through a process that mimics the way the human brain operates. Neural networks consist of layers of interconnected nodes (neurons) that process input data and generate output.&lt;/p&gt;
&lt;h3 id="reinforcement-learning-rl"&gt;Reinforcement Learning (RL)&lt;a class="anchor ms-1" href="#reinforcement-learning-rl" aria-label="Permalink: Reinforcement Learning (RL)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reinforcement Learning (RL) is a type of machine learning where an agent learns to make decisions by taking actions in an environment to maximize a cumulative reward. RL is commonly used in applications such as robotics, game playing, and autonomous systems.&lt;/p&gt;
&lt;h3 id="computer-vision"&gt;Computer Vision&lt;a class="anchor ms-1" href="#computer-vision" aria-label="Permalink: Computer Vision"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Computer Vision is a field of AI that enables machines to interpret and understand visual information from the world, such as images and videos. Computer vision techniques are used in applications such as facial recognition, object detection, and image classification.&lt;/p&gt;
&lt;h3 id="generative-adversarial-networks-gans"&gt;Generative Adversarial Networks (GANs)&lt;a class="anchor ms-1" href="#generative-adversarial-networks-gans" aria-label="Permalink: Generative Adversarial Networks (GANs)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Generative Adversarial Networks (GANs) are a class of neural networks used for generating new data samples that are similar to a given training dataset. GANs consist of two networks: a generator that creates new data samples and a discriminator that evaluates the authenticity of the generated samples. GANs are used in applications such as image synthesis, data augmentation, and style transfer.&lt;/p&gt;
&lt;h3 id="positronic-brain"&gt;Positronic Brain&lt;a class="anchor ms-1" href="#positronic-brain" aria-label="Permalink: Positronic Brain"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Positronic Brain is a fictional technological concept created by science fiction writer Isaac Asimov. It is a highly advanced artificial brain used in robots, enabling them to process information, make decisions, and exhibit behaviors similar to human intelligence. The concept of the Positronic Brain is central to Asimov&amp;rsquo;s Robot series, where it serves as the foundation for the robots&amp;rsquo; cognitive functions and adherence to the Three Laws of Robotics. Star Trek&amp;rsquo;s Commander Data had a positronic brain as well.&lt;/p&gt;
&lt;p&gt;For more information on the Positronic Brain, you can refer to the following sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Positronic_brain" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Positronic Brain&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Robot_series" target="_blank" rel="noopener noreferrer"&gt;Isaac Asimov&amp;rsquo;s Robot Series&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Top electricity-consuming devices</title><link>https://blog-test.funkysi1701.com/posts/2024/top-electricity-devices/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 02 Dec 2024 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/top-electricity-devices/</guid><category term="Electricity">Electricity</category><category term="SmartPlugs">SmartPlugs</category><category term="HomeAssistant">HomeAssistant</category><category term="EnergyMonitoring">EnergyMonitoring</category><category term="PowerConsumption">PowerConsumption</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/elec-usage.png"/><description>&lt;p&gt;I have been wondering what devices in my house use the most electricity. I have a smart meter which tells me how much electricity I am using, but it doesn&amp;rsquo;t tell me what devices are using the most electricity.&lt;/p&gt;
&lt;p&gt;Recently I purchased 12 of these &lt;a href="https://www.amazon.co.uk/dp/B09VP5KNWM?ref=ppx_yo2ov_dt_b_fed_asin_title" target="_blank" rel="noopener noreferrer"&gt;ANTELA Smart Plugs&lt;/a&gt;
(they come in packs of 4 so it hasn&amp;rsquo;t broken the bank). They are straightforward to set up, you plug them into your power socket and plug your device you want to monitor into them, after that you connect to the wifi and can turn the device off/on and see how much power/current/voltage they are using. I have integrated them into Home Assistant and after about a day of usage I can reveal the following findings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 x Monitors attached to my Laptop. As I write this they are only using about 30W of power between them.&lt;/li&gt;
&lt;li&gt;Microwave - I cooked a potato and it used 1.2kWh of power.&lt;/li&gt;
&lt;li&gt;Washing Machine - Peaks at about 2kW of power, plus the cycle takes some time to complete.&lt;/li&gt;
&lt;li&gt;Laptop - Laptop charger, looks to be using about 37W of power.&lt;/li&gt;
&lt;li&gt;Kettle - A massive electricity hog, only runs for a short time but reaches 2.9kW of power.&lt;/li&gt;
&lt;li&gt;My Routers/Switches/Servers - My home network has a few devices on it like Raspberry Pi&amp;rsquo;s, a linux and windows server and a network switch etc. Between them they are using about 32W of power. Not a lot but it is on 24-7.&lt;/li&gt;
&lt;li&gt;Fridge - I have a fridge freezer, it uses about 72W of power.&lt;/li&gt;
&lt;li&gt;TV (and firestick) - This is a surprisingly large amount of power. TV is on quite a lot and is using 110W of power. There are other devices which contribute to this value, however when off the TV is still using 10W of power. I am assuming its age is a big factor.&lt;/li&gt;
&lt;li&gt;Tumble Dryer - Again no surprises that this is a big electricity user, it peaks at 2.3kW of power and as it runs for a good couple of hours or so, is a big contributor to my electricity.&lt;/li&gt;
&lt;li&gt;Dishwasher - I have put the dishwasher on a few times today and it peaks at 2.2kW of power.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Electricity Usage" src="https://blog-test.funkysi1701.com/images/elec-usage.png" loading="lazy"
width="701" height="445"
/&gt;
&lt;/p&gt;
&lt;p&gt;I am not able to monitor 100% of my electricity usage, things like lights, my boiler and anything else wired directly in, won&amp;rsquo;t have a plug and I can&amp;rsquo;t monitor in this way. However over the last month or so I can see what is using the most electricity.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Electricity Usage" src="https://blog-test.funkysi1701.com/images/elec-usage2.png" loading="lazy"
width="1537" height="435"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://octopus.energy/" target="_blank" rel="noopener noreferrer"&gt;Octopus Energy&lt;/a&gt;
who supply my energy have an agile tariff, which means the price of electricity changes every half hour depending on demand. I want to move the heavy usage of electricity to cheaper parts of the day, so I can save money.&lt;/p&gt;
&lt;p&gt;If you want to support me do check out my &lt;a href="https://blog-test.funkysi1701.com/tools-and-resources/"&gt;referral links&lt;/a&gt;
we could both get £50 if you sign up with Octopus Energy to supply your energy.&lt;/p&gt;
&lt;h2 id="now-how-did-i-get-this-all-setup"&gt;Now how did I get this all setup?&lt;a class="anchor ms-1" href="#now-how-did-i-get-this-all-setup" aria-label="Permalink: Now how did I get this all setup?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;1 - Plug a smart plug into a power socket and start measuring power. The app &amp;ldquo;Smart Life&amp;rdquo; is used to connect to the smart plug and get the power readings and is available in the Android store.&lt;/p&gt;
&lt;p&gt;2 - Integrate each smart plug into Home Assistant. The integration you need is the &lt;a href="https://www.home-assistant.io/integrations/tuya" target="_blank" rel="noopener noreferrer"&gt;Tuya&lt;/a&gt;
integration. A User Code from the Smart Life app is needed to add to Home Assistant.&lt;/p&gt;
&lt;p&gt;3 - The Voltage, Power and Current sensors are all defaulted to off in Home Assistant, so you need to go and enable these, once that is done you can see the power usage in Home Assistant.&lt;/p&gt;
&lt;p&gt;4 - Now you have Watts, Amps and Volts in Home Assistant but the Energy section of Home Assistant requires Wh or KWh. To get this you need to use the Integral helper to get the amount of time that the device is on for. Go to Add Integration and search for Integral (helper)&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Electricity Usage" src="https://blog-test.funkysi1701.com/images/elec-usage3.png" loading="lazy"
width="611" height="917"
/&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name is the user friendly name of the device.&lt;/li&gt;
&lt;li&gt;Metric prefix is the unit of measurement, in this case KWh.&lt;/li&gt;
&lt;li&gt;Time of Unit is Hours&lt;/li&gt;
&lt;li&gt;Entity is the sensor that is measuring the power usage.&lt;/li&gt;
&lt;li&gt;Integration method use Left Riemann sum&lt;/li&gt;
&lt;li&gt;Precision is the number of decimal places, so fine to use 0 here.&lt;/li&gt;
&lt;li&gt;Max Sub Interval is 5 minutes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This gives you an extra sensor in Home Assistant which is the energy usage of the device. In my case in kWh.&lt;/p&gt;
&lt;p&gt;5 - Go to your Energy Dashboard in Home Assistant and go to Energy Configuration. Add the new sensor to the Individual Devices section and you can see the energy usage of the device over time.&lt;/p&gt;
&lt;p&gt;The accuracy is not brilliant, sometimes it looks like I have used more energy in my devices than my smart meter says I have used in total. However it is a good indicator of what is using the most electricity in your house. Leave it running for a few days, you may have to tweak the Integral helper settings to get the best results.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://community.home-assistant.io/t/added-tuya-smart-plugs-where-is-the-energy-monitoring/356746/16" target="_blank" rel="noopener noreferrer"&gt;Home Assistant Forums&lt;/a&gt;
are great for getting this sort of thing setup, I have found a lot of useful information on there.&lt;/p&gt;</description></item><item><title>Getting started with .Net Aspire</title><link>https://blog-test.funkysi1701.com/posts/2024/aspire/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 25 Nov 2024 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/aspire/</guid><category term="DotNet">DotNet</category><category term="Blazor">Blazor</category><category term="C-Sharp">C-Sharp</category><category term="VisualStudio">VisualStudio</category><category term="Aspire">Aspire</category><category term="OpenTelemetry">OpenTelemetry</category><category term=".NET9">.NET9</category><category term="Microsoft">Microsoft</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/aspire-ga-what-is-aspire.png"/><description>&lt;h2 id="what-is-net-aspire"&gt;What is .Net Aspire?&lt;a class="anchor ms-1" href="#what-is-net-aspire" aria-label="Permalink: What is .Net Aspire?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;.Net Aspire is a comprehensive set of tools, templates, and packages designed to simplify the development of cloud-native applications using .Net. It focuses on building observable, production-ready apps by providing a consistent and opinionated set of &lt;a href="https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview" target="_blank" rel="noopener noreferrer"&gt;tools and patterns&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;The key features of .Net Aspire:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Orchestration: Enhances the local development experience by simplifying the management of your app&amp;rsquo;s configuration and interconnections. It helps with app composition, service discovery, and connection string management.&lt;/li&gt;
&lt;li&gt;Integrations: Offers NuGet packages for commonly used services like Redis and Postgres, ensuring they connect consistently and seamlessly with your app.&lt;/li&gt;
&lt;li&gt;Tooling: Comes with project templates and tooling experiences for Visual Studio, Visual Studio Code, and the .Net CLI to help you create and interact with .Net Aspire projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, &lt;a href="https://devblogs.microsoft.com/dotnet/introducing-dotnet-aspire-simplifying-cloud-native-development-with-dotnet-8/" target="_blank" rel="noopener noreferrer"&gt;.Net Aspire&lt;/a&gt;
aims to improve the experience of building .Net cloud-native apps by providing a robust framework for developing distributed applications.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Aspire" src="https://blog-test.funkysi1701.com/images/aspire-ga-what-is-aspire.png" loading="lazy"
width="1400" height="895"
/&gt;
&lt;/p&gt;
&lt;h2 id="getting-started-with-net-aspire"&gt;Getting started with .Net Aspire&lt;a class="anchor ms-1" href="#getting-started-with-net-aspire" aria-label="Permalink: Getting started with .Net Aspire"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I touched on .Net Aspire last week, when I talked about what was new in &lt;a href="https://blog-test.funkysi1701.com/posts/2024/dotnet9"&gt;dotnet 9&lt;/a&gt;
, but let&amp;rsquo;s walk through an example.&lt;/p&gt;
&lt;p&gt;Lets say you have a simple application. It has a Blazor web front end, it communicates with a .Net API and that API retrieves data from a SQL Server database. Before Aspire came along I would create a docker compose file and configure ports so the FE could call the API, and add connection strings so the API could access the database.&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-docker-compose.yml" data-lang="docker-compose.yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;Api&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${DOCKER_REGISTRY-}api&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;api&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;12345&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;44338&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;443&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;my-network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;context&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dockerfile&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;API/Dockerfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;sqlserver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;Ui&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${DOCKER_REGISTRY-}ui&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ui&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;44330&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;443&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;my-network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;context&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dockerfile&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;UI/Dockerfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;APIPath=http://Api:80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;sqlserver&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${DOCKER_REGISTRY-}sql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;sql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;sqlvol:/var/opt/mssql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;5432:1433&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;my-network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;context&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dockerfile&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Database/Dockerfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see from this docker compose file, there is a lot of specifying ports and other plumbing to get these three parts of my system to work together.&lt;/p&gt;
&lt;p&gt;Now in Visual Studio, right-click on the API project and select add &lt;strong&gt;.Net Aspire Orchestrator Support&lt;/strong&gt; this will add two new Visual Studio projects to the solution, AppHost and ServiceDefaults.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AppHost is where you configure what service depends on what, you can configure all sorts of different dependencies, like databases (sql server, mysql, postgres etc), rabbitmq, redis and many others.&lt;/li&gt;
&lt;li&gt;ServiceDefaults is where you configure the defaults for your services, like how opentelemetry should be configured, or how logging should work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now right click on the Blazor project and select the same option to get that wired up as well.&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-program.cs" data-lang="program.cs"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; builder = DistributedApplication.CreateBuilder(args);
&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;builder.AddProject&amp;lt;Projects.UI&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ui&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.AddProject&amp;lt;Projects.API&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;api&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.Build().Run();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Your Program.cs file inside your AppHost project will look something like this now, with both your API and UI/Blazor projects referenced.&lt;/p&gt;
&lt;p&gt;There is one more component we need to wire up, but we don&amp;rsquo;t have a project to right click on for the database. It is fairly straightforward to do, update it to look like the following:&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-program.cs" data-lang="program.cs"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; builder = DistributedApplication.CreateBuilder(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; sqldb = builder.AddSqlServer(&lt;span style="color:#e6db74"&gt;&amp;#34;sql&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithDataVolume(&lt;span style="color:#e6db74"&gt;&amp;#34;sql-data&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddDatabase(&lt;span style="color:#e6db74"&gt;&amp;#34;Context&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Project&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; api = builder.AddProject&amp;lt;Projects.API&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;api&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WaitFor(sqldb)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithReference(sqldb);
&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;builder.AddProject&amp;lt;Projects.UI&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ui&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WaitFor(api)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithReference(api);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; builder.Build().RunAsync();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You also need to install a couple of nuget packages. &lt;strong&gt;Aspire.Hosting.SqlServer&lt;/strong&gt; and &lt;strong&gt;Aspire.Microsoft.EntityFrameworkCore.SqlServer&lt;/strong&gt; the second one is because my project is using Entity Framework. Lets look at what we have, we are defining a SQL Server called sql, with a data volume called sql-data, and a database called Project, which we can refer to as Context. We then configure API to reference the sql server we have just configured, and wait for sql server to be ready before starting the API. Next the Blazor project depends on the API and will wait for that to be ready before starting. Pretty powerful stuff.&lt;/p&gt;
&lt;p&gt;OK lets look at the API project, what do I need to configure in my connectionstrings? Not much, Aspire will fill all of this in for you.&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-appsettings.json" data-lang="appsettings.json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ConnectionStrings&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;Context&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In your API project, your Program.cs will need a nuget package &lt;strong&gt;Aspire.Microsoft.EntityFrameworkCore.SqlServer&lt;/strong&gt; and the following line, and no need for any pulling config and passing in connection strings.&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-program.cs" data-lang="program.cs"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.AddSqlServerDbContext&amp;lt;Context&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Context&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One more clever thing we can do with Aspire is seed some data into my database before starting the project. Update the code that sets up your database in the AppHost project as follows.&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-program.cs" data-lang="program.cs"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; sqldb = builder.AddSqlServer(&lt;span style="color:#e6db74"&gt;&amp;#34;sql&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithBindMount(&lt;span style="color:#e6db74"&gt;&amp;#34;./sqlserverconfig&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/config&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithBindMount(&lt;span style="color:#e6db74"&gt;&amp;#34;../API/data/sqlserver&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/docker-entrypoint-initdb.d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithEntrypoint(&lt;span style="color:#e6db74"&gt;&amp;#34;/usr/config/entrypoint.sh&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithDataVolume(&lt;span style="color:#e6db74"&gt;&amp;#34;sql-data&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddDatabase(&lt;span style="color:#e6db74"&gt;&amp;#34;Context&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Project&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add a sqlserverconfig folder inside your AppHost project and add the following two files. I have found entrypoint.sh being a bit picky with its line endings (windows vs linux)&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-entrypoint.sh" data-lang="entrypoint.sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Adapted from: https://github.com/microsoft/mssql-docker/blob/80e2a51d0eb1693f2de014fb26d4a414f5a5add5/linux/preview/examples/mssql-customize/entrypoint.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Start the script to create the DB and user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/config/configure-db.sh &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Start SQL Server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/opt/mssql/bin/sqlservr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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-configure-db.sh" data-lang="configure-db.sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# set -x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Adapted from: https://github.com/microsoft/mssql-docker/blob/80e2a51d0eb1693f2de014fb26d4a414f5a5add5/linux/preview/examples/mssql-customize/configure-db.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Wait 60 seconds for SQL Server to start up by ensuring that&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# calling SQLCMD does not return an error code, which will ensure that sqlcmd is accessible&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# and that system and user databases return &amp;#34;0&amp;#34; which means all databases are in an &amp;#34;online&amp;#34; state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-databases-transact-sql?view=sql-server-2017&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dbstatus&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;errcode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$SECONDS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;end_by&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$((&lt;/span&gt;start_time &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;Starting check for SQL Server start-up at &lt;/span&gt;$start_time&lt;span style="color:#e6db74"&gt;, will end at &lt;/span&gt;$end_by&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $SECONDS -lt $end_by &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt; $errcode -ne &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt; -z &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$dbstatus&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; $dbstatus -ne &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dbstatus&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;/opt/mssql-tools18/bin/sqlcmd -h -1 -t &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; -U sa -P &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$MSSQL_SA_PASSWORD&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; -C -Q &lt;span style="color:#e6db74"&gt;&amp;#34;SET NOCOUNT ON; Select SUM(state) from sys.databases&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; errcode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sleep &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;elapsed_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$((&lt;/span&gt;SECONDS &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time&lt;span style="color:#66d9ef"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;Stopped checking for SQL Server start-up after &lt;/span&gt;$elapsed_time&lt;span style="color:#e6db74"&gt; seconds (dbstatus=&lt;/span&gt;$dbstatus&lt;span style="color:#e6db74"&gt;,errcode=&lt;/span&gt;$errcode&lt;span style="color:#e6db74"&gt;,seconds=&lt;/span&gt;$SECONDS&lt;span style="color:#e6db74"&gt;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $dbstatus -ne &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $errcode -ne &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;SQL Server took more than 60 seconds to start up or one or more databases are not in an ONLINE state&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;dbstatus = &lt;/span&gt;$dbstatus&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;errcode = &lt;/span&gt;$errcode&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exit &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Loop through the .sql files in the /docker-entrypoint-initdb.d and execute them with sqlcmd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; f in /docker-entrypoint-initdb.d/*.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Processing &lt;/span&gt;$f&lt;span style="color:#e6db74"&gt; file...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$MSSQL_SA_PASSWORD&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; -C -d master -i &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$f&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second BindMount line mounts a folder inside your API project, so add a data folder with a subfolder called sqlserver. Inside that add a sql script called init.sql. Put all your CREATE DATABASE and CREATE TABLES sql commands inside this. And if everything works you will have a seeded DB ready to test your application with.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is just a few things I have done with Aspire. Go check out the docs on &lt;a href="https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview" target="_blank" rel="noopener noreferrer"&gt;MS learn&lt;/a&gt;
or the some of the sessions from &lt;a href="https://www.youtube.com/watch?v=fiePiEc1qcU&amp;amp;list=PLdo4fOcmZ0oXeSG8BgCVru3zQtw_K4ANY&amp;amp;index=2" target="_blank" rel="noopener noreferrer"&gt;dotnet conf&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Version 9 of .Net is here</title><link>https://blog-test.funkysi1701.com/posts/2024/dotnet9/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 18 Nov 2024 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/dotnet9/</guid><category term="DotNet">DotNet</category><category term="Blazor">Blazor</category><category term="EFCore">EFCore</category><category term="C-Sharp">C-Sharp</category><category term="VisualStudio">VisualStudio</category><category term="Aspire">Aspire</category><category term="AI">AI</category><category term="OpenTelemetry">OpenTelemetry</category><category term=".NET9">.NET9</category><category term="Microsoft">Microsoft</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/bot-01.png"/><description>&lt;p&gt;Every November it is like Christmas for .NET developers, as Microsoft releases the next version of .NET. This year is no different, and we have version 9 of .NET to play with. This release is packed with new features and improvements across the board.&lt;/p&gt;
&lt;p&gt;If you haven&amp;rsquo;t already head on over to the &lt;a href="https://dotnet.microsoft.com/download/dotnet/9.0" target="_blank" rel="noopener noreferrer"&gt;dotnet website&lt;/a&gt;
and download the latest version.&lt;/p&gt;
&lt;p&gt;Also we get a brand new version of Visual Studio, which is always a good thing, so head on over to the Visual Studio &lt;a href="https://visualstudio.microsoft.com/downloads/" target="_blank" rel="noopener noreferrer"&gt;website&lt;/a&gt;
and download the latest version (or the Preview version if you want to test what is coming out next).&lt;/p&gt;
&lt;p&gt;Back when .Net 7 came out I wrote a &lt;a href="https://blog-test.funkysi1701.com/posts/2022/dotnet7/"&gt;post&lt;/a&gt;
about what you needed to fix to get the latest version working with your existing code. However this time around the upgrade is really smooth.&lt;/p&gt;
&lt;h2 id="nuget-audit"&gt;NuGet Audit&lt;a class="anchor ms-1" href="#nuget-audit" aria-label="Permalink: NuGet Audit"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Back in .Net 8 NuGet Audit was introduced which told you if any of your packages had security vulnerabilities. This has been improved in .Net 9, and now defaults to tell you about transitive dependencies. This is a great feature, but if you would prefer to keep .Net 8&amp;rsquo;s functionality you can add the following to your project (*.csproj) file.&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;NuGetAuditMode&amp;gt;&lt;/span&gt;direct&lt;span style="color:#f92672"&gt;&amp;lt;/NuGetAuditMode&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="net-aspire"&gt;.Net Aspire&lt;a class="anchor ms-1" href="#net-aspire" aria-label="Permalink: .Net Aspire"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Released just after .Net 8 .Net Aspire is a suite of tools to help develop microservices. Gone are the days of specifying ports and connection strings for your services, Aspire can handle this all programmatically.&lt;/p&gt;
&lt;p&gt;Aspire adds two new projects to your solution. AppHost and ServiceDefaults.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AppHost is where you configure what service depends on what, you can configure all sorts of different dependencies, like databases (sql server, mysql, postgres etc), rabbitmq, redis and many others. It is open source so the community are busy adding everything you could possibly need.&lt;/li&gt;
&lt;li&gt;ServiceDefaults is where you configure the defaults for your services, like how opentelemetry should be configured, or how logging should work. Microsoft have thought hard about this and come up with some opinionated defaults, but you can change these to suit your needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Starting the AppHost project will start up the Aspire Dashboard where you can start/stop containers, view logs and see the health of your services. This is primarily a devlopment tool, but there are some deployment tools, however I have not explored these much yet. More details about Aspire can be found &lt;a href="https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="blazor"&gt;Blazor&lt;a class="anchor ms-1" href="#blazor" aria-label="Permalink: Blazor"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have been using Blazor since the first previews in the .Net 3.1 days. It has come a long way since then, and now with .Net 9 it is even better.&lt;/p&gt;
&lt;p&gt;There has been some optimization of the delivery of static assets. To take advantage of this improvement, replace the following line in your Program.cs file.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app.MapStaticAssets(); &lt;span style="color:#75715e"&gt;//Add this line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app.UseStaticFiles(); &lt;span style="color:#75715e"&gt;//Remove this line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;.Net 9 will then cache your static assets ang give them a unique filename. This will allow the browser to cache the files for longer, and only download them when they have changed. This will speed up your site and reduce the amount of data transferred.&lt;/p&gt;
&lt;p&gt;In your razor pages use code similar to 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-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;@Assets[&amp;#34;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bootstrap&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bootstrap&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;min&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;css&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#34;]&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;@Assets[&amp;#34;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;css&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#34;]&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;@Assets[&amp;#34;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BlazorSample&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;styles&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;css&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#34;]&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ai"&gt;AI&lt;a class="anchor ms-1" href="#ai" aria-label="Permalink: AI"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It will have not escaped your notice that AI is everywhere, and it is no different with .Net. I saw some very impressive demos at the &lt;a href="https://www.dotnetconf.net/" target="_blank" rel="noopener noreferrer"&gt;.Net Conf&lt;/a&gt;
online conference. I encourage you to check our the videos. But to summarize Microsoft have added a bunch of abstractions to make it easier to write code to talk to the different AI models, I haven&amp;rsquo;t played about with AI much yet, but I am tempted to give it a go.&lt;/p&gt;
&lt;h2 id="sql-management-studio"&gt;SQL Management Studio&lt;a class="anchor ms-1" href="#sql-management-studio" aria-label="Permalink: SQL Management Studio"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have not used SQL Management Studio for a while as I have trying out Azure Data Studio. However a new Preview of SQL Server Management Studio is now &lt;a href="https://learn.microsoft.com/en-us/ssms/ssms-21/release-notes-21?view=sql-server-ver16" target="_blank" rel="noopener noreferrer"&gt;avaliable&lt;/a&gt;
. This version is 64bit and is based on Visual Studio engine, it even shares the same installer.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is only a small taste of the new features in .Net 9. Go check out .Net Conf to learn more or check out some of the links I have shared above.&lt;/p&gt;</description></item><item><title>Strategy Design Pattern</title><link>https://blog-test.funkysi1701.com/posts/2024/strategy-pattern/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 11 Nov 2024 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/strategy-pattern/</guid><category term="DesignPatterns">DesignPatterns</category><category term="Architecture">Architecture</category><category term="C-Sharp">C-Sharp</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/flying-machine-blueprint-patent-john-malone.jpg"/><description>&lt;h2 id="understanding-the-strategy-design-pattern"&gt;Understanding the Strategy Design Pattern.&lt;a class="anchor ms-1" href="#understanding-the-strategy-design-pattern" aria-label="Permalink: Understanding the Strategy Design Pattern."&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the world of software development, design patterns are essential tools that help developers solve common problems in a standardized way. One such pattern is the &lt;strong&gt;Strategy Design Pattern&lt;/strong&gt;. This pattern is particularly useful when you need to define a family of algorithms, encapsulate each one, and make them interchangeable. Let&amp;rsquo;s dive into what the Strategy Design Pattern is, why it&amp;rsquo;s useful, and how you can implement it in your projects.&lt;/p&gt;
&lt;h3 id="what-is-the-strategy-design-pattern"&gt;What is the Strategy Design Pattern?&lt;a class="anchor ms-1" href="#what-is-the-strategy-design-pattern" aria-label="Permalink: What is the Strategy Design Pattern?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Strategy Design Pattern falls under the category of behavioural design patterns. It enables an algorithm&amp;rsquo;s behaviour to be selected at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.&lt;/p&gt;
&lt;h3 id="why-use-the-strategy-design-pattern"&gt;Why Use the Strategy Design Pattern?&lt;a class="anchor ms-1" href="#why-use-the-strategy-design-pattern" aria-label="Permalink: Why Use the Strategy Design Pattern?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The primary benefits of using the Strategy Design Pattern include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: It allows you to change the algorithm or strategy being used without altering the code that uses the algorithm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reusability&lt;/strong&gt;: By encapsulating algorithms separately, you can reuse them across different parts of your application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;: It promotes cleaner code by adhering to the Single Responsibility Principle, making your code easier to maintain and extend.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="how-to-implement-the-strategy-design-pattern"&gt;How to Implement the Strategy Design Pattern&lt;a class="anchor ms-1" href="#how-to-implement-the-strategy-design-pattern" aria-label="Permalink: How to Implement the Strategy Design Pattern"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s break down the implementation of the Strategy Design Pattern with a simple example. Suppose we are developing a flight simulator that supports multiple flying methods (e.g., Flapping like a bird, Jet Engine powered, and Warp Speed).&lt;/p&gt;
&lt;h4 id="step-1-define-the-strategy-interface"&gt;Step 1: Define the Strategy Interface&lt;a class="anchor ms-1" href="#step-1-define-the-strategy-interface" aria-label="Permalink: Step 1: Define the Strategy Interface"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;First, we define an interface that all payment strategies will implement.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;IFlyingStrategy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Fly();
&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;h4 id="step-2-implement-concrete-strategies"&gt;Step 2: Implement Concrete Strategies&lt;a class="anchor ms-1" href="#step-2-implement-concrete-strategies" aria-label="Permalink: Step 2: Implement Concrete Strategies"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Next, we create concrete classes that implement the IPaymentStrategy interface.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Bird&lt;/span&gt; : IFlyingStrategy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Fly()
&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; Console.WriteLine(&lt;span style="color:#e6db74"&gt;&amp;#34;Flying like a bird&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Plane&lt;/span&gt; : IFlyingStrategy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Fly()
&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; Console.WriteLine(&lt;span style="color:#e6db74"&gt;&amp;#34;Flying using 21st century aviation fuel&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StarShip&lt;/span&gt; : IFlyingStrategy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Fly()
&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; Console.WriteLine(&lt;span style="color:#e6db74"&gt;&amp;#34;Flying using warp engines&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="step-3-create-the-context-class"&gt;Step 3: Create the Context Class&lt;a class="anchor ms-1" href="#step-3-create-the-context-class" aria-label="Permalink: Step 3: Create the Context Class"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The context class uses a IFlyingStrategy to perform the payment.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;FlyContext&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; IFlyingStrategy _flyingStrategy;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; SetPaymentStrategy(IFlyingStrategy flyingStrategy)
&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; _flyingStrategy = flyingStrategy;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Fly()
&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; _flyingStrategy.Fly();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="step-4-use-the-strategy-pattern"&gt;Step 4: Use the Strategy Pattern&lt;a class="anchor ms-1" href="#step-4-use-the-strategy-pattern" aria-label="Permalink: Step 4: Use the Strategy Pattern"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Finally, we use the FlyContext to fly with different strategies.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Main(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;[] args)
&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; FlyContext context = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; FlyContext();
&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; context.SetPaymentStrategy(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; StarShip());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.Fly();
&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; context.SetPaymentStrategy(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Plane());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.Fly();
&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; context.SetPaymentStrategy(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Bird());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.Fly();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Strategy Design Pattern is a powerful tool that promotes flexibility, reusability, and maintainability in your code. By encapsulating algorithms and making them interchangeable, you can easily extend and modify your application without disrupting existing functionality. Whether you’re dealing with payment processing, flying machines, sorting algorithms, or any other scenario requiring dynamic behaviour, the Strategy Design Pattern can help you write cleaner and more efficient code.&lt;/p&gt;</description></item><item><title>How to start a code club for kids</title><link>https://blog-test.funkysi1701.com/posts/2024/codeclub/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 02 Nov 2024 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/codeclub/</guid><category term="youth">youth</category><category term="codeclub">codeclub</category><category term="Community">Community</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/Pnb-NvNJ_400x400.jpg"/><description>&lt;p&gt;Code Clubs are free, welcoming spaces designed to introduce young people to the exciting world of programming and digital skills. Today, I had the pleasure of taking my son—an absolute coding enthusiast—to one of these sessions, held at Leeds Central Library.&lt;/p&gt;
&lt;p&gt;The club was hosted in a cozy room on the top floor of the library. Walking in, I expected rows of computers set up for traditional coding exercises. Instead, we found mysterious white lines taped onto the floor. Curious to find out what they were for, we soon learned they were meant to guide robots that the children would be programming. The instructor handed out iPads and small spherical robots known as Spheros, and the children were tasked with programming the robots to follow the lines.&lt;/p&gt;
&lt;p&gt;The iPads were preloaded with easy-to-use software that felt familiar to those who&amp;rsquo;ve used Scratch, a popular block-based coding language. By simply dragging and dropping blocks of code, the kids controlled the robots’ movements. Each &amp;ldquo;move&amp;rdquo; block had three variables—direction, speed, and duration—that the children could adjust to guide the robot along the lines.&lt;/p&gt;
&lt;p&gt;It was a great hands-on learning experience. My son and I faced a bit of trial and error to figure out which way the robot saw as &amp;ldquo;forward,&amp;rdquo; but soon enough, our Sphero was gliding smoothly along the first line. As we went along, we added &amp;ldquo;pause&amp;rdquo; blocks between movements, which made the robot stop before changing direction, adding a nice rhythm to its journey along the lines.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Children programming Sphero robots to follow taped lines on the floor at Leeds Central Library Code Club" src="https://blog-test.funkysi1701.com/images/20241102_104220.jpg" loading="lazy"
width="854" height="384"
/&gt;
&lt;/p&gt;
&lt;p&gt;Once the main task was completed, there was time for the kids to explore other features. We experimented with different commands, making a smile or frown appear on the robot’s LED display, while others programmed their Spheros to zip around the room, flashing lights and making playful noises.&lt;/p&gt;
&lt;p&gt;The club meets every two weeks, and both my son and I left feeling thrilled with the experience. We’re already looking forward to the next session!&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in finding a Code Club near you check out &lt;a href="https://codeclub.org/en/find" target="_blank" rel="noopener noreferrer"&gt;https://codeclub.org/en/find&lt;/a&gt;
, alternatively, &lt;a href="https://codeclub.org" target="_blank" rel="noopener noreferrer"&gt;https://codeclub.org&lt;/a&gt;
has lots of resources to explain what code clubs are all about.&lt;/p&gt;</description></item><item><title>Scottish Summit 2024</title><link>https://blog-test.funkysi1701.com/posts/2024/scottishsummit/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 28 Oct 2024 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/scottishsummit/</guid><category term="Conference">Conference</category><category term="Microsoft">Microsoft</category><category term="Community">Community</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/scottishsummit.jpg"/><description>&lt;p&gt;Scottish Summit 2024 took place in Aberdeen on October 18th and 19th at the P&amp;amp;J Live Arena, and I was fortunate enough to attend.&lt;/p&gt;
&lt;h2 id="friday"&gt;Friday&lt;a class="anchor ms-1" href="#friday" aria-label="Permalink: Friday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first full day of the conference, Friday the 18th, began with the unmistakable sound of bagpipers welcoming attendees at the venue—an echo of the 2022 event that reminded us all of the conference&amp;rsquo;s Scottish roots. Registration was quick and seamless; all I needed was my QR code ticket to receive a unique lanyard made of seed paper—perfect for planting flowers in the spring.&lt;/p&gt;
&lt;p&gt;Scott Hanselman was the keynote speaker, and I spotted him mingling with other attendees. I almost asked him for a selfie but decided against it. His keynote, titled &amp;ldquo;AI: Hero or Villain,&amp;rdquo; was compelling. He demystified ChatGPT, explaining that it’s not magic but rather a product of machine learning, using mathematics to predict the next word in a sentence.&lt;/p&gt;
&lt;p&gt;Next, MVP Vesa Nopanen delivered his talk on &amp;ldquo;Supercharge Your Teams Meetings.&amp;rdquo; I picked up some valuable tips, particularly the importance of adding notes and agendas to enhance meeting effectiveness.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog-test.funkysi1701.com/images/GaKpRZ3WIAAFsIW.jpg" style="padding-right: 7px; float: left; margin-bottom: 0.5rem;" alt="Scottish Summit organizers presenting how they built event registration and payments with Stripe and Power Platform" /&gt; Following that, a couple of the Scottish Summit organizers discussed the technology behind the event. They explained how they used Stripe for payments, integrating it with Power Automate and Power Pages. I found this particularly interesting for a charity event; it demonstrated a commitment to learning while keeping costs manageable.&lt;/p&gt;
&lt;p&gt;The next session explored what it means to be a modern full-stack software developer, focusing on integrating Power Apps with traditional web development. As someone new to Power Apps, I learned that starting with it can be beneficial, filling gaps with .NET or conventional web development as needed.&lt;/p&gt;
&lt;p&gt;I then attended a session on public speaking. Although I’ve never given a talk at a conference, hearing about others&amp;rsquo; journeys was encouraging and prompted me to consider my own potential in this area.&lt;/p&gt;
&lt;p&gt;The final session of Friday featured Microsoft’s Sarah Lean, who shared how her hobbies—specifically curling—have influenced her work life. This talk made me reflect on my own hobbies and their impact on my professional journey.&lt;/p&gt;
&lt;p&gt;The evening wrapped up with a drag cabaret, which exceeded my expectations. Several brave community members dressed up and participated in the show, all in support of the conference&amp;rsquo;s charity, TIE.&lt;/p&gt;
&lt;h2 id="saturday"&gt;Saturday&lt;a class="anchor ms-1" href="#saturday" aria-label="Permalink: Saturday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Saturday kicked off with a dive into the world of wizards and D&amp;amp;D in a session titled &amp;ldquo;Securing the Realm: DM-less D&amp;amp;D with Azure AI.&amp;rdquo; This practical talk demonstrated how AI can be utilized in running D&amp;amp;D games, discussing essential guardrails and effective AI prompts.&lt;/p&gt;
&lt;p&gt;Another engaging talk, &amp;ldquo;Community - It Just Makes Sense,&amp;rdquo; highlighted the tech community&amp;rsquo;s role in career development. I realized that I’ve only just scratched the surface of community involvement, and I’m eager to explore it further.&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/GaP4xTOW0AA6VHI.jpg" style="padding-left: 7px; float: right; margin-bottom: 0.5rem;" alt="Speaker presenting at Scottish Summit 2024" /&gt;
&lt;p&gt;Sarah Lean returned to discuss KQL (Kusto Query Language), which Application Insights uses for querying data. Although I&amp;rsquo;ve encountered KQL before, learning more about it was fascinating.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;Ask the Azure Experts&amp;rdquo; panel featured four Azure MVPs and Sarah Lean, who answered questions about Azure migration and cost management, sharing numerous helpful insights.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Who&amp;rsquo;s Afraid of a Little Ole Copilot?&amp;rdquo; presented by Dona Sarkar and her colleagues, was a captivating exploration of how Copilots function within the Microsoft ecosystem. It featured various speakers I had encountered throughout the conference, demonstrating the interactivity of Microsoft’s services, from Purview to Responsible AI. It was a fun and enlightening way to close the conference.&lt;/p&gt;
&lt;p&gt;Saturday evening featured a pub quiz and the UK Community Awards ceremony, where dedicated community members were recognized for their hard work. Our quiz team, led by MVP Vesa Nopanen and humorously named &amp;ldquo;Vogon Poets,&amp;rdquo; finished 14th—complete with silly hats. It was a delightful opportunity to socialize with teammates and was one of the highlights of the conference.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In summary, Scottish Summit 2024 was an exceptionally well-organized conference. As a .NET developer, I found a limited number of directly relevant sessions, but the true value lay in the community. I reconnected with familiar faces and met new friends, especially during the pub quiz.&lt;/p&gt;
&lt;p&gt;I left feeling inspired to become more involved in the community and participate in future events. The sessions on public speaking, community engagement, and hobbies underscored the importance of soft skills in the tech world.&lt;/p&gt;
&lt;p&gt;And yes, I caught a glimpse of Scott Hanselman, which was quite a thrill!&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/GaKSNJeXwAA-xyr.jpg" style="padding-right: 7px; float: left; margin-bottom: 0.5rem;" alt="Scott Hanselman at Scottish Summit 2024" /&gt;</description></item><item><title>Funky Si walks a half marathon</title><link>https://blog-test.funkysi1701.com/posts/2024/charity-hike/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 18 Feb 2024 11:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/charity-hike/</guid><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/fsi-hike.jpg"/><description>&lt;p&gt;On June 8th I will walk 13 miles near Bakewell in the Peak District to raise £250 (or more) for Cancer Research. To sponsor me click &lt;a href="https://fundraise.cancerresearchuk.org/page/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;fundraise.cancerresearchuk.org/page/funkysi1701&lt;/a&gt;
, to find out more about the event go &lt;a href="https://www.cancerresearchuk.org/get-involved/find-an-event/big-hike/big-hike-peak-district" target="_blank" rel="noopener noreferrer"&gt;www.cancerresearchuk.org/get-involved/find-an-event/big-hike/big-hike-peak-district&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="so-why-am-i-doing-this"&gt;So why am I doing this?&lt;a class="anchor ms-1" href="#so-why-am-i-doing-this" aria-label="Permalink: So why am I doing this?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/fsi-hike-route.png" alt="Hike Route" width="400px" style="float:left;padding-right:8px" /&gt;
I am a Software Developer in my day to day life, which does not involve a lot of physical activity. I have become very lazy. Doing a half marathon is completely outside of my comfort zone and is not at all a me thing to do.
&lt;p&gt;However last year I realised my mental health was starting to degrade. I have a family which keeps me very busy, I am facing lots of challenges with this, other members of my family have mental health issues which is starting to have a knock on affect on me.&lt;/p&gt;
&lt;p&gt;I mentioned some of these challenges to a friend who suggested I join a walking group which was helping people with mental health problems. I went along and to my surprise I really enjoyed myself, the people were friendly and I enjoyed the walk in the countryside. After this I went out and bought some proper walking shoes&lt;/p&gt;
&lt;p&gt;I went to the next one, and the next one and each time I enjoyed myself. I must admit that after these walks it tired me out due to my unfit nature, but it was worth it as for a few hours I wasn&amp;rsquo;t thinking about the 101 problems that I had no solutions for.&lt;/p&gt;
&lt;p&gt;Fast forward to about a week ago, an advert for this charity walk popped up on facebook. I took a look at it and I started thinking. The 10k was a similar distance I had done on one of my walks, so I could easily do that. What if I could raise some money for a charity and go for a fun walk? For the next few days I kept thinking about it. Eventually I booked it. My thinking was if I am going to do something for charity I need to push myself outside of my comfort zone. I would never manage a full marathon, but what about a half marathon?&lt;/p&gt;
&lt;p&gt;So tomorrow I start training, every day or so I walk for about 40 minutes, I will probably post some updates on my &lt;a href="https://fundraise.cancerresearchuk.org/page/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;charity page&lt;/a&gt;
as no doubt I will struggle to keep going.&lt;/p&gt;
&lt;p&gt;Please if you can think about donating, and give me some encouragement I think I am going to need it.&lt;/p&gt;</description></item><item><title>TrekRanks #174</title><link>https://blog-test.funkysi1701.com/posts/2024/trekranks/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 05 Jan 2024 20:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2024/trekranks/</guid><category term="StarTrek">StarTrek</category><category term="Podcast">Podcast</category><category term="TrekRanks">TrekRanks</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/TrekRanks-ep174.jpg"/><description>&lt;h2 id="trek-ranks-174-top-5-ensemble-episodes"&gt;Trek Ranks #174: Top 5 Ensemble Episodes&lt;a class="anchor ms-1" href="#trek-ranks-174-top-5-ensemble-episodes" aria-label="Permalink: Trek Ranks #174: Top 5 Ensemble Episodes"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was recently invited onto the &lt;a href="https://www.trekranks.com/" target="_blank" rel="noopener noreferrer"&gt;TrekRanks&lt;/a&gt;
podcast. I had a great time talking Trek with Jim Moorhouse and fellow guest Anika Dane. If Trek is your thing, do take a listen.&lt;/p&gt;
&lt;p&gt;Everyone contributes in this episode of TrekRanks as we break down the &amp;ldquo;Top 5 Ensemble Episodes.&amp;rdquo; Our panel highlight those episodes in which the entire cast play important roles and help portray the group as a whole, rather than as individuals. From heavy hitters to deep cuts and everything in between, this one quite appropriately covers it all.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.thetricordertransmissions.com/episode.php?ep=TR174" target="_blank" rel="noopener noreferrer"&gt;Listen here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="TrekRanks episode 174 artwork for Top 5 Ensemble Episodes with Jim Moorhouse, Anika Dane and Simon Foster" src="https://blog-test.funkysi1701.com/images/TrekRanks-ep174.jpg" loading="lazy"
width="1920" height="1080"
/&gt;
&lt;/p&gt;</description></item><item><title>Events 2024</title><link>https://blog-test.funkysi1701.com/posts/events/2024/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 2024 01:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/events/2024/</guid><description>&lt;h2 id="2024"&gt;2024&lt;a class="anchor ms-1" href="#2024" aria-label="Permalink: 2024"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Talk&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Yorkshire Azure&lt;/td&gt;
&lt;td&gt;19 November 2024&lt;/td&gt;
&lt;td&gt;York&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Club&lt;/td&gt;
&lt;td&gt;16 November 2024&lt;/td&gt;
&lt;td&gt;Leeds Library&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/codeclub"&gt;Code Club&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;2 November 2024&lt;/td&gt;
&lt;td&gt;Leeds Library&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scottish Summit&lt;/td&gt;
&lt;td&gt;17-19 October 2024&lt;/td&gt;
&lt;td&gt;Aberdeen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DDD North&lt;/td&gt;
&lt;td&gt;2 March 2024&lt;/td&gt;
&lt;td&gt;Hull&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description></item><item><title>Make API calls from Visual Studio</title><link>https://blog-test.funkysi1701.com/posts/2023/make-api-calls-from-visual-studio/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 19 Nov 2023 22:50:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2023/make-api-calls-from-visual-studio/</guid><category term="VisualStudio">VisualStudio</category><category term="API">API</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/endpoint-explorer.png"/><description>&lt;p&gt;It is that exciting time of year where Microsoft announce a new version of .Net (Version 8 this time) and Visual Studio. There have been lots of announcements which I am still digesting, but one that caught my eye was a new window in Visual Studio that shows all your API endpoints.&lt;/p&gt;
&lt;p&gt;The new window is called &lt;strong&gt;Endpoint Explorer&lt;/strong&gt; and can be added from the menu &lt;strong&gt;View &amp;gt; Other Windows &amp;gt; Endpoint Explorer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Endpoint Explorer" src="https://blog-test.funkysi1701.com/images/endpoint-explorer.png" loading="lazy"
width="400" height="434"
/&gt;
&lt;/p&gt;
&lt;p&gt;If you right click on one of the endpoints you can view the code or send a request. It works with minimal APIs or standard MVC APIs. If you select send a request a .http file will be created, this is a feature that has been in Visual Studio for a while but I haven&amp;rsquo;t taken much notice.&lt;/p&gt;
&lt;p&gt;The syntax for writing these API calls is fairly simple&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;GET {{Catalog.API_HostAddress}}/api/v1/catalog/items
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or something more complex, this one is a POST with a body and a header. This is how you might call APIs which require authentication. Just include a header with your auth token.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;POST {{Catalog.API_HostAddress}}/api/v1/catalog/items
Accept: application/json
{
&amp;#34;name&amp;#34;: &amp;#34;Test&amp;#34;,
&amp;#34;description&amp;#34;: &amp;#34;Test&amp;#34;,
&amp;#34;price&amp;#34;: 1.99,
&amp;#34;pictureFileName&amp;#34;: &amp;#34;test.png&amp;#34;,
&amp;#34;pictureUri&amp;#34;: &amp;#34;https://picsum.photos/200/300&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can also set up various variables at the top of your .http files by prefixing with an @, by default you get one that defines your base URL, but you can add more.&lt;/p&gt;
&lt;p&gt;eg @variable = value&lt;/p&gt;
&lt;p&gt;Full docs of how you use .http files can be found &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/test/http-files?view=aspnetcore-8.0" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A hyperlink above each API call in your .http file is labelled Send request. This initiates the API call and your window splits in half with the right hand side displaying the response.&lt;/p&gt;
&lt;p&gt;The response has four tabs, a nicely json formatted response, a raw response, a headers tab and a request tab.&lt;/p&gt;
&lt;p&gt;Now you will notice an env box underneath your file tabs, where the method dropdown is in a normal c# class file. It took me a while to figure out how to setup environments, but you can add a file that contain environment specific config, like base URL for test/prod/dev etc.&lt;/p&gt;
&lt;p&gt;This blog post tells me about it &lt;a href="https://devblogs.microsoft.com/visualstudio/safely-use-secrets-in-http-requests-in-visual-studio-2022/" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
but the main thing is you need to add a json file called &lt;strong&gt;http-client.env.json&lt;/strong&gt; and create some json like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; &amp;#34;local&amp;#34;: {
&amp;#34;Api_HostAddress&amp;#34;: &amp;#34;http://localhost:44338&amp;#34;
},
&amp;#34;dev&amp;#34;: {
&amp;#34;Api_HostAddress&amp;#34;: &amp;#34;https://dev.example.com&amp;#34;
},
&amp;#34;test&amp;#34;: {
&amp;#34;Api_HostAddress&amp;#34;: &amp;#34;https://test.example.com&amp;#34;
},
&amp;#34;prod&amp;#34;: {
&amp;#34;Api_HostAddress&amp;#34;: &amp;#34;https://prod.example.com&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Other environment specific variables can be added in the same way. Now you can easily call your API in different environments without having to change the URL each time.&lt;/p&gt;
&lt;h2 id="but-what-about-vs-code"&gt;But what about VS Code?&lt;a class="anchor ms-1" href="#but-what-about-vs-code" aria-label="Permalink: But what about VS Code?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Well it turns out that VS Code has a similar feature, but it is not enabled by default. You need to install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" target="_blank" rel="noopener noreferrer"&gt;REST Client&lt;/a&gt;
extension. Once installed you can create a .http file and start making API calls. The syntax is very similar to Visual Studio.&lt;/p&gt;
&lt;p&gt;VS Code has a similar concept of environments. Go to Extensions &amp;gt; REST Client &amp;gt; Extension Settings and click on Edit in settings.json. Add the same settings we used with VS to your settings.json file. You can now switch environments from the command palette &amp;ldquo;Rest Client: Switch Environment&amp;rdquo; and select the environment you want to use.&lt;/p&gt;
&lt;p&gt;You can make use of the response of one API call in the request of another.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;### 1st API Call
# @name login
POST {{Catalog.API_HostAddress}}/api/v1/identity/login
Content-Type: application/json
{
&amp;#34;user&amp;#34;: &amp;#34;username&amp;#34;,
&amp;#34;password&amp;#34;: &amp;#34;password&amp;#34;
}
### 2nd API Call
GET {{Catalog.API_HostAddress}}/api/v1/catalog/items
Authorization: Bearer {{login.response.body.token}}
Content-Type: application/json
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The last feature of VS Code I want to mention is that it can make GQL calls.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;POST {{Catalog.API_HostAddress}}/graphql
X-REQUEST-TYPE: GraphQL
Content-Type: application/json
Authorization: Bearer {{login.response.body.token}}
query ($name: String!, $owner: String!) {
repository(name: $name, owner: $owner) {
name
fullName: nameWithOwner
description
diskUsage
forkCount
stargazers(first: 5) {
totalCount
nodes {
login
name
}
}
watchers {
totalCount
}
}
}
{
&amp;#34;name&amp;#34;: &amp;#34;vscode-restclient&amp;#34;,
&amp;#34;owner&amp;#34;: &amp;#34;Huachao&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sorry postman but I think I have a new favourite tool for making API calls.&lt;/p&gt;</description></item><item><title>Be the best developer you can be</title><link>https://blog-test.funkysi1701.com/posts/2023/become-the-best-actor-astronaut-or-developer-you-can-be/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 03 Nov 2023 01:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2023/become-the-best-actor-astronaut-or-developer-you-can-be/</guid><category term="StarTrek">StarTrek</category><category term="PatrickStewart">PatrickStewart</category><category term="Goals">Goals</category><category term="JoseHernandez">JoseHernandez</category><category term="continuousimprovement">continuousimprovement</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/patrick-stewart.jpg"/><description>&lt;img src="https://blog-test.funkysi1701.com/images/patrick-stewart.jpg" width="400px" style="float:left;padding-right:8px" alt="Patrick Stewart" /&gt;
&lt;p&gt;Recently I have been reading the first few chapters of Patrick Stewart&amp;rsquo;s Memoir, &lt;a href="https://www.amazon.co.uk/Making-It-So-A-Memoir/dp/B0C3VXDSGR/ref=sr_1_1" target="_blank" rel="noopener noreferrer"&gt;Making It So: A Memoir&lt;/a&gt;
. In it he tells the story of his early life. I find it fascinating that very early on it is quite clear he had a life goal. Become the best actor Patrick Stewart can be.&lt;/p&gt;
&lt;p&gt;Yes, there are other things in his life but this is what motivates much of what he does. At 12 he went on an 8 day residential drama course, where he met with like minded people that encourage him. So much that he continued to meet with them years after that course finished to grow his skills as an actor. This is something I would encourage everyone to do, find your tribe, find like minded people that will encourage you to grow and learn.&lt;/p&gt;
&lt;p&gt;After school he couldn&amp;rsquo;t see a future in acting professionally so took a job at a newspaper.  However when his job interfered with his acting in amateur dramatic groups, it caused him to reassess his priorities and he began saving to go to drama school. While at drama school he continued to improve and grow his acting skills. He has a singular vision in these early years to become an actor, and within a few weeks of finishing his training he had a job as an actor at a theatre. I have got up to the point where he is about to go on a world tour with a theatre group. During his first few jobs he continues to work on his acting skills. There is no doubt in my mind that this sense of continuous improvement helped mold Patrick Stewart into the actor we know today. While I am not a actor, I often think about continuous improvement, how can I be better at what I do.&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/million-miles.jpg" width="400px" style="float:right;padding-left:8px" alt="Promotional still from the film A Million Miles Away" /&gt;
&lt;p&gt;A film I saw recently has a similar tale of a singular vision. &lt;a href="https://www.amazon.co.uk/Million-Miles-Away-Michael-Pe%C3%B1a/dp/B0CC7MQFVD/ref=sr_1_1" target="_blank" rel="noopener noreferrer"&gt;A Million Miles Away&lt;/a&gt;
tells the story of Jose Hernandez, a man that wanted to be an Astronaut and applied to NASA 12 times (he was rejected 11 times!) He started life as a migrant farm worker, (so similar to Patrick Stewart who also grew up in poverty). He did everything in his power to achieve his goals, and didn&amp;rsquo;t give up.&lt;/p&gt;
&lt;p&gt;Jose Hernandez, when facing failure looked at those that had got into NASA. What did they have that he didn&amp;rsquo;t? He then worked on those areas to improve himself. He didn&amp;rsquo;t give up, he kept going. He works on his fitness, he got a pilots license, he learns Russian.&lt;/p&gt;
&lt;p&gt;So what&amp;rsquo;s my point. Have a Big Goal. It can be anything but it needs to be &lt;strong&gt;big&lt;/strong&gt;. My big goal of becoming a developer was achieved many years ago, and since then I have done a fair amount of drifting through life. What I need to do is be more like Patrick Stewart and continue to improve my skills, everyday make myself a better developer. What problems am I facing, lets break them down into manageable goals and get them solved so I can move on to the next lot.&lt;/p&gt;</description></item><item><title>DDD East Midlands</title><link>https://blog-test.funkysi1701.com/posts/2023/ddd-east-midlands/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 09 Oct 2023 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2023/ddd-east-midlands/</guid><category term="DotNet">DotNet</category><category term="Community">Community</category><category term="Conference">Conference</category><category term="DDDEastMidlands">DDDEastMidlands</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/ddd_avatar_300.jpg"/><description>&lt;p&gt;On Saturday 7th October I attended &lt;a href="https://dddeastmidlands.com/" target="_blank" rel="noopener noreferrer"&gt;DDD East Midlands&lt;/a&gt;
. It is a community run conference for Developers (the D&amp;rsquo;s stand for Developer) and I had a great time, I have been to DDD North before but this was the first time going to Nottingham for a conference (I grew up in Nottingham, or a town not far from). As I have said before there is nothing quite like chatting over coffee or lunch with fellow Developers about the tech you are learning about, this was probably my favourite thing about conferences. Now on to the talks:&lt;/p&gt;
&lt;h2 id="dungeons-dragons-and-developers"&gt;Dungeons, Dragons and Developers&lt;a class="anchor ms-1" href="#dungeons-dragons-and-developers" aria-label="Permalink: Dungeons, Dragons and Developers"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/Brunty" target="_blank" rel="noopener noreferrer"&gt;Matt Brunt&lt;/a&gt;
gave an excellent keynote talk, comparing the role playing game Dungeons and Dragons with working on Software projects. A good D&amp;amp;D game involves team work, very like a good Software Team. A team of all wizards isn&amp;rsquo;t going to get you very far, the same way a team full of developers that excel at algorithms, won&amp;rsquo;t be good at testing, talking to customers etc. A wizard that has a secret spell to defeat the Troll under the bridge, is almost as bad as a developer that hordes his knowledge and &amp;ldquo;saves the day&amp;rdquo; when things go wrong. Keeping connected with your team as you go out on your quest so no one gets lost is as important as keeping connected with your software team.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Matt Brunt delivering the Dungeons, Dragons and Developers keynote at DDD East Midlands" src="https://blog-test.funkysi1701.com/images/F701q6xXEAAgZk3.jpg" loading="lazy"
width="680" height="510"
/&gt;
&lt;/p&gt;
&lt;h2 id="microservice-mistakes"&gt;Microservice Mistakes&lt;a class="anchor ms-1" href="#microservice-mistakes" aria-label="Permalink: Microservice Mistakes"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/DoesDotNet" target="_blank" rel="noopener noreferrer"&gt;Matt Hunt&lt;/a&gt;
talked about microservice mistakes he had made.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Long lived small teams&lt;/li&gt;
&lt;li&gt;Can&amp;rsquo;t test by &lt;strong&gt;only&lt;/strong&gt; interacting with the frontend&lt;/li&gt;
&lt;li&gt;Use events as well as API calls&lt;/li&gt;
&lt;li&gt;Need to be able to deploy independently of each other&lt;/li&gt;
&lt;li&gt;Have a specific reason for using microservices, a problem to solve&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-art-of-the-bad-code-review"&gt;The Art of the Bad Code Review&lt;a class="anchor ms-1" href="#the-art-of-the-bad-code-review" aria-label="Permalink: The Art of the Bad Code Review"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A 15 minute lightning talk with &lt;a href="https://twitter.com/makitdev" target="_blank" rel="noopener noreferrer"&gt;Martyn Kilbryde&lt;/a&gt;
A fun talk showing some examples of bad code reviews, a few takeaways from this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Explain what is being fixed with a link to the ticket&lt;/li&gt;
&lt;li&gt;Give specific, actionable feedback&lt;/li&gt;
&lt;li&gt;Balance the boy scout rule of leaving the code better than when you found it with do one thing rule&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t make assumptions -&amp;gt; have a conversation instead&lt;/li&gt;
&lt;li&gt;Be helpful and constructive, not dismissive and negative&lt;/li&gt;
&lt;li&gt;Use a branch per ticket, don&amp;rsquo;t tie them together&lt;/li&gt;
&lt;li&gt;Refer to the requirements&lt;/li&gt;
&lt;li&gt;No room for ego, code belongs to the team not an individual&lt;/li&gt;
&lt;li&gt;Avoid overly verbose comments&lt;/li&gt;
&lt;li&gt;Pragmatism is important&lt;/li&gt;
&lt;li&gt;If urgent, raise additional tickets with tech debt issues&lt;/li&gt;
&lt;li&gt;Challenge if necessary, but do so respectfully&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t do a piecemeal review&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="git-under-the-covers"&gt;Git Under the covers&lt;a class="anchor ms-1" href="#git-under-the-covers" aria-label="Permalink: Git Under the covers"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another 15 minute lightning talk with &lt;a href="https://twitter.com/dracan" target="_blank" rel="noopener noreferrer"&gt;Dan Clarke&lt;/a&gt;
This looked at the inner workings of git, this was fascinating as every part points at another part which is obviously part of the reason git is so powerful. It was quite technical and I am sure some of it went over my head.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Dan Clarke presenting the Git Under the Covers lightning talk at DDD East Midlands" src="https://blog-test.funkysi1701.com/images/F71PCBEXsAA4_aJ.jpg" loading="lazy"
width="1639" height="864"
/&gt;
&lt;/p&gt;
&lt;h2 id="this-talk-could-have-been-a-blog-post"&gt;This talk could have been a blog post&lt;a class="anchor ms-1" href="#this-talk-could-have-been-a-blog-post" aria-label="Permalink: This talk could have been a blog post"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another 15 minute lightning talk with &lt;a href="https://twitter.com/JamieTanna" target="_blank" rel="noopener noreferrer"&gt;Jamie Tanna&lt;/a&gt;
. This was a good talk about the importance of blogging. He used the phrase &lt;strong&gt;blogumentation&lt;/strong&gt;, now I have heard of this before but not its name. It is where you use your blog to document what you have learnt, it can be anything a new command or a new language or technology. This talk inspired me to write this blog post, Thank you Jamie. His blog can be found at &lt;a href="https://www.jvt.me/posts/2023/10/07/why-blog/" target="_blank" rel="noopener noreferrer"&gt;https://www.jvt.me/posts/2023/10/07/why-blog/&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="how-to-create-the-conditions-where-happy-people-do-their-best-work"&gt;How to create the conditions where happy people do their best work&lt;a class="anchor ms-1" href="#how-to-create-the-conditions-where-happy-people-do-their-best-work" aria-label="Permalink: How to create the conditions where happy people do their best work"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/paul_bailey_" target="_blank" rel="noopener noreferrer"&gt;Paul Bailey&lt;/a&gt;
introduced the concept of Communities of Practice. Lots of the features of a Community of Practice I have heard of or been in teams that implement. &lt;em&gt;&amp;ldquo;Communities of Practice are groups of people who share a concern or passion for something they do and learn how to do it better as they interact regularly&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Paul Bailey speaking on creating conditions where happy people do their best work at DDD East Midlands" src="https://blog-test.funkysi1701.com/images/F71n4uiWYAA4KHL.jpg" loading="lazy"
width="2048" height="1536"
/&gt;
&lt;/p&gt;
&lt;h2 id="building-robots-for-complete-beginners"&gt;Building Robots for Complete Beginners&lt;a class="anchor ms-1" href="#building-robots-for-complete-beginners" aria-label="Permalink: Building Robots for Complete Beginners"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last talk of the day was my favourite (because it was about Robots) &lt;a href="https://www.linkedin.com/in/mark4security/" target="_blank" rel="noopener noreferrer"&gt;Mark Goodwin&lt;/a&gt;
talked about building Robots using Rasbery Pi Pico (a microcontroller board), most of his examples used python. His demo can be found at &lt;a href="https://github.com/computerist/robot-demos" target="_blank" rel="noopener noreferrer"&gt;https://github.com/computerist/robot-demos&lt;/a&gt;
This fascinated me as I have already dipped my toe into this area when playing with &lt;a href="https://blog-test.funkysi1701.com/posts/2022/microbit/"&gt;microbits&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Picard Season 3</title><link>https://blog-test.funkysi1701.com/posts/2023/picard-season-three/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 23 Feb 2023 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2023/picard-season-three/</guid><category term="StarTrek">StarTrek</category><category term="Podcast">Podcast</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/nexus-nights.jpg"/><description>&lt;p&gt;Last night I had a bit of a chat about season 3 of Star Trek Picard.&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Before &lt;a href="https://twitter.com/hashtag/startrek?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#startrek&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/Picard?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#Picard&lt;/a&gt; S3ep2 airs this week; &lt;a href="https://twitter.com/danielhuckfield?ref_src=twsrc%5Etfw"&gt;@danielhuckfield&lt;/a&gt; Special Guest &lt;a href="https://twitter.com/funkysi1701?ref_src=twsrc%5Etfw"&gt;@funkysi1701&lt;/a&gt; and &lt;a href="https://twitter.com/hitch_daniel?ref_src=twsrc%5Etfw"&gt;@hitch_daniel&lt;/a&gt; chat about the first episode on the Nexus Nights spin-off show.&lt;a href="https://t.co/Jyov53z7hC"&gt;https://t.co/Jyov53z7hC&lt;/a&gt;&lt;/p&gt;&amp;mdash; The Temporal Trek Podcast(s) (@rider_coattail) &lt;a href="https://twitter.com/rider_coattail/status/1628713326149570563?ref_src=twsrc%5Etfw"&gt;February 23, 2023&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;Here is the episode I recorded: &lt;a href="https://podcasters.spotify.com/pod/show/daniel-peter-hitch/episodes/TTNN-Ep-36---PIC-S3ep1-Reaction-Chat-e1vdglo" target="_blank" rel="noopener noreferrer"&gt;TTNN Ep 36 - PIC S3ep1 Reaction Chat&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Dan and Dan are joined by previous Temporal Trek guest Si Foster for a little chinwag over the return of PICARD for the final season.&lt;/p&gt;
&lt;p&gt;Badass Bev, Starships of Thesseus, love to loathe Captain Shaw, Predictions and More.&lt;/p&gt;
&lt;p&gt;It was great fun to record and I hope you enjoy giving it a listen., Hopefully I will be back at the end of the season to discuss the conclusion.&lt;/p&gt;</description></item><item><title>How much does it cost?</title><link>https://blog-test.funkysi1701.com/posts/2023/how-much-does-it-cost/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 04 Feb 2023 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2023/how-much-does-it-cost/</guid><category term="Azure">Azure</category><category term="Website">Website</category><category term="SideProject">SideProject</category><category term="Costs">Costs</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/monthly-costs.png"/><description>&lt;p&gt;How much does it Cost to run my side projects? This is going to be an interesting look at my spending, hopefully it can show you can do a lot without breaking the bank!&lt;/p&gt;
&lt;p&gt;I have a personal Azure subscription that I pay for myself. I don&amp;rsquo;t use anything connected to my work, as jobs change and I don&amp;rsquo;t want to have to shift stuff if I change employers (which happened quite recently). I like Azure, and I like learning what I can do with it, so spending small amounts on a personal subscription is not a problem for me.&lt;/p&gt;
&lt;p&gt;This is how much Azure is costing me daily, I like to keep an eye on this chart fairly often so I can see if I get any increases, especially if I have added a new service.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Azure Cost Analysis chart showing daily spend on a personal subscription" src="https://blog-test.funkysi1701.com/images/daily-costs.png" loading="lazy"
width="1204" height="780"
/&gt;
&lt;/p&gt;
&lt;p&gt;This is my monthly charges over the last few months. In Sept/Oct I switched from CosmosDB to Mongo DB Atlas as my database backend. Experience has told me that my biggest charge is data storage, websites are cheap but any database or storage is what tends to cost the most.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Azure Cost Analysis chart of monthly charges over recent months, including the CosmosDB to MongoDB Atlas switch" src="https://blog-test.funkysi1701.com/images/monthly-costs.png" loading="lazy"
width="1206" height="748"
/&gt;
&lt;/p&gt;
&lt;p&gt;This website you are reading this on (assuming you are not on DevTo or Hashnode) is running Hugo which runs on an Azure Static Web App, the free tier so almost free. I have two of these, a production one and a test one. Source code is on Github (another free service), and auto deploys via Github actions. I have a load of images which I have stuffed in blob storage from when I used to run a wordpress site, the cost for file storage is minimal.&lt;/p&gt;
&lt;p&gt;I also have a service I built using Azure Functions and Static Web Apps which makes use of public APIs like (Twitter/Mastodon/GitHub etc), data for this is stored in the free tier of Mongo DB Atlas. I then use consumption tier Azure Functions and Free Static Web App to do stuff. The definition of what I have deployed is all setup in Pulumi, so I have identical environments for Dev/Test/Prod mostly because I can rather than it being business critical or getting a lot of traffic.&lt;/p&gt;
&lt;p&gt;I currently have 240Mb of data in my free MongoDb database, I have 512 Mb max storage to play with. I have plenty of data to play with at this tier, but I may investigate other options that involve storing less or what costs might be. I previously made use of cosmosDB, which was costing me between £10-£20 per month, so not breaking the bank, but also cheaper to use MongoDB.&lt;/p&gt;
&lt;p&gt;Interrogating the Azure Cost Analysis tool reveals that my biggest cost is file storage (67p Prod, 101p Test and 93p Dev), I may investigate this a bit and see what is using this, but its not breaking the bank so I am pretty happy.&lt;/p&gt;
&lt;p&gt;So what else does it cost to run my things?&lt;/p&gt;
&lt;p&gt;My domains live on CloudFlare, I recently got a bill for £8.04 for a couple of renewals for the next 12 months. But I am struggling to think what else costs me to run my digital things.&lt;/p&gt;</description></item><item><title>Podcasts I have been listening to</title><link>https://blog-test.funkysi1701.com/posts/2023/what-have-i-been-listening-to-week2/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 23 Jan 2023 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2023/what-have-i-been-listening-to-week2/</guid><category term="Podcast">Podcast</category><category term="Leadership">Leadership</category><category term="OpenSource">OpenSource</category><category term="StarTrek">StarTrek</category><category term="Mastodon">Mastodon</category><category term="Tests">Tests</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/872.jpg"/><description>&lt;p&gt;Another week has gone by so here is a rundown of my podcasts listenings&amp;hellip;&lt;/p&gt;
&lt;h2 id="hachyderms-kris-nova-on-running-a-mastodon-server"&gt;Hachyderm’s Kris Nova on running a Mastodon Server&lt;a class="anchor ms-1" href="#hachyderms-kris-nova-on-running-a-mastodon-server" aria-label="Permalink: Hachyderm’s Kris Nova on running a Mastodon Server"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://hanselminutes.com/872/hachyderms-kris-nova-on-running-a-mastodon-server" target="_blank" rel="noopener noreferrer"&gt;Hanselminutes episode 871&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A great chat about how Hachderm grew as people moved from Twitter to Mastodon. You can find me on Hachyderm &lt;a href="https://hachyderm.io/@funkysi1701" target="_blank" rel="noopener noreferrer"&gt;https://hachyderm.io/@funkysi1701&lt;/a&gt;
Hachyderm saw amazing growth in a short space of time, so great to hear how that impacted the service, which Kris Nova provides for free in her own time.&lt;/p&gt;
&lt;h2 id="the-shipment"&gt;The Shipment&lt;a class="anchor ms-1" href="#the-shipment" aria-label="Permalink: The Shipment"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://podcasts.apple.com/gb/podcast/the-temporal-trek-podcast-season-3-episode-59-the-shipment/id1499160640?i=1000591042656" target="_blank" rel="noopener noreferrer"&gt;The Temporal Trek Season 3 episode 58&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;DanDan discuss the season 3 episode The Shipment, which sees Enterprise season 3 back on track, with a proper Star Trek story. But I can&amp;rsquo;t believe Dan forgot to include the DanDan jingle its why I tune in each week.&lt;/p&gt;
&lt;h2 id="trekranks-potpouri"&gt;TrekRanks Potpouri&lt;a class="anchor ms-1" href="#trekranks-potpouri" aria-label="Permalink: TrekRanks Potpouri"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.trekranks.com/trekranks-podcast" target="_blank" rel="noopener noreferrer"&gt;TrekRanks episode 150&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This was a great show celebrating 150 shows, and was a lucky dip into all the 149 topics that have been chosen before. Jim was caught out by the guests this week as they went above and beyond finding answers for all possible shows that could be picked. As always some great picks reminding me why I love the show.&lt;/p&gt;
&lt;h2 id="troy-hunts-weekly-update"&gt;Troy Hunt’s Weekly Update&lt;a class="anchor ms-1" href="#troy-hunts-weekly-update" aria-label="Permalink: Troy Hunt’s Weekly Update"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.troyhunt.com/weekly-update-327/" target="_blank" rel="noopener noreferrer"&gt;Weekly Update 327&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I like listening to what Troy has been up to in the last week. (I am a bit behind as this show came out at Christmas time) Troy talks about Twitter and Elon Musk, and the LastPass data breach. I am a big fan of 1Password for my password manager but my employer uses LastPass&lt;/p&gt;
&lt;h2 id="troy-vinson-learning-from-the-rackspace-security-breach"&gt;Troy Vinson: Learning From the Rackspace Security Breach&lt;a class="anchor ms-1" href="#troy-vinson-learning-from-the-rackspace-security-breach" aria-label="Permalink: Troy Vinson: Learning From the Rackspace Security Breach"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=MsK5zaUogJ4" target="_blank" rel="noopener noreferrer"&gt;Azure DevOps Podcast Episode 225&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;An interesting look at security and the recent rackspace incident. I used to be a big fan of Rackspace but in recent years I have been more interested in cloud offerings like Azure.&lt;/p&gt;
&lt;h2 id="dr-gregory-kapfhammer-wants-to-stop-flaky-tests"&gt;Dr. Gregory Kapfhammer wants to stop flaky tests&lt;a class="anchor ms-1" href="#dr-gregory-kapfhammer-wants-to-stop-flaky-tests" aria-label="Permalink: Dr. Gregory Kapfhammer wants to stop flaky tests"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://hanselminutes.com/874/dr-gregory-kapfhammer-wants-to-stop-flaky-tests" target="_blank" rel="noopener noreferrer"&gt;Hanselminutes episode 874&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I am currently looking at fixing some flaky tests on a codebase I am not familiar with so this is a great podcast to listen to. The episode goes through common reactions to flaky tests, why tests get flaky and what to do about them.&lt;/p&gt;</description></item><item><title>What podcasts have I been listening to</title><link>https://blog-test.funkysi1701.com/posts/2023/what-have-i-been-listening-to/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 05 Jan 2023 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2023/what-have-i-been-listening-to/</guid><category term="Podcast">Podcast</category><category term="Leadership">Leadership</category><category term="OpenSource">OpenSource</category><category term="StarTrek">StarTrek</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/dotnetrocks.jpg"/><description>&lt;p&gt;I love listening to podcasts so I thought I would share what I have been listening to over the last few days.&lt;/p&gt;
&lt;h2 id="source-open-vs-open-source-and-identityserver-with-dominick-baier-and-brock-allen"&gt;Source Open vs Open Source and IdentityServer with Dominick Baier and Brock Allen&lt;a class="anchor ms-1" href="#source-open-vs-open-source-and-identityserver-with-dominick-baier-and-brock-allen" aria-label="Permalink: Source Open vs Open Source and IdentityServer with Dominick Baier and Brock Allen"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.dotnetrocks.com/details/1824" target="_blank" rel="noopener noreferrer"&gt;.Net Rocks episode 1824&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The creators of the open source project Identity Server which went commercial discuss the reasons for doing so. This was a very interesting discussion on the challenges of running open source projects and ways that they can be more maintainable. I have seen Twitter arguments on both sides about various products that have done this. It is a very nuanced problem, which I don’t know much about so interesting hearing what was involved.&lt;/p&gt;
&lt;h2 id="growing-as-an-engineering-manager-with-taylor-poindexter"&gt;Growing as an Engineering Manager with Taylor Poindexter&lt;a class="anchor ms-1" href="#growing-as-an-engineering-manager-with-taylor-poindexter" aria-label="Permalink: Growing as an Engineering Manager with Taylor Poindexter"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://hanselminutes.com/871/growing-as-an-enginering-manager-with-taylor-poindexter" target="_blank" rel="noopener noreferrer"&gt;Hanselminutes episode 871&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A discussion about being an engineering manager, mentoring and growing and learning. I am not a manager and I don’t have people that report to me, however, I am a senior developer so anything that can help me improve on the leadership side of things is great. On a side note, I love how diverse the guests are on Hanselminutes, I often listen to people on this show I would never have heard of or known about if I just stuck to topics I know about.&lt;/p&gt;
&lt;h2 id="top-5-scenes-at-a-table"&gt;Top 5 Scenes at a Table&lt;a class="anchor ms-1" href="#top-5-scenes-at-a-table" aria-label="Permalink: Top 5 Scenes at a Table"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.trekranks.com/trekranks-podcast" target="_blank" rel="noopener noreferrer"&gt;TrekRanks episode 149&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Star Trek for me has always been about positivity and Trek Ranks delivers this in spades. The concept, in case you don’t know, is to choose 5 episodes about the chosen topic, but it is really an excuse to talk about them! So what 5 scenes at a table would I choose?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Undiscovered Country - Dinner with the Klingons. Klingons, Shakespeare, terrible table manners what is not to love about this scene&lt;/li&gt;
&lt;li&gt;Q Who - Scene in the observation lounge with Q and Guinan as they discuss how to respond to the newly discovered Borg&lt;/li&gt;
&lt;li&gt;Civil Defence - Scene in Ops between Garak and Dukat while the crew hide from an automated phaser firing at them, the best bit is when Duakt tried to leave and ends up trapped with the rest of the crew&lt;/li&gt;
&lt;li&gt;Mirror, Mirror - Scene where Bones realises that some things are the same in the mirror universe, the spot where he spilt acid&lt;/li&gt;
&lt;li&gt;Unification Part 2 - Spock, Picard and Data have been captured by Sela, and Sela comments that she doesn’t get to write many speeches, and then Data comments that maybe she would be happy doing another job&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Events 2023</title><link>https://blog-test.funkysi1701.com/posts/events/2023/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 01 Jan 2023 01:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/events/2023/</guid><description>&lt;h2 id="2023"&gt;2023&lt;a class="anchor ms-1" href="#2023" aria-label="Permalink: 2023"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Talk&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DevBoss&lt;/td&gt;
&lt;td&gt;16 November 2023&lt;/td&gt;
&lt;td&gt;Leeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2023/ddd-east-midlands"&gt;DDD East Midlands&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;7 October 2023&lt;/td&gt;
&lt;td&gt;Nottingham&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SteelCon&lt;/td&gt;
&lt;td&gt;8 July 2023&lt;/td&gt;
&lt;td&gt;Sheffield&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yorkshire Azure&lt;/td&gt;
&lt;td&gt;13 June 2023&lt;/td&gt;
&lt;td&gt;Leeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevBoss&lt;/td&gt;
&lt;td&gt;20 April 2023&lt;/td&gt;
&lt;td&gt;Leeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dotnet York Machine Learning with ML.Net&lt;/td&gt;
&lt;td&gt;2 March 2023&lt;/td&gt;
&lt;td&gt;York&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description></item><item><title>2022 What Happened?</title><link>https://blog-test.funkysi1701.com/posts/2022/2022-what-happened/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 31 Dec 2022 22:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/2022-what-happened/</guid><category term="Goals">Goals</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/goals.jpeg"/><description>&lt;p&gt;As 2022 draws to a close its time to do my annual look back at what happened.&lt;/p&gt;
&lt;p&gt;I am going to talk a bit about my personal life as well as tech things, so if that is not your bag feel free to skip this post and read my more technical articles.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;January - I started the year &lt;a href="https://www.funkysi1701.com/posts/2021/back-to-basic/" target="_blank" rel="noopener noreferrer"&gt;teaching my son to code&lt;/a&gt;
.&lt;/li&gt;
&lt;li&gt;February - I did some work on my website this year, and it is now using Hugo instead of wordpress.&lt;/li&gt;
&lt;li&gt;March - I was guest on a Star Trek &lt;a href="https://www.funkysi1701.com/posts/2022/temporal-trek-podcast/" target="_blank" rel="noopener noreferrer"&gt;podcast&lt;/a&gt;
, hopefully a repeat appearance in the works very soon. I also passed an &lt;a href="https://www.funkysi1701.com/posts/2022/aws-cloud-practitioner/" target="_blank" rel="noopener noreferrer"&gt;AWS exam&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;April - Lots of work with &lt;a href="https://www.funkysi1701.com/posts/2022/scratch/" target="_blank" rel="noopener noreferrer"&gt;Scratch&lt;/a&gt;
with my boy&lt;/li&gt;
&lt;li&gt;June - &lt;a href="https://www.funkysi1701.com/posts/2022/scottishsummit/" target="_blank" rel="noopener noreferrer"&gt;Scottish Summit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;August - My boys birthday so some coding activities with his &lt;a href="https://www.funkysi1701.com/posts/2022/microbit/" target="_blank" rel="noopener noreferrer"&gt;Microbit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;October - I bought a second hand car and less than a week later it burst into flames, a scary event but no one hurt and everything has since been replaced/repaired.&lt;/li&gt;
&lt;li&gt;November - I lost my job&lt;/li&gt;
&lt;li&gt;December - Extended time with family for Christmas with a new job starting in January. I sat and narrowly missed passing AZ-204 (Developing Solutions for Azure). I attended &lt;a href="https://www.funkysi1701.com/posts/2022/ddd-north/" target="_blank" rel="noopener noreferrer"&gt;DDD North&lt;/a&gt;
, I attended LeedsSharp and went on a virtual tour of a Microsoft Datacenter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don&amp;rsquo;t know what is in store for 2023 but I am sure it will be equally interesting. The first thing to get my head around is my new job.&lt;/p&gt;
&lt;p&gt;So onto my goals for 2023&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;New job and get my head around all the new stuff I need to learn&lt;/li&gt;
&lt;li&gt;Celebrate 10 years of marriage and concentrate on family things&lt;/li&gt;
&lt;li&gt;Pass AZ-204 - It was such a close miss that I need to retry this&lt;/li&gt;
&lt;li&gt;More coding with my son, he got a laptop for Christmas and would be great to build on what he has learnt so far.&lt;/li&gt;
&lt;li&gt;Blog regularly - I doubled the number of blog posts from 2021, but it would be great to keep up the momentum with regular posts of what I am up to.&lt;/li&gt;
&lt;li&gt;I recently added an events page, so I need to go to some events. Events like DDD North and Scottish Summit are great, but so are local user groups so a mix of these would be great.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Last year I had the following &lt;a href="https://www.funkysi1701.com/posts/2022/2022-goals/" target="_blank" rel="noopener noreferrer"&gt;goals&lt;/a&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Video - Not used my green screen yet, would be good to make some time to use this in 2023&lt;/li&gt;
&lt;li&gt;Conference - I attended Scottish Summit and DDD North, would be great to go to more like these this year as well&lt;/li&gt;
&lt;li&gt;Blog More - Yeah I achieved this, but lets keep doing this.&lt;/li&gt;
&lt;li&gt;Metrics - I have done little bits with this over the last year, but not a huge amount.&lt;/li&gt;
&lt;li&gt;My personal brand has improved this year as my blog relaunched on the Hugo platform, and I am very happy with its look, probably more I can do.&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>DDD North</title><link>https://blog-test.funkysi1701.com/posts/2022/ddd-north/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 05 Dec 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/ddd-north/</guid><category term="DotNet">DotNet</category><category term="Azure">Azure</category><category term="Community">Community</category><category term="Conference">Conference</category><category term="DDDNorth">DDDNorth</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/dddnorth-hull-developers-conference-2022.jpg"/><description>&lt;p&gt;On Saturday 3rd December I attended &lt;a href="https://www.dddnorth.co.uk/" target="_blank" rel="noopener noreferrer"&gt;DDD North&lt;/a&gt;
. It is a community run conference for Developers (the D&amp;rsquo;s stand for Developer) and I had a fab time there. Many conferences are going online which is great, however there is nothing quite like chatting over coffee or lunch with fellow Developers about the tech you are learning about, this was probably my favourite thing about the conference.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="DDD North" src="https://blog-test.funkysi1701.com/images/dddnorth-hull-developers-conference-2022.jpg" loading="lazy"
width="800" height="600"
/&gt;
&lt;/p&gt;
&lt;p&gt;The first talk I attended was &amp;lsquo;.Net Minimal APIs&amp;rsquo; by &lt;a href="https://twitter.com/kev_bite" target="_blank" rel="noopener noreferrer"&gt;Kevin Smith&lt;/a&gt;
. Kevin runs .Net user groups in York and Sheffield so I have heard him speak before. He went through some of the features of minimal APIs. I have briefly experimented with them in .Net 6, however from the sound of things the tech is much improved in .Net 7, with lots of improvements, so this is something I want to give another try.&lt;/p&gt;
&lt;p&gt;During the coffee break I managed to have a quick conversation with &lt;a href="https://www.youtube.com/c/Elfocrash" target="_blank" rel="noopener noreferrer"&gt;Nick Chapsas&lt;/a&gt;
. Nick has a YouTube channel that my colleagues at work have been sharing during our weekly knowledge share sessions. It was great to chat with someone that I have been watching on YouTube.&lt;/p&gt;
&lt;p&gt;The second talk was &amp;lsquo;When microservices go bad&amp;rsquo; by &lt;a href="https://twitter.com/TechyChap" target="_blank" rel="noopener noreferrer"&gt;Andy Clark&lt;/a&gt;
. This talk was a discussion of the different ways you can use &lt;a href="https://github.com/App-vNext/Polly" target="_blank" rel="noopener noreferrer"&gt;Polly&lt;/a&gt;
, Carl Franklin of .NetRocks fame has mentioned Polly a few times on the show, so this was a good talk to explain the different ways it can be used.&lt;/p&gt;
&lt;p&gt;The third talk was &amp;lsquo;Don&amp;rsquo;t put your messages in a bottle; Implement messaging patterns&amp;rsquo; by &lt;a href="https://twitter.com/egrootenboer" target="_blank" rel="noopener noreferrer"&gt;Eldert Grootenboer&lt;/a&gt;
, he should have been joined by &lt;a href="https://twitter.com/borzenko_lena" target="_blank" rel="noopener noreferrer"&gt;Olena Borzenko&lt;/a&gt;
however she was unable to travel (didn&amp;rsquo;t catch exactly why, I think she was from Ukraine or working in Ukraine and Visa&amp;rsquo;s from that part of the world are a problem at the moment). This was a talk all about message queues and the patterns and practises you should implement. I don&amp;rsquo;t know much about queues, having only recently started using AWS SQS messages recently so this was useful to put that work into context. The slides from this talk are available &lt;a href="https://eldertnet-my.sharepoint.com/:p:/g/personal/eldert_eldert_net/EXbVxQpSzzNJmtvKNPjzSvYBSGfnLI7qC5U5Ia-PYCqioA?rtime=fIdK6wHX2kg" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Lunch was next and the food was excellent. I found myself sitting with Jamie Taylor (from the Tabs and Spaces podcast), &lt;a href="https://twitter.com/YorkshireTechy" target="_blank" rel="noopener noreferrer"&gt;Craig Pickles&lt;/a&gt;
, &lt;a href="https://twitter.com/chris_sainty" target="_blank" rel="noopener noreferrer"&gt;Chris Sainty&lt;/a&gt;
and a few others. There was a fascinating discussion on Blazor, .Net and how Microsoft introduces new stuff. Really appreciate being able to listen in on such an interesting discussion.&lt;/p&gt;
&lt;p&gt;The fourth talk was &amp;lsquo;Why don&amp;rsquo;t people seem to be able to diagnose problems these days?&amp;rsquo; by &lt;a href="https://twitter.com/richardfennell" target="_blank" rel="noopener noreferrer"&gt;Richard Fennell&lt;/a&gt;
. This was a fascinating walk through computer history and the challenges of finding where the problem is. The slides from this talk are available &lt;a href="https://github.com/rfennell/Presentations/blob/main/Why%20don%27t%20people%20seem%20to%20be%20able%20to%20diagnose%20problems%20these%20days.pptx" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The last talk was &amp;lsquo;Empathy, Sympathy, and Compassion&amp;rsquo; by &lt;a href="https://twitter.com/podcasterJay" target="_blank" rel="noopener noreferrer"&gt;Jamie Taylor&lt;/a&gt;
who I had met at lunch. This was a fascinating look at how we place barriers between ourselves as Developers and the users of the software. It expanded into ethics, code of conduct and doing good.&lt;/p&gt;
&lt;p&gt;It was a great event so thank you &lt;a href="https://twitter.com/dddnorth" target="_blank" rel="noopener noreferrer"&gt;DDD North&lt;/a&gt;
for all your hard work, I look forward to the next one. I have lots to go away and think about.&lt;/p&gt;</description></item><item><title>Expiring Azure AD Client Secrets</title><link>https://blog-test.funkysi1701.com/posts/2022/expiring-azuread-client-secrets/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 18 Oct 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/expiring-azuread-client-secrets/</guid><category term="DotNet">DotNet</category><category term="Azure">Azure</category><category term="ActiveDirectory">ActiveDirectory</category><category term="Secret">Secret</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/AzureADSecret.png"/><description>&lt;p&gt;This morning the client complains that the website is not working. I do some checking and I confirm that there is indeed an error.&lt;/p&gt;
&lt;p&gt;The error they are seeing is:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;An unhandled exception occurred while processing the request.
MsalServiceException: A configuration issue is preventing authentication
- check the error message from the server for details.
You can modify the configuration in the application registration portal.
See https://aka.ms/msal-net-invalid-client for details.
Original exception: AADSTS7000222: The provided client secret keys for
app &amp;#39;00000000-0000-0000-0000-000000000000&amp;#39; are expired.
Visit the Azure portal to create new keys for your app: https://aka.ms/NewClientSecret,
or consider using certificate credentials for added security: https://aka.ms/certCreds.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The fix for this is relatively simple, generate a new client secret in Azure AD and update the website config to make use of it.&lt;/p&gt;
&lt;p&gt;The problem is that this problem will reoccur in 3, 6, 12, 18 or 24 months, depending on what expiry date you set on the secret.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Add a client secret" src="https://blog-test.funkysi1701.com/images/AzureADSecret.png" loading="lazy"
width="572" height="350"
/&gt;
&lt;/p&gt;
&lt;p&gt;A suggestion from twitter is that Logic Apps and Event Grid might help solve this problem. Lets see how this might work.&lt;/p&gt;
&lt;p&gt;Logic Apps have a consumption plan, so this kind of solution shouldn&amp;rsquo;t break the bank as will only cost per run eg daily/weekly etc&lt;/p&gt;
&lt;p&gt;But first here is a powershell script that lists all the secrets that are due to expire in the next 30 days.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#secret expiration date filter (for example 30 days)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$LimitExpirationDays = &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#Retrieving the list of secrets that expires in the above range of days&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$SecretsToExpire = Get-AzureADApplication -All:$true | ForEach-Object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $app = $_
&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; Get-AzureADApplicationPasswordCredential -ObjectId $_.ObjectId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Get-AzureADApplicationKeyCredential -ObjectId $_.ObjectId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) | Where-Object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $_.EndDate &lt;span style="color:#f92672"&gt;-lt&lt;/span&gt; (Get-Date).AddDays($LimitExpirationDays)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } | ForEach-Object {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id = &lt;span style="color:#e6db74"&gt;&amp;#34;Not set&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($_.CustomKeyIdentifier) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id = [&lt;span style="color:#66d9ef"&gt;System.Text.Encoding&lt;/span&gt;]::UTF8.GetString($_.CustomKeyIdentifier)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#66d9ef"&gt;PSCustomObject&lt;/span&gt;] @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; App = $app.DisplayName
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ObjectID = $app.ObjectId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AppId = $app.AppId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Type = $_.GetType().name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KeyIdentifier = $id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EndDate = $_.EndDate
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#Printing the list of secrets that are near to expire&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($SecretsToExpire.Count &lt;span style="color:#f92672"&gt;-EQ&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;No secrets found that will expire in this range&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Secrets that will expire in this range:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output $SecretsToExpire.Count
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output $SecretsToExpire
&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;This works quite well, but I have to manually run it every so often. I have not found a way to automate this as I don&amp;rsquo;t know how to get past the MFA that is configured on my Azure AD tenant.&lt;/p&gt;
&lt;p&gt;Now lets look at how a Logic App might help us. First of all we need somewhere to query the expiry dates, and Azure Key Vault is the ideal place to store them.&lt;/p&gt;
&lt;p&gt;Create a Key Vault if you don&amp;rsquo;t already have one and add a new Secret. Manually add the Client Secret from Azure AD and give it a name you can identify it with. Tick the Set expiration date and save the expiry date of your secret.&lt;/p&gt;
&lt;p&gt;Now Create a Logic App, I am going to use Consumption, so it only costs you when it runs.&lt;/p&gt;
&lt;p&gt;Using the Logic Apps Designer, start with a Recurrence trigger. This lets you queue up your logic app on a schedule, I&amp;rsquo;ve set mine to run every 30 days.&lt;/p&gt;
&lt;p&gt;Next run a Get Secret command from your Key Vault. Select the identifying name you saved the secret with earlier. This will retrieve the secret from the Key Vault, if you go into the settings you can hide the output as you are only really interested in the expiry date.&lt;/p&gt;
&lt;p&gt;I am doing a low tech solution for now, and just emailing myself the expiry date. It is easy to add the expiry date of the secret to an email.&lt;/p&gt;
&lt;p&gt;Later on I might add a bit more logic to only email myself when the expiry is less than 30 days, a reminder to create a new secret. When creating a new secret in Azure AD, I also need to add the secret and expiry date into Key Vault.&lt;/p&gt;
&lt;p&gt;At the very least this solution will give me an early warning of when my secrets are about to expire. It is possible to get my website to read information from Key Vault directly which I may well investigate.&lt;/p&gt;</description></item><item><title>Upgrading to .Net 7</title><link>https://blog-test.funkysi1701.com/posts/2022/dotnet7/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 01 Oct 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/dotnet7/</guid><category term="DotNet">DotNet</category><category term="Blazor">Blazor</category><category term="EFCore">EFCore</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/coverage.png"/><description>&lt;p&gt;I have a Blazor application that was built with .Net Core 3, and I have updated it to .Net 5 and later .Net 6 when those versions of were released. In November .Net 7 is released so I have been testing it with the .Net 7 previews.&lt;/p&gt;
&lt;p&gt;However for this update I encountered a few more issues than I remember from the other updates.&lt;/p&gt;
&lt;h2 id="automapper"&gt;Automapper&lt;a class="anchor ms-1" href="#automapper" aria-label="Permalink: Automapper"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first issue I encountered was with Automapper. My Unit tests failed with the following error&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Error Message:
System.ArgumentException : GenericArguments[0], &amp;#39;System.Char&amp;#39;, on &amp;#39;T MaxFloat[T](System.Collections.Generic.IEnumerable`1[T])&amp;#39; violates the constraint of type &amp;#39;T&amp;#39;.
---- System.Security.VerificationException : Method System.Linq.Enumerable.MaxFloat: type argument &amp;#39;System.Char&amp;#39; violates the constraint of type parameter &amp;#39;T&amp;#39;.
Stack Trace:
at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation)
at AutoMapper.Internal.TypeDetails.&amp;lt;&amp;gt;c__DisplayClass25_1.&amp;lt;GetPublicNoArgExtensionMethods&amp;gt;b__10(MethodInfo extensionMethod)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
at System.Linq.Enumerable.SelectManyIterator[TSource,TCollection,TResult](IEnumerable`1 source, Func`2 collectionSelector, Func`3 resultSelector)+MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.UnionIterator`1.GetNext()
at System.Linq.Enumerable.UnionIterator`1.MoveNext()
at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
at AutoMapper.Internal.TypeDetails.PossibleNames()
at AutoMapper.Internal.TypeDetails.GetMember(String name)
at AutoMapper.Configuration.Conventions.DefaultName.GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, String nameToSearch)
at AutoMapper.Configuration.Conventions.ParentSourceToDestinationNameMapper.GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, String nameToSearch)
at AutoMapper.Configuration.Conventions.DefaultMember.MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceTypeDetails, Type destType, Type destMemberType, String nameToSearch, List`1 resolvers, IMemberConfiguration parent, Boolean isReverseMap)
at AutoMapper.Configuration.Conventions.MemberConfiguration.MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, String nameToSearch, List`1 resolvers, Boolean isReverseMap)
at AutoMapper.Configuration.Conventions.NameSplitMember.MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, String nameToSearch, List`1 resolvers, IMemberConfiguration parent, Boolean isReverseMap)
at AutoMapper.Configuration.Conventions.MemberConfiguration.MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, String nameToSearch, List`1 resolvers, Boolean isReverseMap)
at AutoMapper.ProfileMap.MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, String destMemberName, List`1 members, Boolean reverseNamingConventions)
at AutoMapper.TypeMap..ctor(Type sourceType, Type destinationType, ProfileMap profile, Boolean isReverseMap)
at AutoMapper.ProfileMap.BuildTypeMap(IGlobalConfiguration configurationProvider, ITypeMapConfiguration config)
at AutoMapper.ProfileMap.Register(IGlobalConfiguration configurationProvider)
at AutoMapper.MapperConfiguration.Seal()
at AutoMapper.MapperConfiguration..ctor(MapperConfigurationExpression configurationExpression)
at AutoMapper.MapperConfiguration..ctor(Action`1 configure)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)
----- Inner Stack Trace -----
at System.RuntimeMethodHandle.GetStubIfNeeded(RuntimeMethodHandleInternal method, RuntimeType declaringType, RuntimeType[] methodInstantiation)
at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At first I didn&amp;rsquo;t realise it was an issue with Automapper and I started searching for breaking changes in dotnet 7. Eventually this lead to finding that a change to .Net had created an issue with version 11 of Automapper. The following github issues explains more about what was involved in fixing this.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dotnet/runtime/issues/69119" target="_blank" rel="noopener noreferrer"&gt;https://github.com/dotnet/runtime/issues/69119&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/AutoMapper/AutoMapper/pull/3999" target="_blank" rel="noopener noreferrer"&gt;https://github.com/AutoMapper/AutoMapper/pull/3999&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This week &lt;a href="https://github.com/AutoMapper/AutoMapper/releases/tag/v12.0.0" target="_blank" rel="noopener noreferrer"&gt;version 12&lt;/a&gt;
of Automapper was released and it fixed this issue for me.&lt;/p&gt;
&lt;h2 id="code-coverage"&gt;Code Coverage&lt;a class="anchor ms-1" href="#code-coverage" aria-label="Permalink: Code Coverage"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My build includes the calculation of code coverage of my unit tests. For some reason this step was failing.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; - task: DotNetCoreCLI@2
displayName: &amp;#39;Running API Tests&amp;#39;
inputs:
command: &amp;#39;test&amp;#39;
arguments: &amp;#39;--no-restore --no-build --configuration $(buildConfiguration) --runtime win-x64 /p:CollectCoverage=true /p:CoverletOutputFormat=opencover&amp;#39;
projects: &amp;#39;Path To csproj file&amp;#39;
nobuild: true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For .Net 6 this step would run my unit tests and include a section that looked a bit like this.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Calculating coverage result...
Generating report &amp;#39;D:\a\1\s\WhatEver\coverage.opencover.xml&amp;#39;
+---------------------------+--------+--------+--------+
| Module | Line | Branch | Method |
+---------------------------+--------+--------+--------+
| Something | 50.91% | 48.77% | 65.44% |
+---------------------------+--------+--------+--------+
| Something.Core | 41.79% | 6.92% | 47.2% |
+---------------------------+--------+--------+--------+
| Something.Core.Email | 96.55% | 50% | 100% |
+---------------------------+--------+--------+--------+
+---------+--------+--------+--------+
| | Line | Branch | Method |
+---------+--------+--------+--------+
| Total | 49.46% | 44.2% | 53.55% |
+---------+--------+--------+--------+
| Average | 63.08% | 35.22% | 70.88% |
+---------+--------+--------+--------+
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However for .Net 7 the unit tests would pass but the coverage bit above would not run, and no visible errors to help me.&lt;/p&gt;
&lt;p&gt;Testing dotnet test locally I discovered that if I included the path and filename to the csproj file the coverage would not run, if I removed this it would work as per .Net 6. No idea why this was happening.&lt;/p&gt;
&lt;p&gt;I did some testing with the DotNetCoreCLI@2 task, but I couldn&amp;rsquo;t get the coverage to work. However I was testing this locally via the command line so it was a simple thing to swap DotNetCoreCLI@2 for a command line step. After I did that the coverage started working again!&lt;/p&gt;
&lt;p&gt;Here is the command line step I added&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; - task: CmdLine@2
displayName: &amp;#39;Running API Tests&amp;#39;
inputs:
script: |
&amp;#34;C:\Program Files\dotnet\dotnet.exe&amp;#34; test --logger trx --results-directory D:\a\_temp --no-restore --no-build --configuration Release --runtime win-x64 /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
workingDirectory: &amp;#39;$(Build.SourcesDirectory)/PathToWhereEver&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="sql-server-tables-with-triggers"&gt;SQL Server tables with triggers&lt;a class="anchor ms-1" href="#sql-server-tables-with-triggers" aria-label="Permalink: SQL Server tables with triggers"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My build was all working so now time to test the application was working. But an error was being thrown if I tried to save any data to the SQL Server database.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Could not save changes because the target table has database triggers. Please configure your entity type accordingly, see https://aka.ms/efcore-docs-sqlserver-save-changes-and-triggers for more information. The target table &amp;#39;Something&amp;#39; of the DML statement cannot have any enabled triggers if the statement contains an OUTPUT clause without INTO clause.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A nice error, as it gives me a link to the change and what to do to fix.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;override&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
&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; configurationBuilder.Conventions.Add(_ =&amp;gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; BlankTriggerAddingConvention());
&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;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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BlankTriggerAddingConvention&lt;/span&gt; : IModelFinalizingConvention
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;virtual&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; ProcessModelFinalizing(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IConventionModelBuilder modelBuilder,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IConventionContext&amp;lt;IConventionModelBuilder&amp;gt; context)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; entityType &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; modelBuilder.Metadata.GetEntityTypes())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; table = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (table != &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;amp;&amp;amp; entityType.GetDeclaredTriggers().All(t =&amp;gt; t.GetDatabaseName(table.Value) == &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; entityType.Builder.HasTrigger(table.Value.Name + &lt;span style="color:#e6db74"&gt;&amp;#34;_Trigger&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; fragment &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; entityType.GetMappingFragments(StoreObjectType.Table))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (entityType.GetDeclaredTriggers().All(t =&amp;gt; t.GetDatabaseName(fragment.StoreObject) == &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; entityType.Builder.HasTrigger(fragment.StoreObject.Name + &lt;span style="color:#e6db74"&gt;&amp;#34;_Trigger&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&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;Adding the following to my DBContext allowed data to be saved even if triggers existed on my database.&lt;/p&gt;
&lt;p&gt;A longer term fix, should be to investigate if the triggers on the database are still needed and remove if not. From reading the docs, it sounds like a performance gain would be had after doing this!&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are the issues I have encountered so far updating to .Net 7. A few more than for .Net 5 or 6. However so far I have managed to find a solution for all issues. I expect one more release candidate, with the final version of .Net 7 coming out in November.&lt;/p&gt;</description></item><item><title>MakeCode and the BBC micro:bit</title><link>https://blog-test.funkysi1701.com/posts/2022/microbit/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 21 Aug 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/microbit/</guid><category term="Scratch">Scratch</category><category term="kids">kids</category><category term="MakeCode">MakeCode</category><category term="Microbit">Microbit</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/blocks.png"/><description>&lt;p&gt;Programming is in my DNA, so when I had children it was obvious that I would attempt to share my passion. It has taken a while, for some reason for loops don&amp;rsquo;t interest toddlers! However my 7 year old son has got a taste for it now.&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/getcoding.jpg" style="float:left; padding-right: 15px;" alt="Cover of the book Get Coding! for young programmers" /&gt;
&lt;p&gt;It was his birthday the other day and he got quite a few tech related things. First off he got some programming books. &lt;a href="https://www.amazon.co.uk/gp/product/1406366846/ref=ppx_yo_dt_b_asin_title_o02_s01?ie=UTF8&amp;amp;psc=1" target="_blank" rel="noopener noreferrer"&gt;Get Coding!&lt;/a&gt;
, &lt;a href="https://www.amazon.co.uk/gp/product/1641522453/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&amp;amp;psc=1" target="_blank" rel="noopener noreferrer"&gt;Coding for Kids: Scratch:&lt;/a&gt;
and &lt;a href="https://www.amazon.co.uk/gp/product/1641521759/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&amp;amp;psc=1" target="_blank" rel="noopener noreferrer"&gt;Coding for Kids: Python:&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;He has been reading an old Javascript book, so I wanted to get him something a bit more up to date, so the Get Coding book should give him the basics of creating webpages and doing things with Javascript. He has been also been playing with &lt;a href="https://blog-test.funkysi1701.com/posts/2022/scratch/"&gt;Scratch&lt;/a&gt;
for a while so the second book will definitely interest him. He also keeps mentioning Python, which I know nothing about, so even if he never reads it, I have something new to learn!&lt;/p&gt;
&lt;p&gt;As well as the books he got a BBC micro:bit (with some accessories!) from his grandparents. He has been playing with &lt;a href="https://makecode.microbit.org/#" target="_blank" rel="noopener noreferrer"&gt;MakeCode&lt;/a&gt;
which features a simulator of a micro:bit, so I thought he might like having a physical device in his hands.&lt;/p&gt;
&lt;p&gt;He has loved playing with it so far, and I have loved working with him. Already we are at the point where he knows where to find some of the blocks he needs to write the programs, and is telling me I am looking in the wrong place!&lt;/p&gt;
&lt;p&gt;In case you are not familiar with MakeCode it is a block based programming language similar to Scratch. You drag blocks onto the screen which represent if statements or variables or loops etc. The micro:bit section of the site, simulates a &lt;a href="https://microbit.org/new-microbit/" target="_blank" rel="noopener noreferrer"&gt;BBC micro:bit&lt;/a&gt;
and allows you to write programs for it. There is a download feature which allows you to download the program you have written and run it on a physical device. The process of downloading and running your code on the micro:bit is really straight forward. The micro:bit can be connected to your pc/laptop with a micro usb cable, which also powers the device. The device then shows up as a drive and the programs can be downloaded directly onto the device.&lt;/p&gt;
&lt;p&gt;The BBC micro:bit is a pocket-sized computer that introduces you to how software and hardware work together. It has an LED light display, buttons, sensors and many input/output features that, when programmed, let it interact with you and your world. There is a huge list of sensors from buttons, to accelerometer, to temperature and light. It really is an amazing device.&lt;/p&gt;
&lt;p&gt;The MakeCode website is full of help pages, tutorials and videos, so whatever level or experience you are, you will be able to get started. Also you can get a lot out of the site without having a physical device as the simulator is rather good. However me and my boy, have really enjoyed having a physical device in our hands, that we can move around the house with. We programmed up a simple light sensor, and we could move around the house finding where was dark and what happened if we moved our hands in front of it. The website allows the same thing, however moving a slider is not the same experience.&lt;/p&gt;
&lt;p&gt;Twenty five years ago (or so) my step father was getting me into electronics, by explaining capacitors, resistors and all the other components. So it is no surprise that he has loved setting things up for my boy. He has spent a great deal of time getting components that would work with the micro:bit and 3D printing boards and connectors (to make it easy to connect things up)&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="BBC micro:bit accessories including breadboards, cables, battery boxes, a joystick, a NeoPixel LED strip and an 8x8 LED matrix" src="https://blog-test.funkysi1701.com/images/microbit-accessories.jpg" loading="lazy"
width="4000" height="3000"
/&gt;
&lt;/p&gt;
&lt;p&gt;Pictured are a selection of the components. We have a selection of breadboards which we haven&amp;rsquo;t tried yet, a selection of cables for connecting things up. Two battery boxes, (3V and 9V). A slider variable resistor, we experimented with using this as a volume control earlier. A board that makes it easy to connect components to the micro:bit. A joystick. A &lt;a href="https://makecode.microbit.org/pkg/microsoft/pxt-neopixel" target="_blank" rel="noopener noreferrer"&gt;NeoPixel&lt;/a&gt;
strip of ten colourful LEDs. A 8x8 LED &lt;a href="https://makecode.microbit.org/pkg/alankrantas/pxt-max7219_8x8" target="_blank" rel="noopener noreferrer"&gt;Matrix&lt;/a&gt;
for cool scrolling messages. The last two components, the NeoPixel and the Matrix require an extension to the standard controls but these are easily found on the MakeCode website.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="MakeCode blocks that move an LED around the micro:bit 5x5 display using joystick X and Y co-ordinates" src="https://blog-test.funkysi1701.com/images/blocks.png" loading="lazy"
width="461" height="384"
/&gt;
&lt;/p&gt;
&lt;p&gt;I have featured on this page the code I helped write that uses the joystick to move a LED around the 5 x 5 grid that is on the micro:bit. To write this I started off by printing the X Co-ordinates to the screen. With the joystick in the centre position, it was about 500, when moved one way it was low teens, and the other way it was 1000+. Then I needed to figure out how to convert X, Y Co-ordinates for the joystick that could be 0 to 1000, to X, Y co-ordinates of the display that is 5 x 5. The Maths was a bit beyond my boy, but he just about understood what was going on. The clear screen step is needed so the previous position can be removed from the screen.&lt;/p&gt;
&lt;p&gt;I am really enjoying learning about the micro:bit and seeing my boy engage with it and learn programming. I have been very impressed with his ability to retain knowledge of ifs and other programming concepts (however I am a bit biased being his father)&lt;/p&gt;</description></item><item><title>A brief history of Source Control</title><link>https://blog-test.funkysi1701.com/posts/2022/a-brief-history-of-source-control/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 25 Jul 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/a-brief-history-of-source-control/</guid><category term="SourceControl">SourceControl</category><category term="History">History</category><category term="Bitbucket">Bitbucket</category><category term="AzureDevOps">AzureDevOps</category><category term="GitHub">GitHub</category><category term="Git">Git</category><category term="Subversion">Subversion</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/svn.jpg"/><description>&lt;p&gt;I have been thinking back to when I started using source control and some of the different tools I have used over the years.&lt;/p&gt;
&lt;p&gt;When I was learning to code it was some time after I had learned the basics that I learnt about source control. Back when I started writing webpages I would have a folder containing all my html, css, images etc and I would FTP these up to my web server. If I made a change to a file I would reupload the file I changed, or reupload all my files to make sure I didn&amp;rsquo;t miss anything.&lt;/p&gt;
&lt;p&gt;It was sometime later that I learnt about source control. I can&amp;rsquo;t remember exactly when, but I suspect it was after I had used it at work. (between 2006 and 2010 as a best guess, my oldest repo says it is 12 years old!)&lt;/p&gt;
&lt;p&gt;Source control (or version control) is the practice of tracking and managing changes to code. These tools provide a running history of code development and help to resolve conflicts when merging.&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/svn.jpg" width="400px" style="float: left; margin-right: 1rem; margin-bottom: 0.5rem;" alt="Apache Subversion (SVN) logo" /&gt;
&lt;p&gt;The first source control tool I remember using was subversion. The windows client for this was called &lt;a href="https://tortoisesvn.net/downloads.html" target="_blank" rel="noopener noreferrer"&gt;TortoiseSVN&lt;/a&gt;
and is still available today. I know this as my current job has some legacy code which still uses it.&lt;/p&gt;
&lt;p&gt;Back then, to use Subversion you needed to set up a linux server with subversion on it, and you would then connect over your LAN to it from your development machine. This was before the days of github, where everything was hosted on a SaaS service somewhere. I do not remember the process of getting everything setup, but with it being linux, there was no doubt a load of config files to edit, and different dependencies to install.&lt;/p&gt;
&lt;p&gt;Over the years I installed various web interfaces to allow &amp;ldquo;&lt;em&gt;browsing&lt;/em&gt;&amp;rdquo; of source code, some even had bug trackers built in. The ones I can remember are &lt;a href="https://trac.edgewall.org/" target="_blank" rel="noopener noreferrer"&gt;Trac&lt;/a&gt;
and &lt;a href="https://www.redmine.org/" target="_blank" rel="noopener noreferrer"&gt;Redmine&lt;/a&gt;
. Both look to still be available and you can probably install them if you want to remember way back when.&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/2022/github-octocat.png" width="400px" style="float: right; margin-left: 1rem; margin-bottom: 0.5rem;" alt="GitHub Octocat mascot" /&gt;
&lt;p&gt;The first hosted source control tool I remember using was &lt;a href="https://bitbucket.org/product/" target="_blank" rel="noopener noreferrer"&gt;bitbucket&lt;/a&gt;
and this as far as I can tell has only ever supported git. So I am guessing I imported my subversion repos into git ones at this point. The reason for bitbucket was chosen was it allowed private repositories for free, at that point github was probably available but only provided public repositories.&lt;/p&gt;
&lt;p&gt;After bitbucket the git repos where moved to Azure DevOps or Visual Studio Team Services as it was called back then. This move was mainly to take advantage of the builds and releases feature and to decommission some aging build servers.&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/azuredevops.png" width="400px" style="float: left; margin-right: 1rem; margin-bottom: 0.5rem;" alt="Azure DevOps logo" /&gt;
&lt;p&gt;This brings me to today where I have a mix of public repos on github and private repos on Azure DevOps. For building my code I use a mix of github actions and Azure Pipelines. As Microsoft own both services now, there is a fair amount of crossover between the two services, however it is far from certain which service is the future.&lt;/p&gt;
&lt;p&gt;Wow, my code has moved around a lot over the years. From no source control, to subversion, to git, to Bitbucket to Azure DevOps!&lt;/p&gt;</description></item><item><title>Visual Studio Keyboard Shortcuts</title><link>https://blog-test.funkysi1701.com/posts/2022/keyboard-shortcuts/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 05 Jul 2022 21:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/keyboard-shortcuts/</guid><category term="VisualStudio">VisualStudio</category><category term="shortcuts">shortcuts</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/shortcuts.png"/><description>&lt;p&gt;I use keyboard shortcuts all the time, mostly without thinking, but they can be quite a time saver especially for frequently used tasks.&lt;/p&gt;
&lt;p&gt;I recently came across this list of Visual Studio ones. &lt;a href="https://learn.microsoft.com/en-us/visualstudio/ide/default-keyboard-shortcuts-in-visual-studio?view=vs-2022" target="_blank" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/visualstudio/ide/default-keyboard-shortcuts-in-visual-studio?view=vs-2022&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I was going to do a top ten, but not really sure how you rank keyboard shortcuts, so instead I will mention some of my favourites.&lt;/p&gt;
&lt;h2 id="build-solution"&gt;Build solution&lt;a class="anchor ms-1" href="#build-solution" aria-label="Permalink: Build solution"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are using Visual Studio you need to build your code. If you are anything like me, after even the smallest change I want to see what affect that has had so a rebuild is often needed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl + Shift + B / Build Solution&lt;/li&gt;
&lt;li&gt;F5 / Run&lt;/li&gt;
&lt;li&gt;Ctrl + F5 / Run with no debugging&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cut-copy-paste-undo-redo"&gt;Cut, Copy, Paste, Undo, Redo&lt;a class="anchor ms-1" href="#cut-copy-paste-undo-redo" aria-label="Permalink: Cut, Copy, Paste, Undo, Redo"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Programming is sometimes refered to as copying and pasting from &lt;a href="https://stackoverflow.com/" target="_blank" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt;
, but they are always times you want to copy and paste stuff so the standard keyboard shortcuts are all here.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl + C / Copy&lt;/li&gt;
&lt;li&gt;Ctrl + X / Cut&lt;/li&gt;
&lt;li&gt;Ctrl + V / Paste&lt;/li&gt;
&lt;li&gt;Ctrl + Z / Undo&lt;/li&gt;
&lt;li&gt;Ctrl + Y / Redo (or Undo your Undo)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="comments-in-your-code"&gt;Comments in your code&lt;a class="anchor ms-1" href="#comments-in-your-code" aria-label="Permalink: Comments in your code"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Often we like to temporarily comment out a line of code to see what affect it has.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl + K, Ctrl + C / Comment selection&lt;/li&gt;
&lt;li&gt;Ctrl + K, Ctrl + U /Uncomment selection&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="using-statements"&gt;Using statements&lt;a class="anchor ms-1" href="#using-statements" aria-label="Permalink: Using statements"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I like to keep my using statements tidy, and not clutered up with ones that aren&amp;rsquo;t used anymore.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl + R, Ctrl + G / Remove and Sort Usings&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="go-to-implementation"&gt;Go to Implementation&lt;a class="anchor ms-1" href="#go-to-implementation" aria-label="Permalink: Go to Implementation"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I like to move quickly between methods that a class is calling to find out what is happening so the go to implementation and go to definition shortcuts are very useful. I tend to use the right click option more than the sortcut, but I would save myself a heap of time if I learnt these shortcuts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;F12 / Go to Definition&lt;/li&gt;
&lt;li&gt;Alt + F12 / Peek Definition&lt;/li&gt;
&lt;li&gt;Ctrl + F12 / Go to Implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="find-file-in-solution-explorer"&gt;Find file in Solution Explorer&lt;a class="anchor ms-1" href="#find-file-in-solution-explorer" aria-label="Permalink: Find file in Solution Explorer"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You are editing a file and you have no idea what folder it is in the Solution Explorer. There is a shortcut to find out where you are.&lt;/p&gt;
&lt;p&gt;Ctrl + [, S / Select Active File in Solution Explorer&lt;/p&gt;
&lt;h2 id="search"&gt;Search&lt;a class="anchor ms-1" href="#search" aria-label="Permalink: Search"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finding references or a certain string is a common activity&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl + F / Find in current file&lt;/li&gt;
&lt;li&gt;Ctrl + H / Replace&lt;/li&gt;
&lt;li&gt;Ctrl + Shift + F / Find in all files&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="visual-studio-tries-to-be-helpful"&gt;Visual Studio tries to be helpful&lt;a class="anchor ms-1" href="#visual-studio-tries-to-be-helpful" aria-label="Permalink: Visual Studio tries to be helpful"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Often Visual Studio will try and be helpful with a lightbulb or similar icon, instead of clicking you can press this shortcut to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl + . / Show Visual Studio suggestion&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="learn-some-more"&gt;Learn some more&lt;a class="anchor ms-1" href="#learn-some-more" aria-label="Permalink: Learn some more"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As I said before keyboard shortcuts are great time savers. Go check out the complete list and share with me the ones you found most useful.&lt;/p&gt;</description></item><item><title>Diagrams with Mermaid</title><link>https://blog-test.funkysi1701.com/posts/2022/diagrams-with-mermaid/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 19 Jun 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/diagrams-with-mermaid/</guid><category term="GitHub">GitHub</category><category term="mermaid">mermaid</category><category term="documentation">documentation</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/mermaid2.png"/><description>&lt;p&gt;I have been wanting to produce a diagram of the architecture of my side project for some time, but I have put it off as never sure what the correct tools is for this job.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mermaid.js.org/" target="_blank" rel="noopener noreferrer"&gt;Mermaid&lt;/a&gt;
is a tool that lets you create diagrams from code and text. I first came across this tool about a year ago for use in a project. I had forgotten about this tool until the other day, when I was thinking about this problem again.&lt;/p&gt;
&lt;p&gt;Is it possible to embed a mermaid diagram in the markdown used in a github repo? Well the answer is yes, so lets look at how that works.&lt;/p&gt;
&lt;p&gt;A simple mermaid diagram looks like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;graph TD;
A[fff]---&amp;gt;B;
A---&amp;gt;C;
B---&amp;gt;D;
C---&amp;gt;D;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;which renders like this:&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Mermaid" src="https://blog-test.funkysi1701.com/images/mermaid.png" loading="lazy"
width="630" height="912"
/&gt;
&lt;/p&gt;
&lt;p&gt;Lets look at what it is doing.&lt;/p&gt;
&lt;p&gt;TD means the chart is top down.&lt;/p&gt;
&lt;p&gt;A is the name of a node in the chart, [fff] is a label being applied to it.&lt;/p&gt;
&lt;p&gt;Then we just define the relationships between the different nodes, you can have &amp;lt;&amp;mdash;, &amp;mdash;&amp;gt; or &amp;mdash;, or even&lt;br/&gt; &amp;lt;&amp;mdash;&amp;gt;&lt;/p&gt;
&lt;p&gt;Lets look at my architecture. I have a database (cosmosDB), I have a website running on Azure Static Web Apps, I have some Azure functions for getting data into and out of my database. I also have Application Insights monitoring the whole thing. I also have a console app for doing some data import stuff. This produces a diagram like this:&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Mermaid" src="https://blog-test.funkysi1701.com/images/mermaid2.png" loading="lazy"
width="409" height="445"
/&gt;
&lt;/p&gt;
&lt;p&gt;The code to produce this and display it on my &lt;a href="https://github.com/funkysi1701/Blogv2/" target="_blank" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;
is simply&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;```mermaid
graph TD
A[Azure Static Web App]---B[Http Fn]
B---D[Database]
C[Timer Fn]---D
D---E[Import Console App]
F[App Insights]---A
F---B
F---C
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pretty nice for a few lines of code to show what system talks with what.&lt;/p&gt;
&lt;p&gt;There are improvements that can be made to the diagram, for example changing the shapes of the different services.&lt;/p&gt;
&lt;p&gt;eg
&lt;img class="img-fluid" alt="Mermaid" src="https://blog-test.funkysi1701.com/images/mermaid3.png" loading="lazy"
width="1034" height="253"
/&gt;
&lt;/p&gt;
&lt;p&gt;If you live in the AzureDevOps world you can add a mermaid diagram to your wiki pages (but I don&amp;rsquo;t think to your markdown files). Just use the following syntax&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;::: mermaid
sequenceDiagram
Alice-&amp;gt;&amp;gt;John: Hello John, how are you?
John--&amp;gt;&amp;gt;Alice: Great!
Alice-)John: See you later!
:::
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For more info see the docs &lt;a href="https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;What diagrams are you going to build?&lt;/p&gt;</description></item><item><title>Scottish Summit 2022</title><link>https://blog-test.funkysi1701.com/posts/2022/scottishsummit/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 14 Jun 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/scottishsummit/</guid><category term="Conference">Conference</category><category term="Microsoft">Microsoft</category><category term="Community">Community</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/scottishsummit.jpg"/><description>&lt;p&gt;On the 10th and 11th June 2022 &lt;a href="https://scottishsummit.com/" target="_blank" rel="noopener noreferrer"&gt;Scottish Summit 2022&lt;/a&gt;
happened and I was there. It was an awesome event and I will attempt to summarise what happened.&lt;/p&gt;
&lt;h2 id="thursday-9th"&gt;Thursday 9th&lt;a class="anchor ms-1" href="#thursday-9th" aria-label="Permalink: Thursday 9th"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On Thursday 9th I travelled down on the train full of excitement about the event. Once I got to the hotel, I was immediately greeted by &lt;a href="https://twitter.com/OfficialCookJ" target="_blank" rel="noopener noreferrer"&gt;James Cook&lt;/a&gt;
, I was obviously in the right place, this weekend is going to be good.&lt;/p&gt;
&lt;h2 id="friday-10th"&gt;Friday 10th&lt;a class="anchor ms-1" href="#friday-10th" aria-label="Permalink: Friday 10th"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The hotel was less then 5 mins walk to the conference, which was being held at the Technology and Innovation Centre, University of Strathclyde. Registration was simple wave your tickets (which were free, apart from a contribution to charity), and you get your badge and a wrist band. (Pink for people contact, blue for hold back) I then got chatting to &lt;a href="https://twitter.com/MrKeithAtherton" target="_blank" rel="noopener noreferrer"&gt;Keith Atherton&lt;/a&gt;
, who amazingly lived in part of the world where I grew up. (Amazing what you learn at conferences!)&lt;/p&gt;
&lt;img src="https://blog-test.funkysi1701.com/images/scottishsummit.jpg" style="float: left; margin-right: 1rem; margin-bottom: 0.5rem;" alt="Scottish Summit conference during the keynote, with bagpipers and attendees in the venue" /&gt;
&lt;p&gt;Time for the Keynote talk. Which of course because we are in scotland was introduced by bagpipes marching through the room! The talk was given by &lt;a href="https://twitter.com/cmcginley" target="_blank" rel="noopener noreferrer"&gt;Connell McGinley&lt;/a&gt;
and was titled Disability Awareness &amp;amp; Inclusivity. This talk was amazing. Connell is deaf and gave the entire talk with sign language and this was translated for the rest of us to hear. Connell talked about his career and the barriers he faced. Microsoft Teams was an amazing improvement to his work life, as the captioning allowed him to talk with customers for the first time!&lt;/p&gt;
&lt;p&gt;The purple pound is the amount of spending power people with some kind of disability (15% of the worlds population) have and it is approx $13 trillion. If businesses can open their products up to more people it is a win for everyone. This was a really powerful way to open up the conference.&lt;/p&gt;
&lt;p&gt;Next up was &lt;a href="https://twitter.com/davesmall28" target="_blank" rel="noopener noreferrer"&gt;David Small&lt;/a&gt;
talking about Azure DevOps pipelines and Power Platform. I don&amp;rsquo;t know much about Power Platform however all the DevOps stuff was great, some of it reinforced stuff I already knew, some was new.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/samcogan" target="_blank" rel="noopener noreferrer"&gt;Sam Cogan&lt;/a&gt;
was next talking about Infrastructure as Code. Resources for this talk are on his &lt;a href="https://github.com/sam-cogan/events/tree/main/Scottish%20Summit%202022" target="_blank" rel="noopener noreferrer"&gt;github&lt;/a&gt;
This was a great comparison of different tools for doing Infrastructure as Code. Terraform, Pulumi, Bicep, ARM templates where all covered. The difference between stateless and stateful tools. If you have a state file you need to look after it, so if you don&amp;rsquo;t need this think about using a stateless tool. If you are only using Azure consider Azure. If you are a C# (other languages are available) think about using Pulumi (which I have used and quite like)&lt;/p&gt;
&lt;p&gt;Getting Started with Static Web Apps was next with &lt;a href="https://twitter.com/PoornimaNayar" target="_blank" rel="noopener noreferrer"&gt;Poornima Nayar&lt;/a&gt;
this was a great overview of Static Web Apps but as I already use Static Web Apps this was mainly reinforcing what I already knew. However the Static Web App CLI was mentioned which I didn&amp;rsquo;t know about so I am going to spend some time looking at that! Another thing that was mentioned was GraphQL which is a language agnostic way of building APIs which I also want to learn more about. Resources for this talk can be found &lt;a href="https://poornimanayar.co.uk/community/resources-for-my-talk-at-azure-thursdays-july-2021/" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Next was Naming stuff in Azure with &lt;a href="https://twitter.com/Ba4bes" target="_blank" rel="noopener noreferrer"&gt;Barbara Forbes&lt;/a&gt;
, she went through the challenges of getting naming right, especially with all the exceptions Azure throws into the mix. Tagging your resources can really help. Also Azure Policy can help report on what you have (and even enforce it, if you are careful). Lots of interesting stuff, as my naming strategy is non existent at the moment!&lt;/p&gt;
&lt;p&gt;Defender for Cloud Apps with &lt;a href="https://twitter.com/getofmeland" target="_blank" rel="noopener noreferrer"&gt;Charlie Gough&lt;/a&gt;
. This was his first talk and he did really well despite technical problems. This was a security talk, I thought it was going to be about securing the apps you have built, but it was more about securing the apps that the users in your company are using. Still useful to know about, but not really my thing. Sorry Charlie!&lt;/p&gt;
&lt;p&gt;Last talk of the day was &amp;lsquo;What I didn&amp;rsquo;t know about Office 365&amp;rsquo; with &lt;a href="https://twitter.com/sharoneweaver" target="_blank" rel="noopener noreferrer"&gt;Sharon Weaver&lt;/a&gt;
Sharon went through Shifts, Planner and Forms all included in your Office 365 subscription.&lt;/p&gt;
&lt;h2 id="saturday-11th"&gt;Saturday 11th&lt;a class="anchor ms-1" href="#saturday-11th" aria-label="Permalink: Saturday 11th"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To start the second day I had &lt;a href="https://twitter.com/webmaxru" target="_blank" rel="noopener noreferrer"&gt;Maxim Salnikov&lt;/a&gt;
talk about Static Web apps, if I had know it was about Static Web Apps again I may have chosen a different talk but this was still a great talk. Again the CLI was mentioned which I really need to investigate further.&lt;/p&gt;
&lt;p&gt;Next up was James Cook&amp;rsquo;s talk Monitor Azure DevOps and GitHub with Sentinel. This was all about securing your code repositories with Sentinel and looking through the logs at what is happening. To use this tech you need either a GitHub Enterprise subscription or Azure DevOps using Azure AD Logins as it is designed more for the Enterprise than a one man band kind like me, however I will see if I can have a play around with it and see what I can learn.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/TechieLass" target="_blank" rel="noopener noreferrer"&gt;Sarah Lean&lt;/a&gt;
gave a talk about the state of IT Ops tools in the hybrid age. I enjoyed this talk, Sarah added extra fun elements like talking about the Scottish language and the highland cow. The first tool mentioned was Windows Admin Centre. I have heard about this but never used it, must have come out after I switched from Ops to Dev. Looks very Azure like. Azure Update Management was mentioned next, which I have used and works really well. This is the next generation of Update Management, a bit like WSUS from my server days. Azure Policy was mentioned again, a great tool for reporting and/or enforcing things. Azure Arc was mentioned, a way to bring Azure to you. With all these tools consider why you want to use them, what benefits do they bring, not just because it it shiny!&lt;/p&gt;
&lt;p&gt;Mental Health with &lt;a href="https://twitter.com/AzureRory" target="_blank" rel="noopener noreferrer"&gt;Rory Neary&lt;/a&gt;
. This was one of my favourite talks. Rory talked about his mental health problems, his challenges, some of his coping mechanisms some of which involved the power platform. He encouraged us all to be more open about talking about Mental Health. Lots of talks have a solution to a problem, this one didn&amp;rsquo;t, but that Ok. We are all on a journey complete with its ups and downs.&lt;/p&gt;
&lt;p&gt;Accessibility for Blazor with &lt;a href="https://twitter.com/DennieDeclercq" target="_blank" rel="noopener noreferrer"&gt;Dennie Declercq&lt;/a&gt;
. I wasn&amp;rsquo;t as keen on this talk as some of the others, while I agree Accessibility is very important the solutions presented felt very generic and not really specific to Blazor. However I do have some ideas to try now and the accessibility browser extension sounds like a great idea.&lt;/p&gt;
&lt;h2 id="after-hours"&gt;After Hours&lt;a class="anchor ms-1" href="#after-hours" aria-label="Permalink: After Hours"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the best things about the conference was talking to people between sessions and afterwards. I am an introvert and tend to keep quiet but even I managed to talk to (for me) loads of people. Some of these I had previously connected to on twitter, and some were brand new on the day. I would encourage anyone reading this to reach out to the community, go to an event like this, you will be surprised how friendly and helpful people can be.&lt;/p&gt;</description></item><item><title>Getting started with Scratch coding</title><link>https://blog-test.funkysi1701.com/posts/2022/scratch/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 26 Apr 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/scratch/</guid><category term="Scratch">Scratch</category><category term="kids">kids</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/scratch.png"/><description>&lt;p&gt;My 6 year old boy has been playing with Scratch, so here is a quick introduction to what we have learnt about it.&lt;/p&gt;
&lt;p&gt;Scratch is a website that allows you to &amp;ldquo;code&amp;rdquo; by combining blocks together.&lt;/p&gt;
&lt;p&gt;This is how the scratch website describes its self&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Scratch is the world’s largest coding community for children and a coding language with a simple visual interface that allows young people to create digital stories, games, and animations. Scratch is designed, developed, and moderated by the Scratch Foundation, a nonprofit organization.
Scratch promotes computational thinking and problem solving skills; creative teaching and learning; self-expression and collaboration; and equity in computing.
Scratch is always free and is available in more than 70 languages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Scratch can be found by going to &lt;a href="https://scratch.mit.edu/projects/editor/" target="_blank" rel="noopener noreferrer"&gt;https://scratch.mit.edu/projects/editor/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A lot of the blocks affect your character or &amp;ldquo;sprite&amp;rdquo;, the default is a cute looking cat which may also be the scratch logo.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Scratch editor showing the default cat sprite, block palette on the left and coding area in the centre" src="https://blog-test.funkysi1701.com/images/scratch.png" loading="lazy"
width="905" height="835"
/&gt;
&lt;/p&gt;
&lt;p&gt;The left hand side of the screen consists of a list of the blocks of code you can use and your coding area where you can arrange them.&lt;/p&gt;
&lt;p&gt;The right hand side shows the results of your code, where you can run and test what your code does.&lt;/p&gt;
&lt;p&gt;It didn&amp;rsquo;t take my boy long to code something like this tonight.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Scratch project where the sprite moves towards the mouse pointer and displays a got you message" src="https://blog-test.funkysi1701.com/images/scratch2.png" loading="lazy"
width="712" height="725"
/&gt;
&lt;/p&gt;
&lt;p&gt;This game moves the &amp;ldquo;sprite&amp;rdquo; towards the mouse pointer and a message &amp;ldquo;got you&amp;rdquo; appears on screen when it reaches your mouse pointer.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t go through all the different blocks you can choose from, but I will highlight some of the programming concepts being learnt here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;inputs&lt;/strong&gt; every computer program needs inputs and there are lots to choose from, things like moving the mouse or pressing a key on the keyboard.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;outputs&lt;/strong&gt; your code needs to do something, this code moves a sprite about the screen&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;variables&lt;/strong&gt; my boy hasn&amp;rsquo;t heard of algebra yet, but he is already grasping concepts like variables, where a value can be assigned and maths can be applied to. In this example the score increases&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;loops&lt;/strong&gt; this program keeps looping until it reaches the mouse pointer&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;logic&lt;/strong&gt; other logic commands are also available, like if / else statements, also &amp;lt;, &amp;gt; and = statements can be used&lt;/p&gt;
&lt;p&gt;There are lots of help and tutorials on the site to help you along, and you can customise the look and even record short sound clips to play in your code.&lt;/p&gt;</description></item><item><title>Temporal Trek Podcast</title><link>https://blog-test.funkysi1701.com/posts/2022/temporal-trek-podcast/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 18 Mar 2022 18:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/temporal-trek-podcast/</guid><category term="StarTrek">StarTrek</category><category term="Podcast">Podcast</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/podcast.jpg"/><description>&lt;p&gt;Earlier this year I was a guest on the Temporal Trek Podcast.&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Your Inquiry is recognised.&lt;br&gt;Here is this weeks episode of The Temporal Trek.&lt;br&gt;“Dead Stop” part 2 of the unofficial Battle Damage two parter.&lt;br&gt;&lt;br&gt;Special Guest &lt;a href="https://twitter.com/funkysi1701?ref_src=twsrc%5Etfw"&gt;@funkysi1701&lt;/a&gt; who was paid with three containers of warp plasma. Bargain!&lt;a href="https://t.co/up4zAKOpZy"&gt;https://t.co/up4zAKOpZy&lt;/a&gt; &lt;a href="https://t.co/0EUTAWmqgl"&gt;pic.twitter.com/0EUTAWmqgl&lt;/a&gt;&lt;/p&gt;&amp;mdash; The Temporal Trek Podcast(s) (@rider_coattail) &lt;a href="https://twitter.com/rider_coattail/status/1504830089002897414?ref_src=twsrc%5Etfw"&gt;March 18, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;Here is the episode I recorded:
&lt;a href="https://podcasts.apple.com/gb/podcast/the-temporal-trek-podcast-season-3-episode-30-dead/id1499160640?i=1000554428633" target="_blank" rel="noopener noreferrer"&gt;Temporal Trek Podcast Season 3 episode 30 Dead Stop&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This week &amp;ldquo;Dan Dan&amp;rdquo; are joined by long time friend of the show, formerly from The Ten Forward Podcast, Simon Foster.&lt;/p&gt;
&lt;p&gt;We discuss whether this is&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A part two of a two-parter, last of a four parter or a previosuly unseen part 5 to the Tessek Prime Quintology?&lt;/li&gt;
&lt;li&gt;Rogue full-AI or just a really super advanced computer?&lt;/li&gt;
&lt;li&gt;Station seen again in Voyager?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oh and by the way has anyone seen the guy who flies the ship, you know the one, tall bloke, loves a good prank, Space Boomer, answers to &amp;lsquo;Travis&amp;rsquo;?&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Temporal Trek Podcast" src="https://blog-test.funkysi1701.com/images/podcast.jpg" loading="lazy"
width="268" height="268"
/&gt;
&lt;/p&gt;
&lt;p&gt;It was great fun to record and I hope you enjoy giving it a listen.&lt;/p&gt;</description></item><item><title>AWS Cloud Practitioner</title><link>https://blog-test.funkysi1701.com/posts/2022/aws-cloud-practitioner/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 17 Mar 2022 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/aws-cloud-practitioner/</guid><category term="AWS">AWS</category><category term="Certification">Certification</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/aws.png"/><description>&lt;p&gt;So today I sat the AWS Cloud Practitioner Certification Exam and passed! This is my second certification exam I have sat after the Azure Fundamentals one I sat last year.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.credly.com/badges/3aab54c8-a109-4018-bcad-dbe0d6a1fc0c/public_url"&gt;&lt;img src="https://blog-test.funkysi1701.com/images/awscp.png" alt="AWS Cloud Practitioner" width="150" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This time was different than the Azure one. Colleagues at work encouraged me to look into doing this particular exam and my employer is going to cover the cost of the exam itself. Last time I did the exam in my own time and didn&amp;rsquo;t really discuss it with anyone from work.&lt;/p&gt;
&lt;p&gt;The other difference was this time I went to a testing centre. The centre was a 5 minute walk from the office. So I decided to work from the office today and 20 minutes before the exam started I walked to the centre. I signed a couple of bits of paper, had my photo taken, had my passport and driving license laughed at, put my belongings in a locker and I was free to start the exam. No worrying about internet connectivity or kids making noise outside my room, or the endless photos at the prep stage of an exam from home. I think I prefer the exam centre experience.&lt;/p&gt;
&lt;p&gt;The other difference was the first exam was Azure, this one was AWS. Both exams cover similar concepts, they are both introductions to Cloud Computing. It&amp;rsquo;s ten months since I did the Azure one, however they both had multiple choice questions and gave you the results at the end. I feel overly familir with Azure, while I don&amp;rsquo;t feel that was with AWS yet. A lot of questions relied on you knowing what AWS services are called. eg AWS Pipeline, AWS CodeStar, AWS CodeBuild, Amazon CodeGuru are all AWS services and are easily mixed up, especially as I have only used a few AWS services, while I have used a lot more of the Azure ones.&lt;/p&gt;
&lt;p&gt;My memory is the Azure gave you a breakdown of your score at the end, while I am still waiting for that from todays exam. This difference may of course be due to it being in a testing centre.&lt;/p&gt;
&lt;p&gt;I still prefer Azure to AWS, however today has proven that I can learn AWS stuff as well. For my next exam I want to get more hands on with my learning, as most of the services I have learnt about so far I haven&amp;rsquo;t seen in action.&lt;/p&gt;</description></item><item><title>Updating SQL Server with Docker</title><link>https://blog-test.funkysi1701.com/posts/2022/updating-sqlserver-with-docker/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 23 Feb 2022 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/updating-sqlserver-with-docker/</guid><category term="Docker">Docker</category><category term="SQL">SQL</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/header-01.png"/><description>&lt;p&gt;This morning I was listening to a podcast where the new features coming out for SQL Server 2022 were being discussed. This starting me thinking about what would be involved in upgrading.&lt;/p&gt;
&lt;p&gt;Upgrading production environments is complex and there are licensing considerations to take into account. However for non production workloads like development this isn&amp;rsquo;t a problem so lets look at that first.&lt;/p&gt;
&lt;p&gt;In the past I have installed SQL Server Devloper Edition onto my laptop, this is fine but I have found that unless you are very careful you may end up with multiple different versions of SQL Server sitting around, and it is difficult to cleanly remove them without a fresh install of the OS.&lt;/p&gt;
&lt;p&gt;However in this day and age, Docker and Containers are king. My current development environment makes use of Docker and has a docker compose file which sets up SQL Server for this particular application, lets take a look.&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-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;sqlserver&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;mcr.microsoft.com/mssql/server:2019-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Sql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;5432:1433&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;my-network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;sqlvolume:/var/opt/mssql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This defines which docker image to use, in this case 2019-latest, sets up ports and the name and saves the data on a docker volume.&lt;/p&gt;
&lt;p&gt;If we then run SELECT @@VERSION on this instance of SQL Server we get told:&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Microsoft SQL Server 2019 (RTM-CU13) (KB5005679) - 15.0.4178.1 (X64) Sep 23 2021 16:47:49 Copyright (C) 2019 Microsoft Corporation Developer Edition (64-bit) on Linux (Ubuntu 20.04.3 LTS) &amp;lt;X64&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What if we change the docker-compose file to use 2022-latest?&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;manifest for mcr.microsoft.com/mssql/server:2022-latest not found: manifest unknown: manifest tagged by &amp;#34;2022-latest&amp;#34; is not found
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SQL Server 2022 hasn&amp;rsquo;t been released yet so there is no docker image for it yet. Try this command again in a few months when it is available.&lt;/p&gt;
&lt;p&gt;OK so what else can we try? What about a downgrade to 2017-latest? Will that work?&lt;/p&gt;
&lt;p&gt;SQL Server 2017 starts but the following error gets logged.&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2022-02-23 21:41:15.30 Server Software Usage Metrics is disabled.
&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;2022-02-23 21:41:15.30 spid6s Starting up database &amp;#39;master&amp;#39;.
&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;2022-02-23 21:41:15.34 spid6s Error: 948, Severity: 20, State: 1.
&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;2022-02-23 21:41:15.34 spid6s The database &amp;#39;master&amp;#39; cannot be opened because it is version 904. This server supports version 869 and earlier. A downgrade path is not supported.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Doh we can&amp;rsquo;t downgrade the existing database we have. Probably a good thing really.&lt;/p&gt;
&lt;p&gt;Microsoft release regular updates for SQL Server called CU&amp;rsquo;s (Cumulative Updates), you can see above we are on CU13. Is there a CU14 or CU15 we could try?&lt;/p&gt;
&lt;p&gt;Update the docker compose to: mcr.microsoft.com/mssql/server:2019-CU14-ubuntu-20.04&lt;/p&gt;
&lt;p&gt;At this point I actually got an error&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-tct" data-lang="tct"&gt;2022-02-23 21:50:20.71 Server Error: 17058, Severity: 16, State: 1.
2022-02-23 21:50:20.71 Server initerrlog: Could not open error log file &amp;#39;/var/opt/mssql/log/errorlog&amp;#39;. Operating system error = 5(Access is denied.).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is caused by trying to use SQL Server 2017 but it is easy to fix.&lt;/p&gt;
&lt;p&gt;In docker desktop there is a volumes section, find the volume you are using with SQL Server and delete the errorlog mentioned above.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Docker Desktop" src="https://blog-test.funkysi1701.com/images/2022/docker-desktop1.png" loading="lazy"
width="2945" height="1010"
/&gt;
&lt;/p&gt;
&lt;p&gt;Now if you retry SQL will start OK.&lt;/p&gt;
&lt;p&gt;Repeating the SELECT @@VERSION gives us a new CU&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Microsoft SQL Server 2019 (RTM-CU14) (KB5007182) - 15.0.4188.2 (X64) Nov 3 2021 19:19:51 Copyright (C) 2019 Microsoft Corporation Developer Edition (64-bit) on Linux (Ubuntu 20.04.3 LTS) &amp;lt;X64&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Microsoft SQL Server 2019 (RTM-CU15) (KB5008996) - 15.0.4198.2 (X64) Jan 12 2022 22:30:08 Copyright (C) 2019 Microsoft Corporation Developer Edition (64-bit) on Linux (Ubuntu 20.04.3 LTS) &amp;lt;X64&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;How much easier is this than manually installing updates and rebooting or attempting to uninstall and reinstall SQL Server. As SQL Server 2022 isn&amp;rsquo;t out yet I can&amp;rsquo;t say for certain what issues I may encounter but hopefully it will be as easier as this. And I don&amp;rsquo;t need to backup or restore and databases they are all available as before!&lt;/p&gt;</description></item><item><title>dotnet is 20 years old</title><link>https://blog-test.funkysi1701.com/posts/2022/dotnet-is-20-years-old/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 14 Feb 2022 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/dotnet-is-20-years-old/</guid><category term="DotNet">DotNet</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/FLjBrnPXwAQE8BN.jfif"/><description>&lt;p&gt;Today Microsoft celebrated 20 years since the first version of dotnet was released with a special live stream event.&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/67tCWKnweso" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;A lot has happened in the 20 years of dotnet (or .Net). It is my understanding that .Net was created to rival Java. When the .Net Framework was first created it was a windows only thing, but today modern .Net is a modern run anywhere platform, with .net applications running everywhere from PCs and Laptops, Raspberry Pi&amp;rsquo;s, Mobile phones and tablets (via Xamarin Forms), to Websites and Microservice APIs running on every Cloud platform out there.&lt;/p&gt;
&lt;p&gt;If you want to celebrate this achievment tweet with the hashtag &lt;a href="https://twitter.com/search?q=%23dotnetlovesme" target="_blank" rel="noopener noreferrer"&gt;#DotNetLovesMe&lt;/a&gt;
or download some of the digital swag available from &lt;a href="https://github.com/dotnet-presentations/dotNET20th/tree/main/Swag" target="_blank" rel="noopener noreferrer"&gt;github&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;On Thursday the 17th Feb the first preview of dotnet 7.0 is going to be released, with the latest version 6.0 only being released last November.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="History of DotNet" src="https://blog-test.funkysi1701.com/images/2022/FLj8kj7XEAcW3ng.jpg" loading="lazy"
width="2916" height="1260"
/&gt;
&lt;/p&gt;
&lt;p&gt;The above graphic comes from the following tweet.&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;This is 20 years of &lt;a href="https://twitter.com/hashtag/dotnet?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#dotnet&lt;/a&gt; releases. &lt;a href="https://twitter.com/hashtag/dotNETLovesMe?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#dotNETLovesMe&lt;/a&gt; &lt;a href="https://t.co/Zxfe1SdWTq"&gt;pic.twitter.com/Zxfe1SdWTq&lt;/a&gt;&lt;/p&gt;&amp;mdash; Khalid 🎟 (@buhakmeh) &lt;a href="https://twitter.com/buhakmeh/status/1493220984916258817?ref_src=twsrc%5Etfw"&gt;February 14, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;What do you like about dotnet? When did you first start using it? What are you going to build with it next?&lt;/p&gt;</description></item><item><title>Why developers need a personal site</title><link>https://blog-test.funkysi1701.com/posts/2022/why-do-i-have-a-website/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 25 Jan 2022 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/why-do-i-have-a-website/</guid><category term="Website">Website</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/WHAT-IS-THE-CORPORATE-WEBSITE.jpg"/><description>&lt;p&gt;Is it to share my ideas? Is it to learn new technologies and techniques? Is it to create a following? Is it to educate others? Is it to build some kind of service? Is it some combination of all of these.&lt;/p&gt;
&lt;h2 id="history"&gt;History&lt;a class="anchor ms-1" href="#history" aria-label="Permalink: History"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Back when the web was young and I was first learning HTML. I hand crafted web pages, adding photos I had taken with captions. If I needed a new page I just added a new html page and linked to it from another page.&lt;/p&gt;
&lt;p&gt;As time went on I started to learn mysql and php and my website became a hand crafted php nightmare. I also applied what I learned to help my father run the website for his camera club.&lt;/p&gt;
&lt;p&gt;At some point I started playing with WordPress. I have had various WordPress websites or blogs over the years. WordPress is very powerful you can do so many things, install so many plugins. WordPress runs on php and mysql and as my career started to centre around the .net space, I started to want something that was similar, so I could apply things I had learnt to my own website.&lt;/p&gt;
&lt;p&gt;This has led me to the current state of my website. I have a WordPress blog, with most of my oldest content, my newer content lives on dev.to and I have a Blazor webassembly site that uses the dev.to api to run my new website.&lt;/p&gt;
&lt;p&gt;Blazor webassembly is great, however it has some limitations which I am starting to push against. To host this as cheaply as possible I am using Azure static web apps, so no .net backend all the website is front end. I have some Azure Functions that does the backend bits that I need.&lt;/p&gt;
&lt;p&gt;Google and other bots are not able to find any of my pages except index, due to the way Blazor works. I have got round this by pre rendering the content using &lt;a href="https://prerender.io/" target="_blank" rel="noopener noreferrer"&gt;https://prerender.io/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;My next difficulty is how to generate a sitemap.xml or a rss feed for my blog. This has started to make me question my architecture decisions.&lt;/p&gt;
&lt;p&gt;I could use a hosted solution like &lt;a href="https://ghost.org/" target="_blank" rel="noopener noreferrer"&gt;ghost&lt;/a&gt;
which is popular with a some of my peers. This would solve many of the problems I am currently facing but I wouldn&amp;rsquo;t be able to play with everything as it is hosted and therefore someone else&amp;rsquo;s problem. How important that is I will look at later.&lt;/p&gt;
&lt;p&gt;Another option would be to use github pages, there are quite a few ways to publish a github page, &lt;a href="https://jekyllrb.com/" target="_blank" rel="noopener noreferrer"&gt;Jekyll&lt;/a&gt;
and &lt;a href="https://gohugo.io/" target="_blank" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt;
appear to be the most popular. Both produce static content and both are a new for me to learn. Interestingly I could also publish either to Azure Static Web apps if github pages ends up not being suitable.&lt;/p&gt;
&lt;h2 id="split-in-two"&gt;Split in two&lt;a class="anchor ms-1" href="#split-in-two" aria-label="Permalink: Split in two"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I think my website needs to be split in two. I need a stable blog platform probably using Hugo and github pages. This is what I want to get indexed by the search engines and be the primary way people find out about what I am doing.&lt;/p&gt;
&lt;p&gt;I then have additional sites, that I use as my playground for learning new tech. I can easily link between them and I can tweak the style so they &amp;ldquo;fit&amp;rdquo; nicely together.&lt;/p&gt;
&lt;p&gt;I am still considering what to do with dev.to. I like that I am using it as the backend for my blog posts, and its API gives me that flexibility to display that content where I want.&lt;/p&gt;</description></item><item><title>Using GitHub Actions</title><link>https://blog-test.funkysi1701.com/posts/2022/using-github-actions/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 10 Jan 2022 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/using-github-actions/</guid><category term="GitHub">GitHub</category><category term="DevOps">DevOps</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2022/using-github-actions-banner.png"/><description>&lt;p&gt;I&amp;rsquo;ve been running my website on Azure Static Web Apps for a while and it is pretty cool.&lt;/p&gt;
&lt;p&gt;When you create a Static Web App on Azure you get asked for the github repo of your source code and even the branch to use.
&lt;img class="img-fluid" alt="GitHub Repo for my Static Web App" src="https://blog-test.funkysi1701.com/images/2022/static-web-app-github-repo.png" loading="lazy"
width="734" height="340"
/&gt;
&lt;/p&gt;
&lt;p&gt;Once you have selected this, you get asked for the type of code to deploy, mine is Blazor Web Assembly but you can use Angular, React or Vue.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="GitHub Actions workflow creation" src="https://blog-test.funkysi1701.com/images/2022/github-actions-workflow-creation.png" loading="lazy"
width="730" height="321"
/&gt;
You now have three variables to fill in the location in your code of the Website, the location of your Azure Functions and the output location usually wwwroot. Once you have set these three you can preview the GitHub Actions file that will be created and added to your repository.&lt;/p&gt;
&lt;p&gt;I get something like this&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;name: Azure Static Web Apps CI/CD
on:
push:
branches:
- feature/tempbranch
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- feature/tempbranch
jobs:
build_and_deploy_job:
if: github.event_name == &amp;#39;push&amp;#39; || (github.event_name == &amp;#39;pull_request&amp;#39; &amp;amp;&amp;amp; github.event.action != &amp;#39;closed&amp;#39;)
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_&amp;lt;GENERATED_HOSTNAME&amp;gt; }}
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
action: &amp;#34;upload&amp;#34;
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: &amp;#34;Client&amp;#34; # App source code path
api_location: &amp;#34;Api&amp;#34; # Api source code path - optional
output_location: &amp;#34;wwwroot&amp;#34; # Built app content directory - optional
###### End of Repository/Build Configurations ######
close_pull_request_job:
if: github.event_name == &amp;#39;pull_request&amp;#39; &amp;amp;&amp;amp; github.event.action == &amp;#39;closed&amp;#39;
runs-on: ubuntu-latest
name: Close Pull Request Job
steps:
- name: Close Pull Request
id: closepullrequest
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_&amp;lt;GENERATED_HOSTNAME&amp;gt; }}
action: &amp;#34;close&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This github action will run when you create a Pull Request to the branch mentioned in the file, or if you push code into the branch. This code get added into the .github/workflows/ folder and is the location that all github action workflows live.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t done much with github actions, however I have used Azure DevOps quite a bit. Over on the Azure DevOps side I have created a pipeline that deploys to a Dev environment, then a Test environment and finally a production environment.&lt;/p&gt;
&lt;p&gt;Lets have a look at the workflow that I ended up with and with can break down how it all works. Note I am new to Github actions so if there is a better way of doing this do let me know.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;name: Azure Static Web Apps
on:
push:
branches:
- main
- develop
- feature/*
jobs:
dev:
runs-on: ubuntu-latest
environment:
name: Dev
name: Dev
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_&amp;lt;GENERATED_HOSTNAME&amp;gt; }}
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
action: &amp;#34;upload&amp;#34;
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: &amp;#34;Blog&amp;#34; # App source code path
api_location: &amp;#34;Blog.Func&amp;#34; # Api source code path - optional
output_location: &amp;#34;wwwroot&amp;#34; # Built app content directory - optional
###### End of Repository/Build Configurations ######
test:
if: github.ref == &amp;#39;refs/heads/develop&amp;#39;
runs-on: ubuntu-latest
environment:
name: Test
name: Test
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_&amp;lt;GENERATED_HOSTNAME&amp;gt; }}
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
action: &amp;#34;upload&amp;#34;
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: &amp;#34;Blog&amp;#34; # App source code path
api_location: &amp;#34;Blog.Func&amp;#34; # Api source code path - optional
output_location: &amp;#34;wwwroot&amp;#34; # Built app content directory - optional
###### End of Repository/Build Configurations ######
prod:
if: github.ref == &amp;#39;refs/heads/main&amp;#39;
runs-on: ubuntu-latest
environment:
name: Prod
name: Prod
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_&amp;lt;GENERATED_HOSTNAME&amp;gt; }}
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
action: &amp;#34;upload&amp;#34;
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: &amp;#34;Blog&amp;#34; # App source code path
api_location: &amp;#34;Blog.Func&amp;#34; # Api source code path - optional
output_location: &amp;#34;wwwroot&amp;#34; # Built app content directory - optional
###### End of Repository/Build Configurations ######
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first thing I did was create three Azure Static Web Apps, I am using the free tier so while this is tripling my costs it is all still free! Doing this created three github action workflow files, I deleted two and edited the third, but before I deleted them I made a note of the AZURE_STATIC_WEB_APPS_API_TOKEN. If you look in your settings -&amp;gt; secrets for your repo you will see secrets have been created, this is the secure token that github uses to update your static web app.&lt;/p&gt;
&lt;p&gt;While we are in settings we might as well look at environments. I created a Prod, Test and Dev environment that I was going to use in my github actions.&lt;/p&gt;
&lt;p&gt;Environments can have various rules setup on them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Required reviewers - this is like an approver, a user specified here must approve for the workflow to be deployed&lt;/li&gt;
&lt;li&gt;Wait time - I didn&amp;rsquo;t use this, but it looks like a certain amount of time can be set to pause the deployment. (I assume to do some kind of manual check)&lt;/li&gt;
&lt;li&gt;Deployment Branch - specify what branch are allowed to be deployed to what environments. I specified develop, main and feature branches could be deployed to the Dev environment, develop and main could go on Test and main could go on Prod&lt;/li&gt;
&lt;li&gt;Environment secrets - I didn&amp;rsquo;t use this as my secrets were already created, however it looks like your secrets can be associated with a specific environment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have the static web apps setup and the environments lets look at the github action file.&lt;/p&gt;
&lt;p&gt;First of all I removed the PR stuff and just concentrated on pushes. I wanted my workflow to be.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Push to feature branch&lt;/li&gt;
&lt;li&gt;Deploys to Dev env&lt;/li&gt;
&lt;li&gt;PR feature branch to develop&lt;/li&gt;
&lt;li&gt;Once merged code gets pushed into develop&lt;/li&gt;
&lt;li&gt;Deploys to Test env&lt;/li&gt;
&lt;li&gt;PR develop to main&lt;/li&gt;
&lt;li&gt;Once merged code gets pushed into main&lt;/li&gt;
&lt;li&gt;Deploys to Prod env (after approval)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The approval on deploying to production I think is probably overkill, but I still have it setup like that for now.&lt;/p&gt;
&lt;p&gt;My gh action has three jobs defined as dev: test: and prod: they are all the same except they have the azure_static_web_apps_api_token that is correct for their environment.&lt;/p&gt;
&lt;p&gt;They also each have a environment defined eg&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;environment:
name: Prod
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Lastly Test and Prod have an if test setup, if the test is false the job won&amp;rsquo;t run. Importantly it won&amp;rsquo;t fail it just won&amp;rsquo;t run.&lt;/p&gt;
&lt;p&gt;For Prod this needs to only run on main branch so we have&lt;/p&gt;
&lt;p&gt;if: github.ref == &amp;lsquo;refs/heads/main&amp;rsquo;&lt;/p&gt;
&lt;p&gt;For Test this needs to only run on develop so&lt;/p&gt;
&lt;p&gt;if: github.ref == &amp;lsquo;refs/heads/develop&amp;rsquo;&lt;/p&gt;
&lt;p&gt;I could have a test for develop to only run on feature/* but I have allowed it to run every time.&lt;/p&gt;
&lt;p&gt;There is loads more you can do with github actions, but hopefully this gives you a taste of some of the things you can do. I currently have a mix of Azure DevOps and github actions so I will be working on getting github actions to do more.&lt;/p&gt;
&lt;h2 id="github-actions-cheat-sheet"&gt;GitHub Actions Cheat Sheet&lt;a class="anchor ms-1" href="#github-actions-cheat-sheet" aria-label="Permalink: GitHub Actions Cheat Sheet"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Want a quick-reference guide you can keep beside your keyboard? I&amp;rsquo;ve put together a one-page GitHub Actions cheat sheet covering workflow structure, triggers, runners, contexts, conditions, matrix builds, caching, artifacts, OIDC permissions, and the most common actions — all on a single A4 page.&lt;/p&gt;
&lt;div class="card mb-4 border-primary"&gt;
&lt;div class="card-body"&gt;
&lt;h3 class="card-title"&gt;GitHub Actions Cheat Sheet — PDF&lt;/h3&gt;
&lt;p class="card-text text-muted"&gt;A one-page A4 quick-reference covering workflow structure, triggers, runners, contexts, conditions, matrix builds, caching, artifacts, OIDC permissions, and the most-used actions.&lt;/p&gt;
&lt;div class="d-flex justify-content-between align-items-center mt-3"&gt;
&lt;span class="fs-4 fw-bold text-success"&gt;£2.99&lt;/span&gt;
&lt;a href="https://buy.stripe.com/8x200j5Exe6UgRB5Ne0Ny00" class="btn btn-primary btn-lg" target="_blank" rel="noopener noreferrer"&gt;
Buy Now &amp;rarr;
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Events 2022</title><link>https://blog-test.funkysi1701.com/posts/events/2022/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 01 Jan 2022 01:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/events/2022/</guid><description>&lt;h2 id="2022"&gt;2022&lt;a class="anchor ms-1" href="#2022" aria-label="Permalink: 2022"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event/Talk&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Datacenter Tour: Virtual Experience&lt;/td&gt;
&lt;td&gt;6 December 2022&lt;/td&gt;
&lt;td&gt;Online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2022/ddd-north"&gt;DDD North&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;3 December 2022&lt;/td&gt;
&lt;td&gt;Hull&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LeedsSharp Azure Patterns for Fun and Profit&lt;/td&gt;
&lt;td&gt;24 November 2022&lt;/td&gt;
&lt;td&gt;Leeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.Net Conf (Keynote only)&lt;/td&gt;
&lt;td&gt;8 November 2022&lt;/td&gt;
&lt;td&gt;Online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2022/scottishsummit/"&gt;Scottish Summit&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;10-11 June 2022&lt;/td&gt;
&lt;td&gt;Glasgow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The .Network (Networking event)&lt;/td&gt;
&lt;td&gt;28 April 2022&lt;/td&gt;
&lt;td&gt;Leeds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description></item><item><title>2022 Goals</title><link>https://blog-test.funkysi1701.com/posts/2022/2022-goals/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 01 Jan 2022 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2022/2022-goals/</guid><category term="Goals">Goals</category><description>&lt;p&gt;Lets have a look at what my goals were for 2021. I had eight of them, lets look at them one by one.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Azure certification&lt;/strong&gt;. In May of this year I sat and passed the Azure Fundamentals exam. I am calling this goal as achieved.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mentoring&lt;/strong&gt;. I didn&amp;rsquo;t do anything about working with others or mentoring, so not sure I achieved this one. However I do now work in a development team and I have been reviewing others code and having my own reviewed. We have a junior developer and I am enjoying the opportunities I have to work with him and share my wisdom.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;F#&lt;/strong&gt;. I have done zero work with F# in 2021, so this one I didn&amp;rsquo;t achieve.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cosmos db/Mongo db&lt;/strong&gt;. I have worked with both of these technologies in 2021. I used Cosmos the most with my website, and storing data for it. I used Mongo/Atlas for auditing for a project I did for my previous job. I wouldn&amp;rsquo;t say I was expert in either of these, but I am starting to get a flavour of non SQL Server databases. I should also note that I am using mysql a lot in my latest job, so another non SQL Server technology that I get to use on a daily basis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Give a talk&lt;/strong&gt;. I said last year that maybe I would make baby steps towards doing this, and I have. In the interview for my new job I gave a short presentation (I thought it was bad, but others didn&amp;rsquo;t!) I also gave a short introduction to Blazor talk which went down well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mandlebrot Generator&lt;/strong&gt;. Did nothing on this one as well. I may have googled the code but that is as far as I got.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pwned Pass Mobile App&lt;/strong&gt;. I got an increase in users in 2021 and hence it it still running and I still pay for the API key. I am still considering what to do with it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time for me&lt;/strong&gt;. Achieved this one, had plenty of time for myself.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="not-a-bad-year-but-what-are-my-goals-for-2022"&gt;Not a bad year but what are my goals for 2022?&lt;a class="anchor ms-1" href="#not-a-bad-year-but-what-are-my-goals-for-2022" aria-label="Permalink: Not a bad year but what are my goals for 2022?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt;. I have just purchased a green screen, so my first goal is to learn how to use OBS, how to light myself properly without getting horrible reflections. I have the content for my first talk, the talk I gave at work about Blazor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Conference&lt;/strong&gt;. Attend an in person conference. I am booked to attend Scottish Summit, however it has been postponed due to COVID-19.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Blog More&lt;/strong&gt;. I have been neglecting writing blog posts a bit recently, so I want to do more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Metrics&lt;/strong&gt;. I have been recording various metrics from twitter, github etc and I would like to expand this and make it a service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Profile Pic&lt;/strong&gt;. My profile pic is getting a bit old, so it would be nice to update the images I use online and improve my personal brand.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Rediscovering BASIC as a language</title><link>https://blog-test.funkysi1701.com/posts/2021/back-to-basic/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 28 Dec 2021 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2021/back-to-basic/</guid><category term="BASIC">BASIC</category><category term="History">History</category><category term="Lynx">Lynx</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/FHi_NyOXEAo9YbG.jfif"/><description>&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;How exciting my Lynx Computer from my childhood has come home, all 96k of it &lt;a href="https://t.co/aeN38KBiS8"&gt;pic.twitter.com/aeN38KBiS8&lt;/a&gt;&lt;/p&gt;&amp;mdash; Simon Foster (@funkysi1701) &lt;a href="https://twitter.com/funkysi1701/status/1475139125154037760?ref_src=twsrc%5Etfw"&gt;December 26, 2021&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;I can&amp;rsquo;t remember the syntax for BASIC, luckily I have been able to find the &lt;a href="https://camputers.dk/lynxbooks.html" target="_blank" rel="noopener noreferrer"&gt;Manual&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;All the commands are listed inside so lets see what we can do.&lt;/p&gt;
&lt;p&gt;The Lynx presents you with a command prompt in which you can type text. Back in the 80s we had a tape player to load programs from tape, however I don&amp;rsquo;t have one today so only programs I write can be run.&lt;/p&gt;
&lt;p&gt;PRINT - To write Hello World, you can just type PRINT &amp;ldquo;Hello World&amp;rdquo; and Hello World appears on the screen. To Write a program that displays Hello World, you just write the line number first.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;10 PRINT &amp;#34;Hello World&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run this you type RUN
To view the code you type LIST&lt;/p&gt;
&lt;p&gt;To Edit a specific Line you can use Ctrl+E and type the line number, or you can just write the line out again.&lt;/p&gt;
&lt;p&gt;CLS - This command clears the screen&lt;/p&gt;
&lt;p&gt;INPUT N - stores text typed by the user and stores it in the variable N&lt;/p&gt;
&lt;p&gt;GOTO N - Execution of code continues at Line Number N&lt;/p&gt;
&lt;p&gt;The first Program I wrote with a bit of help from my boys.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;10 CLS
20 PRINT &amp;#34;What is your Age?&amp;#34;
30 INPUT N
40 IF N&amp;gt;5 AND N&amp;lt;41 THEN PRINT &amp;#34;a good age&amp;#34;
50 ELSE IF N&amp;lt;6 THEN PRINT &amp;#34;a spaceman&amp;#34;
60 ELSE IF N&amp;gt;40 THEN PRINT &amp;#34;too old&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;My 4yo didn&amp;rsquo;t like being &amp;ldquo;too young&amp;rdquo; in the original version, so my 6yo helped me change him to be a &amp;ldquo;spaceman&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Not bad and it was fun pair programming with a 6yo, all my typos were quickly spotted, and he easily understood the logic of IF/ELSE/THEN statements.&lt;/p&gt;
&lt;p&gt;The Lynx comes from 1983 and has just 96k of memory. I am very lucky it actually still works, however I have been able to find an emulator so I can write Lynx BASIC from the comfort of my laptop. &lt;a href="https://jynxemulator.wordpress.com/" target="_blank" rel="noopener noreferrer"&gt;jynxemulator&lt;/a&gt;
, it is also on &lt;a href="https://github.com/jonathan-markland/Jynx" target="_blank" rel="noopener noreferrer"&gt;github&lt;/a&gt;
but it doesn&amp;rsquo;t include the ROMs so getting from the website is a better option.&lt;/p&gt;
&lt;p&gt;The developer experience today is so much nicer than it must have been in the 1980s, however back then distractions must have been much reduced.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No internet or google to get answers to your questions&lt;/li&gt;
&lt;li&gt;No Copy/Paste of text&lt;/li&gt;
&lt;li&gt;No Load/Save (unless you have a working disk drive or tape player!)&lt;/li&gt;
&lt;li&gt;No IDE&lt;/li&gt;
&lt;li&gt;No Build or Release process just type RUN&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I then have additional sites, that I use as my playground for learning new tech. I can easily link between them and I can tweak the style so they &amp;ldquo;fit&amp;rdquo; nicely together.&lt;/p&gt;
&lt;p&gt;I am still considering what to do with dev.to. I like that I am using it as the backend for my blog posts, and its API gives me that flexibility to display that content where I want.&lt;/p&gt;</description></item><item><title>Comparing All Good Things and Picard</title><link>https://blog-test.funkysi1701.com/posts/2021/a-comparison-of-all-good-things-and-star-trek-picard/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 15 Dec 2021 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2021/a-comparison-of-all-good-things-and-star-trek-picard/</guid><category term="StarTrek">StarTrek</category><category term="Picard">Picard</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/picard.jpeg"/><description>&lt;p&gt;The final episode of Star Trek: The Next Generation features a few scenes set 25 years into the future. That episode aired May 1994. The newest Star Trek TV show Star Trek Picard has just aired its first episode and this is 25 years and 8 months after that episode. This article may contain minor spoilers for the first episode of Star Trek Picard, you have been warned.&lt;/p&gt;
&lt;p&gt;I thought it would be interesting to compare the two time periods.&lt;/p&gt;
&lt;h2 id="fate-of-picards-crew"&gt;Fate of Picards crew&lt;a class="anchor ms-1" href="#fate-of-picards-crew" aria-label="Permalink: Fate of Picards crew"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In All Good Things&amp;hellip; all of Picards crew are still alive except one. Deanna Troi passed away but it is never revealed how.&lt;/p&gt;
&lt;p&gt;In Star Trek Picard, we know Data has died as featured in the feature file Star Trek Nemesis. From the trailers we know Riker and Troi are still alive. We do not know the fate of Crusher, LaForge and Worf yet, but I am going to assume they are still alive somewhere.&lt;/p&gt;
&lt;p&gt;In both timelines we have one dead crew member.&lt;/p&gt;
&lt;h2 id="living-arrangements"&gt;Living arrangements&lt;a class="anchor ms-1" href="#living-arrangements" aria-label="Permalink: Living arrangements"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In both time lines Picard is living in France at his vineyard.&lt;/p&gt;
&lt;p&gt;In All Good Things&amp;hellip; we do not know who Picard is living with, it is assumed he lives alone, which is why Geordi feels the need to check on him, once he learns about his Irumodic Syndrome.&lt;/p&gt;
&lt;p&gt;In Star Trek Picard we learn that Picard is living with a Romulan couple, due to the involvement Picard made to save the Romulan people when their star went supernova. Picard appears older but for the most part in good health, he can&amp;rsquo;t for example run up a flight of stairs (he is 92 so not surprising really!) and is plagued by dreams from his past.&lt;/p&gt;
&lt;h2 id="romulan-neutral-zone"&gt;Romulan Neutral Zone&lt;a class="anchor ms-1" href="#romulan-neutral-zone" aria-label="Permalink: Romulan Neutral Zone"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In All Good Things&amp;hellip; there is no Neutral Zone, the Romulan empire has been taken over by the Klingons.&lt;/p&gt;
&lt;p&gt;In Star Trek Picard one would assume there is no Neutral Zone as well because the Romulan star system was destroyed. A handful of Romulans survived mostly due to the actions of Picard.&lt;/p&gt;
&lt;h2 id="looks"&gt;Looks&lt;a class="anchor ms-1" href="#looks" aria-label="Permalink: Looks"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As we have seen Patrick Stewart does not appear to be ageing. Below is a comparison of how he looks in the two time frames.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="All Good Things.." src="https://blog-test.funkysi1701.com/images/2021/all-good-things.jpg" loading="lazy"
width="320" height="320"
/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Star Trek Picard" src="https://blog-test.funkysi1701.com/images/2021/picard.jpeg" loading="lazy"
width="880" height="479"
/&gt;
&lt;/p&gt;
&lt;p&gt;I really enjoyed the first episode of Star Trek Picard and it is going to be interesting seeing what other similarities and differences there are between it and All Good Things&amp;hellip;&lt;/p&gt;
&lt;p&gt;Did you know you can track episodes from TNG and Picard in &lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Lone developer to senior, my 2021</title><link>https://blog-test.funkysi1701.com/posts/2021/lone-developer-to-senior-developer-my-2021-story/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 05 Dec 2021 09:00:05 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2021/lone-developer-to-senior-developer-my-2021-story/</guid><category term="FestiveTechCalendar2021">FestiveTechCalendar2021</category><category term="Career">Career</category><category term="LifeStory">LifeStory</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/github/festivetechcalendar-calendar.jpg"/><description>&lt;h2 id="welcome-to-day-5-of-the-festive-tech-calendar"&gt;Welcome to Day 5 of the Festive Tech Calendar!&lt;a class="anchor ms-1" href="#welcome-to-day-5-of-the-festive-tech-calendar" aria-label="Permalink: Welcome to Day 5 of the Festive Tech Calendar!"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Usually at this time of year I like to take the opportunity to look back on the last 12 months, highlight some of my achievements and make a few goals for the new year.&lt;/p&gt;
&lt;p&gt;Like many of you 2021 has been a difficult year, but it has also been a year of change, and I am in a much better place now than at the start of the year.&lt;/p&gt;
&lt;p&gt;To tell you my 2021 story I first need to give you a bit of a history lesson about my career. So, lets fire up your flux capacitor (or Tardis of similar value) and journey back to 2006.&lt;/p&gt;
&lt;h3 id="back-to-2006"&gt;Back to 2006&lt;a class="anchor ms-1" href="#back-to-2006" aria-label="Permalink: Back to 2006"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In 2006 I got my first IT job. My housemate, who was working as an IT Manager for a small Health and Safety Company, suggested I come work with him. I was currently working an admin job with no idea what to do with my life, so I said yes.&lt;/p&gt;
&lt;p&gt;So, in October 2006 I joined as a member of the IT Team. I worked mainly on first line support, but as the IT department was small, I learnt about all sorts of IT things, from fixing printers, setting up the CEOs BlackBerry mobile phone with emails, administering active directory, writing SQL queries to swapping tapes for the weekly backups.&lt;/p&gt;
&lt;p&gt;The company had many faults which I won&amp;rsquo;t discuss here, but the work was varied, and I was always learning something new so I stayed with the company.&lt;/p&gt;
&lt;p&gt;At the end of 2010, the IT Manager resigned, shortly followed by the rest of the IT department. In January 2011 I was IT Manager, I had no staff, plenty of IT problems and no clue what I was doing.&lt;/p&gt;
&lt;p&gt;This was an amazing time for me, I learnt how to interview and hire staff, I learnt more about the different systems we used. It was approximately at this point in time that I switched from being exclusively a SysAdmin to starting to learn Development.&lt;/p&gt;
&lt;p&gt;I had been creating simple websites for a while, mainly using PHP and MySQL. But since I started working in IT I learned more and more about databases, SQL Server and writing T-SQL scripts. I was the companies &amp;ldquo;database guy&amp;rdquo;, so the company naturally asked me to do more and more database work. This led to learning other technologies like MS Access and C# so I could do more and solve more of the company&amp;rsquo;s problems.&lt;/p&gt;
&lt;p&gt;However, the company was small, and I would always be dragged in to fix SysAdmin problems so I never managed to spend 100% of my time doing development, so in 2016 I moved on to my first full time development job.&lt;/p&gt;
&lt;p&gt;The new job was great, but I kept in touch with my old CEO, Ally and helped out with bits of work on the side, writing SQL queries, updating the odd bespoke application.&lt;/p&gt;
&lt;h3 id="back-where-it-all-began"&gt;Back where it all began&lt;a class="anchor ms-1" href="#back-where-it-all-began" aria-label="Permalink: Back where it all began"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In 2019 I started formulating a plan to go back to my old job as a contract developer. To my amazement Ally almost bit my arm off to get me back, agreeing to all my terms. So, in the summer of 2019 I started full time as a contract developer, mostly working from home with the occasionally meeting in the office and supporting the business with IT issues.&lt;/p&gt;
&lt;p&gt;My second stint with the company was different than my first, I was able to concentrate almost exclusively on development work. As the only developer I was in full control of development, I decided to use dotnet and Blazor.&lt;/p&gt;
&lt;p&gt;Late in 2019 I was given advanced warning that the company was being sold. In Feb 2020 the company did get sold, the new owners kept me on to finish the project I was working on but made me a permanent member of staff. In March 2020, the whole company began to work from home due to COVID-19, with parts of the business being furloughed.&lt;/p&gt;
&lt;p&gt;This was a difficult time; on top of the stress the whole world was feeling from the global pandemic I was trying to assist with various IT integrations that you would expect when any company gets sold.&lt;/p&gt;
&lt;h3 id="january-2021"&gt;January 2021&lt;a class="anchor ms-1" href="#january-2021" aria-label="Permalink: January 2021"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is pretty much where you find me in January 2021. I was working remotely developing internal applications with dotnet/Blazor with the occasional Teams meeting to demonstrate what I had built so far.&lt;/p&gt;
&lt;p&gt;Working on your own as a developer is great! You start work and can write code all day. There is no daily stand up, you don&amp;rsquo;t need to explain what you have been working on, or what challenges you are facing. You don&amp;rsquo;t have any process or formality to follow, only what you impose on yourself.&lt;/p&gt;
&lt;p&gt;I created a build/release pipelines in Azure DevOps, I created pull requests that would kick of a build, run my unit tests, and run some static code analysis. I would glance over my PRs but 99% of the time I would approve them.&lt;/p&gt;
&lt;p&gt;This was the greatest weakness of working on my own, no one to suggest ideas of better ways of writing code, no one to bounce ideas off, no one to encourage or be encouraged when I figured out something clever or offer to help you overcome a problem.&lt;/p&gt;
&lt;h3 id="redundancy"&gt;Redundancy&lt;a class="anchor ms-1" href="#redundancy" aria-label="Permalink: Redundancy"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In Mid July I was told that the development function was no longer required, and my job was at risk of redundancy. As I was the only one working in development it sounded very much like a done deal. I had a couple of redundancy meetings to attend and I would need to talk through how various applications worked as part of a handover.&lt;/p&gt;
&lt;p&gt;To be honest I agreed with the decision to make me redundant. New development work was not coming through, although the users of the applications I had developed loved what I had created, upper management were keen to migrate off these systems and use more centrally managed systems. If I was in charge, I would probably have made a similar difficult decision.&lt;/p&gt;
&lt;p&gt;As soon as I found out I was at risk of redundancy I called up a couple of recruitment agents I had spoken to before. They told me that it was a great time to be looking for a job and immediately arranged some interviews for the next week. I also took advantage of social media and asked on twitter if anyone was looking for developers like me. To my surprise this resulted in at least one interview.&lt;/p&gt;
&lt;p&gt;One thing I stressed in all my conversations with recruiters and companies I spoke with, was that I was looking for a &lt;strong&gt;team&lt;/strong&gt;. I wanted to work in a team, bounce ideas off others, mentor others, learn from others. This was the most important thing I wanted in whatever my next role was going to be.&lt;/p&gt;
&lt;p&gt;Other important things for me was continuing to use Azure or similar cloud technologies. However, I always think that the tech stack and technology can be learnt on the job, tech moves so quickly these days that you have to be constantly learning to stay relevant.&lt;/p&gt;
&lt;p&gt;About two weeks after I first found out about my impending redundancy I contacted (or more likely was contacted by) a third recruitment agency. It was this third one that eventually got me a job, however all three were brilliant, and kept me updated and answered all of my questions.&lt;/p&gt;
&lt;p&gt;The next few days were packed with phone calls, interviews, tech tests. I had a lot of different types of companies that I spoke with, from Software Consultancy companies, FinTech companies, Energy suppliers, Legal companies and many others.&lt;/p&gt;
&lt;p&gt;During this time of interviews, I can think of only two in person interviews. The rest made use of Teams, Zoom, Google Meet and even Skype (yes at least one company still uses it for video chats!)&lt;/p&gt;
&lt;p&gt;The usual way the process went was a conversation with the recruiter about a role after which my details were sent to the company, If the company liked the sound of me an initial informal interview was arranged, after that a second more technical interview was held, sometimes there would be a tech test, sometimes it was more technical questions being asked in the interview. Some companies had more stages that this, but this was what I typically encountered.&lt;/p&gt;
&lt;p&gt;I lost count of the actual number of interviews I had, but I used a spreadsheet to try and keep it all straight in my mind. The last thing I wanted was to ask a question about the wrong company!&lt;/p&gt;
&lt;h3 id="positive-no"&gt;Positive No&lt;a class="anchor ms-1" href="#positive-no" aria-label="Permalink: Positive No"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I got plenty of noes from these interviews, however all were phrased as a positive no. That being they liked me as a person but something about my skill or experience wasn&amp;rsquo;t quite right. A friend once described me as an odd mix of junior and senior developer. I agree with that statement, I have a lot of experience in some areas and a real lacking in others.&lt;/p&gt;
&lt;p&gt;A common one was working in a team. Being a lone developer is not good for gaining experience working in a team. However, each time I spoke with companies I stressed that the &lt;strong&gt;team&lt;/strong&gt; was what I was looking for.&lt;/p&gt;
&lt;p&gt;Another weakness of mine is front end. When I am building something, functionality is more important than getting it looking good. I came from a database and backend start, so it is only natural that I am more at home working on these things. Also, my most recent projects are working with Blazor, which is brand new and few companies are doing much with it yet.&lt;/p&gt;
&lt;p&gt;I tried really hard not to be discouraged by these noes and that the right company was just around the corner. One no hit harder than most. I had an initial chat with the team of a FinTech Company and then there was a second interview with the CTO which I felt had gone OK.&lt;/p&gt;
&lt;p&gt;From what I had heard it ticked a lot of boxes, the team sounded good, with lots of support and development opportunities and they were moving to the Cloud, so my Azure experience sounded ideal. The CTO liked me and thought I would be a good fit, but I was part way between a junior and a senior, so he had gone away to try and make a bespoke role for me, eventually it would be a no.&lt;/p&gt;
&lt;p&gt;Looking back, it is easy to see, that this was really encouraging. They tried to create a bespoke role for me! However, at the time all I could think about was all the noes I was hearing.&lt;/p&gt;
&lt;h3 id="the-job-for-me"&gt;The job for me&lt;a class="anchor ms-1" href="#the-job-for-me" aria-label="Permalink: The job for me"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;About the same time, I had my initial interview with the company I would eventually accept a role with. I kept being told that there was a tech test to do, but for some reason it never got sent to me, so the interview featured a lot of tech questions and they really grilled me. I came away without much of a sense of if it went well or not.&lt;/p&gt;
&lt;p&gt;However, they liked me and wanted me to do a presentation at their office. I am rubbish at public speaking and doing presentations, so I thought I will do this presentation, but it is very unlikely they will like what I do.&lt;/p&gt;
&lt;p&gt;The topic of my presentation was how I upskilled a team on a new project or technology. As a lone developer what an earth could I do for a topic like that? I thought about what I had done to upskill myself on various things, however that doesn&amp;rsquo;t really address the question, as they wanted to know more about what I had done to upskill a team.&lt;/p&gt;
&lt;p&gt;I thought back to a time when I helped get a largely un-version controlled codebase into source control and automated the build and release pipeline using Azure and Azure DevOps. This involved talking to SQL and data developers so could be a better option for a presentation.&lt;/p&gt;
&lt;p&gt;I arrived at the office to do my presentation. First of all, I parked next to the factory where all the forklifts were, I was directed to the correct place to park. Then I tried to go to the wrong building, a very helpful employee helped me go to the correct place. I was introduced to the people who would be interviewing me, one of whom I had worked with in the past, who immediately said you should hire this guy, he is an excellent developer! As introductions go, that&amp;rsquo;s not bad!&lt;/p&gt;
&lt;p&gt;In my opinion the presentation was bad. I didn&amp;rsquo;t have a PowerPoint or similar to go with my talk, so I just waffled on for ten minutes about what I had done a few years back about how I helped get source control being used.&lt;/p&gt;
&lt;h3 id="the-next-day-i-got-the-job-offer"&gt;The next day I got the job offer.&lt;a class="anchor ms-1" href="#the-next-day-i-got-the-job-offer" aria-label="Permalink: The next day I got the job offer."&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I was very surprised to get the offer as I thought I had done so badly the day before they would give me another positive no. I took a few hours to think about it, however all my other applications were either not started or waiting for the next stage, so I was 99% sure I would accept.&lt;/p&gt;
&lt;p&gt;I had no idea what to expect when I started, as I didn&amp;rsquo;t really ask many questions at the last interview as I was convinced, I was going to get a no after my presentation.&lt;/p&gt;
&lt;p&gt;I worked my notice period and at the start of October I started my new job. My contract only arrived the day before I started, so in the days before I started my mind was making up reasons why the job would disappear.&lt;/p&gt;
&lt;p&gt;The job started with a two-day induction. Things that were covered on the induction were, mental health, sleep cycles, company values, health and safety and of course a bit of form filling and photocopying passports that you would expect on a first day.&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Back when I had been job hunting, each time I stressed the importance of team. The company I had joined had an amazing focus on supporting its staff and getting the best from each other. I had got the best possible fit for the kind of team I was looking for.&lt;/p&gt;
&lt;p&gt;Usually when I start a new job, I get a large dose of imposter syndrome. Now, two months after I started, I can say, I didn&amp;rsquo;t really get that this time. Maybe it is how the team functions, maybe it is my level of experience, or maybe its just something else.&lt;/p&gt;
&lt;p&gt;I am happy in my new job. There is a lot to learn, both technology and how to work well in this team. But I am supported, there are people to ask question, I am contributing almost from day one. I have already shared a brief talk about my experience with Blazor, which went down better than I expected. I am excited to learn what is next for me.&lt;/p&gt;
&lt;p&gt;If you have read all the way to here, Thank you! This is my story and I hope you have found it interesting. If you are looking for a new role, I would encourage you to focus on the soft skills you are looking for next, if you concentrate on team like I did, there is a good chance you will land in an amazing team.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t forget to check out some of the other great content that is being created by all the amazing &lt;a href="https://festivetechcalendar.com/" target="_blank" rel="noopener noreferrer"&gt;Festive Calendar 2021&lt;/a&gt;
contributors.&lt;/p&gt;</description></item><item><title>2021 mid-year review and progress</title><link>https://blog-test.funkysi1701.com/posts/2021/more-than-halfway-through-2021/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 31 Aug 2021 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2021/more-than-halfway-through-2021/</guid><category term="Goals">Goals</category><description>&lt;p&gt;We are over halfway through 2021, let&amp;rsquo;s have a quick look at some things I have done this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Deployed a new version of the Pre Qualification questionnaire website for my employers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Passed Azure Fundamentals Exam&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mongo DB Atlas - experimented with using it for auditing my application&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SonarCloud - tried to improve the quality of my code&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Azure DevOps API -&amp;gt; built an application to show builds and releases from my Azure DevOps organisation, code is on github&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Experimented with replacing SQL Agent Jobs with Azure Functions, ended up abandoning this project but was a great learning experience&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Played with MS Graph - displaying profile pic from Azure AD but I am the only one in my org with a photo so abandoned this as well&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added a captch to a website to reduce spam&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Charted my Gas and Electricity usage using the Octopus Energy API&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Charted various metrics from services I use, eg twitter followers, github commits, blog posts published&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Started learning react, easily connected it with Azure AD&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Integrated my employers project management system with a postcode API and google maps so can see where in the country different projects are located&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tested dotnet 6 preview and the latest Visual Studio 2022 preview&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I was made redundant and got a new job&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote my first piece of dotnet code to run on a Raspberry Pi&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kept cost of Azure down, by removing unused services, refactoring and optimizing existing services.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wow, I have done loads this year, what is next?&lt;/p&gt;</description></item><item><title>My road to Certification</title><link>https://blog-test.funkysi1701.com/posts/2021/my-road-to-certification/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 11 May 2021 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2021/my-road-to-certification/</guid><category term="Azure">Azure</category><category term="Certification">Certification</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/dev-to/eytphopn3inx2x77m9n5.png"/><description>&lt;p&gt;So today I sat the Azure Fundamentals Certification Exam and passed!
&lt;img class="img-fluid" alt="Alt Text" src="https://blog-test.funkysi1701.com/images/dev-to/eytphopn3inx2x77m9n5.png" loading="lazy"
width="600" height="600"
/&gt;
&lt;/p&gt;
&lt;p&gt;Really pleased with myself at achieving this. It was one of my goals for 2021 so I can tick that off.&lt;/p&gt;
&lt;p&gt;Back in January I booked my first exam, however due to technical problems I didn&amp;rsquo;t get as far as the Exam. In order to be able to sit an exam like this you need a webcam and microphone so you can be monitored remotely to check that you are not cheating. Something in my network was blocking them from seeing my video so it got cancelled before it started.&lt;/p&gt;
&lt;p&gt;My theory is that either my internet connection was playing up at the time, My Pi Hole was blocking something, or something else on my network was blocking the video feed.&lt;/p&gt;
&lt;p&gt;This cancellation put me off Certifications, as I wasn&amp;rsquo;t sure how to debug the issue and find out exactly what the problem was.&lt;/p&gt;
&lt;p&gt;A few months back I won a free Azure Certification for taking part in a skills challenge run by &lt;a href="https://twitter.com/gregor_suttie" target="_blank" rel="noopener noreferrer"&gt;Gregor Suttie&lt;/a&gt;
and &lt;a href="https://twitter.com/Pixel_Robots" target="_blank" rel="noopener noreferrer"&gt;Richard Hooper&lt;/a&gt;
and this was due to expire at the end of this month so I thought why not book a second exam and see if I can get past the technical problems. I didn&amp;rsquo;t do any exam prep as I thought, I wouldn&amp;rsquo;t get that far.&lt;/p&gt;
&lt;p&gt;This time I connected directly to my router, bypassing most of the network, firewall and other items on my network that could possibly cause an issue.&lt;/p&gt;
&lt;p&gt;I cleared my desk, took photos of my ID, took pictures of my desk from every orientation, and waited for the technical issues to start.&lt;/p&gt;
&lt;p&gt;I was in a queue waiting for the exam to start.&lt;/p&gt;
&lt;p&gt;A connection issue has occurred you have been sent to the back of the queue. Oh here we go again!&lt;/p&gt;
&lt;p&gt;But no I connected with the invigilator, who asked to confirm my monitors were disconnected and to move my wallet out of reach off my desk.&lt;/p&gt;
&lt;p&gt;And we are off, I am answering questions from the exam.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t go into detail about the questions, but I whizzed through them, most made me think, some I guessed at. I wasn&amp;rsquo;t expecting to pass, I thought maybe half marks or just under due to my familiarity with Azure. (I have been using it for years which must count for something!)&lt;/p&gt;
&lt;p&gt;I was wrong I passed comfortably and now I have my first certification.&lt;/p&gt;
&lt;p&gt;My advice for you if you have been using Azure for a while is to book this exam and see how you do, you may well pass like me. There are plenty of opportunities to get a free exam, attending conferences like Ignite often qualify you for one, look out for challenges and competitions by #AzureFamily people on twitter as they are very encouraging and helpful in your Certification journey.&lt;/p&gt;
&lt;p&gt;And yes I am thinking about what Certificate to do next!&lt;/p&gt;</description></item><item><title>DotNet on a Raspberry Pi</title><link>https://blog-test.funkysi1701.com/posts/2021/dotnet-on-a-raspberry-pi/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 10 May 2021 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2021/dotnet-on-a-raspberry-pi/</guid><category term="RaspberryPi">RaspberryPi</category><category term="DotNet">DotNet</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/dev-to/e21z7vbamy6w6akhhiwd.jpg"/><description>&lt;p&gt;I have had a Raspberry Pi for a few years and recently I connected it up again, I plugged in the camera and everything worked.&lt;/p&gt;
&lt;p&gt;To start off you can view photos from the camera with the raspistill command. With a bit of clever scripting and the crontab I got the Pi taking pictures every 60 seconds. Even managed to take a nice picture of a robin.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Alt Text" src="https://blog-test.funkysi1701.com/images/dev-to/e21z7vbamy6w6akhhiwd.jpg" loading="lazy"
width="547" height="699"
/&gt;
&lt;/p&gt;
&lt;p&gt;However scripting isn&amp;rsquo;t really programming, and I would like to write a bit more code. Dotnet can run everywhere these days and it made sense to see if it would run on a Raspberry Pi.&lt;/p&gt;
&lt;p&gt;@pete_codes has written a nice guide to getting started with dotnet on a Raspberry Pi &lt;a href="https://www.petecodes.co.uk/install-and-use-microsoft-dot-net-5-with-the-raspberry-pi/" target="_blank" rel="noopener noreferrer"&gt;https://www.petecodes.co.uk/install-and-use-microsoft-dot-net-5-with-the-raspberry-pi/&lt;/a&gt;
This guide and the nuget package &lt;a href="https://www.nuget.org/packages/Unosquare.Raspberry.IO/" target="_blank" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/Unosquare.Raspberry.IO/&lt;/a&gt;
was all I needed to get started taking pictures with my Pi.&lt;/p&gt;
&lt;p&gt;My initial goal is to take some wildlife pictures, stick my camera to a window and take pictures of what flies/crawls/jumps past the window.&lt;/p&gt;
&lt;p&gt;The code I have written so far is available on github &lt;a href="https://github.com/funkysi1701/RaspberryPiDotNet" target="_blank" rel="noopener noreferrer"&gt;https://github.com/funkysi1701/RaspberryPiDotNet&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;So far the code takes a picture, uploads this file to Azure Blob Storage (so as not to fill up the Pi with too many image files) and deletes the image locally.&lt;/p&gt;
&lt;p&gt;Run a dotnet publish -c Release and then cron can run dotnet RaspberryPiDotNet.dll (with full paths to the relevant files)&lt;/p&gt;
&lt;p&gt;I then use crontab to execute the code every 60 seconds.&lt;/p&gt;
&lt;p&gt;My code has an appsetting.json file which has a couple of settings that need completing for my code to work.&lt;/p&gt;
&lt;p&gt;Storage: This is the connection string for Azure Blob Storage
LocalPath: This is the path to where the camera will save its photos to, something like /home/pi/ is all you need but feel free to specify what you need.&lt;/p&gt;
&lt;p&gt;Once the photos are in blob storage I plan to display them somewhere, add options to delete what I don&amp;rsquo;t want, maybe do something timelapsey.&lt;/p&gt;
&lt;p&gt;I also don&amp;rsquo;t have a proper release pipeline and this grates on me a bit. I have been doing a mixture of writing code in VS and pushing that to github and then doing git pull on the Pi, and also writing code directly on the Pi. (VS Code can connect via SSH which is pretty cool!)&lt;/p&gt;</description></item><item><title>Chart energy use with Octopus API</title><link>https://blog-test.funkysi1701.com/posts/2021/charting-my-energy-usage-with-the-octopus-energy-api/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 07 Mar 2021 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2021/charting-my-energy-usage-with-the-octopus-energy-api/</guid><category term="API">API</category><category term="OctopusEnergy">OctopusEnergy</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/dev-to/63ep8hp6ipyn2l4emiop.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="image" src="https://blog-test.funkysi1701.com/images/dev-to/63ep8hp6ipyn2l4emiop.png" loading="lazy"
width="774" height="622"
/&gt;
&lt;/p&gt;
&lt;p&gt;Back when I was a kid, I used to record our weekly gas and electricity meter readings in a little notebook. We then typed these reading into a spreadsheet (this was in the pre-Excel days), which allowed plotting as a line graph.&lt;/p&gt;
&lt;h2 id="how-would-i-go-about-doing-a-similar-thing-today"&gt;How would I go about doing a similar thing today?&lt;a class="anchor ms-1" href="#how-would-i-go-about-doing-a-similar-thing-today" aria-label="Permalink: How would I go about doing a similar thing today?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First off, I have a smart meter that submits meter readings every 30 minutes or so. However, I do not know anyway to get access to these readings directly, short of manually recording them like I did 30 years ago!&lt;/p&gt;
&lt;p&gt;Octopus Energy have a public API which allows you to pull your consumption readings. The smart meter sends your usage to your energy supplier, in my case Octopus, they then process these readings and allow them to be queried with an API they have created. It is not a direct connection to your data, but it is the next best thing.&lt;/p&gt;
&lt;p&gt;Other energy suppliers will hopefully follow this example and allow users access to their consumption data.&lt;/p&gt;
&lt;h2 id="how-do-i-use-the-api"&gt;How do I use the API?&lt;a class="anchor ms-1" href="#how-do-i-use-the-api" aria-label="Permalink: How do I use the API?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using the API is straight forward. Octopus supply you with a secret which you use to authenticate against the API with Basic Auth, no password just a username. Then you just need to pass some details of your meters to get an object containing the last few days meter readings.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developer.octopus.energy/rest/reference/" target="_blank" rel="noopener noreferrer"&gt;API Docs&lt;/a&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GET /v1/electricity-meter-points/{mpan}/meters/{serial_number}/consumption/&lt;/li&gt;
&lt;li&gt;GET /v1/gas-meter-points/{mprn}/meters/{serial_number}/consumption/&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;{mpan}/{mprn} of your gas or electricity meter, and {serial_number} is the serial number of the meters.&lt;/p&gt;
&lt;p&gt;Something to be aware of, I initially collected the last days consumption, which worked, however on one day I encountered a gap in the data for electricity. So, I changed to collect and store the last month&amp;rsquo;s data. I can then query this for what I need.&lt;/p&gt;
&lt;p&gt;Usually, the last 24 hours of data is available after midnight of that day. e.g. at midnight 2nd March all the data for 1st March should be available. This is not guaranteed so don&amp;rsquo;t rely on it, however I see no problem with having a few days delay between charting your usage.&lt;/p&gt;
&lt;p&gt;I am still testing this out but so far, I have three charts for gas (and the same for electricity), the first chart covers a 24-hour period, the next covers a day total over 2 weeks, the final chart covers a total for each month (as I write this I have less than a month&amp;rsquo;s worth of data!)&lt;/p&gt;
&lt;p&gt;For the day and 2 weeks charts, I plot a comparison line of the previous period so you can easily compare the current and previous usage. From my limited testing I have already discovered my usage is very similar day to day.&lt;/p&gt;
&lt;p&gt;Another point of interest is that gas consumption is in m^3 and electricity is in kW/h.
&lt;img class="img-fluid" alt="image" src="https://blog-test.funkysi1701.com/images/dev-to/r5d35ceh0q5zgc15vos8.png" loading="lazy"
width="787" height="621"
/&gt;
&lt;/p&gt;
&lt;p&gt;If you are interested in trying the Octopus Energy API, here is a referral &lt;a href="https://share.octopus.energy/amber-eel-810" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Azure DevOps pre and post approvals</title><link>https://blog-test.funkysi1701.com/posts/2021/azure-devops-release-pipelines-pre-and-post-approval/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 14 Feb 2021 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2021/azure-devops-release-pipelines-pre-and-post-approval/</guid><category term="AzureDevOps">AzureDevOps</category><category term="DevOps">DevOps</category><category term="Azure">Azure</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/dev-to/9k6vo6pfv434u7yq3mt4.png"/><description>&lt;p&gt;Azure DevOps release pipelines have lots of options to do things how you want. One of my favourites is the option for approval.&lt;/p&gt;
&lt;p&gt;There are two ways you can do approvals Pre and Post deployment. Lets look at both.&lt;/p&gt;
&lt;h2 id="pre-deployment-approval"&gt;Pre Deployment Approval&lt;a class="anchor ms-1" href="#pre-deployment-approval" aria-label="Permalink: Pre Deployment Approval"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="image" src="https://blog-test.funkysi1701.com/images/dev-to/9k6vo6pfv434u7yq3mt4.png" loading="lazy"
width="2646" height="1048"
/&gt;
&lt;/p&gt;
&lt;p&gt;Lets imagine you have a simple deployment pipeline that deploys to a test/development environment before deploying to a production environment.&lt;/p&gt;
&lt;p&gt;Pre Deployment Approval happens immediately before the release so in this example, click in the ellipse before the Prod release step.&lt;/p&gt;
&lt;p&gt;You will get a screen like the above, you can select what users need to approve it and how long approval waits before timing out, the default is 30 days, but I tend to use a shorter time out of 3 days.&lt;/p&gt;
&lt;h2 id="post-deployment-approval"&gt;Post Deployment Approval&lt;a class="anchor ms-1" href="#post-deployment-approval" aria-label="Permalink: Post Deployment Approval"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="image" src="https://blog-test.funkysi1701.com/images/dev-to/reiulrhinzqyyon6mrqi.png" loading="lazy"
width="2644" height="809"
/&gt;
&lt;/p&gt;
&lt;p&gt;Post Deployment Approval happens immediately after the release so in this example, click in the circle after the Test release step.&lt;/p&gt;
&lt;p&gt;You will get a screen like the above, with the same settings as before.&lt;/p&gt;
&lt;p&gt;That is pretty much all there is to approvals so either option will prompt you to approve before anything gets deployed to your production environment.&lt;/p&gt;
&lt;h2 id="deployment-hours"&gt;Deployment Hours&lt;a class="anchor ms-1" href="#deployment-hours" aria-label="Permalink: Deployment Hours"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To complicate matters I make use of the following setting to define deployment hours.
&lt;img class="img-fluid" alt="image" src="https://blog-test.funkysi1701.com/images/dev-to/aku2z0dl3m3xkvfvh7wd.png" loading="lazy"
width="2592" height="1318"
/&gt;
&lt;/p&gt;
&lt;p&gt;This setting will start the Prod deployment at 3am Mon-Fri.&lt;/p&gt;
&lt;p&gt;If I configure Post Deployment Approval, as soon as my deploy to Test has completed a request for Approval is sent.&lt;/p&gt;
&lt;p&gt;If I configure Pre Deployment Approval, at 3am Mon-Fri a request for Approval is sent (not ideal if you tend to be asleep at 3am)&lt;/p&gt;
&lt;p&gt;So it looks like Post Deployment Approval is more useful for my use case. However if you deny approval either in Pre or Post approval this will mark the deployment as failed and show Red in your list of deployments.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="image" src="https://blog-test.funkysi1701.com/images/dev-to/vichyb1srgc1ln85hj0o.png" loading="lazy"
width="840" height="377"
/&gt;
&lt;/p&gt;
&lt;p&gt;From a casual glance it looks like the deployment to Test is failing, it isn&amp;rsquo;t I am just opting to not continue my deployment to production.&lt;/p&gt;
&lt;h2 id="my-pipeline"&gt;My Pipeline&lt;a class="anchor ms-1" href="#my-pipeline" aria-label="Permalink: My Pipeline"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="image" src="https://blog-test.funkysi1701.com/images/dev-to/9kprp90t59owfmsmqkcp.png" loading="lazy"
width="3059" height="762"
/&gt;
&lt;/p&gt;
&lt;p&gt;This is how I have my pipeline setup. Deployment happens on Test and doesn&amp;rsquo;t have a post approval step.&lt;/p&gt;
&lt;p&gt;After Test an empty stage called Approval runs and that has a post deployment approval, this happens immediately after Test so you get asked straight away for approval.&lt;/p&gt;
&lt;p&gt;Prod does not start as I have my deployment hours configured. Once it is time for deployment to Prod to start it executes.&lt;/p&gt;
&lt;p&gt;Now a casual look at my past releases, you can easily see which have been stopped by approval and which have failed due to whatever issue, and which have run all the way through to Prod.&lt;/p&gt;
&lt;p&gt;And deployments to Prod can only ever run during my defined deployment window.&lt;/p&gt;
&lt;p&gt;I am interested to hear how you have your deployment pipeline setup. Do you make use of Pre or Post Approvals? Do you ensure deployments always happen at specific times?&lt;/p&gt;</description></item><item><title>Set and achieve 2021 developer goals</title><link>https://blog-test.funkysi1701.com/posts/2020/goals-for-2021/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 28 Dec 2020 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/goals-for-2021/</guid><category term="Goals">Goals</category><description>&lt;p&gt;I didn&amp;rsquo;t make any goals for 2020, or if I did, I didn&amp;rsquo;t officially announce them. 2020 has been a hard year for all of us, 2021 is going to be better.&lt;/p&gt;
&lt;p&gt;Here are a few ideas for my goals for the year ahead.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Azure certification&lt;/li&gt;
&lt;li&gt;Mentoring&lt;/li&gt;
&lt;li&gt;F#&lt;/li&gt;
&lt;li&gt;Cosmos db/Mongo db&lt;/li&gt;
&lt;li&gt;Give a talk&lt;/li&gt;
&lt;li&gt;Mandlebrot Generator&lt;/li&gt;
&lt;li&gt;Pwned Pass Mobile App&lt;/li&gt;
&lt;li&gt;More time for me&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I want to get a certificate to show how much I know. The obvious area for this is Azure. I spend a lot of time playing with Azure, building and deploying to the platform I should be able to get certified in this area. I actually had an exam booked in 2020 but it was an in-person exam so was cancelled when Covid hit. I plan to sit the &lt;a href="https://docs.microsoft.com/en-us/learn/certifications/exams/az-900" target="_blank" rel="noopener noreferrer"&gt;foundation&lt;/a&gt;
exam in the first quarter of 2021 and I will take it from there.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I have had a few times recently where I have been reminded that I don&amp;rsquo;t have much experience working with others. Mostly because I work in a one-man development team so there are limited opportunities in the workplace. I have a few ideas to change this, but this is one of my top priorities for 2021.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;amp; 4) My experience is very Microsoft and C# so I want to spend some time exploring and learning tech that is adjacent to this. A functional language like F# sounds like a good compliment to my existing skills and my data skills are also very SQL server so some document database skills would be a good place to spend some time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Doing a talk has been on my list for years. I am terrified of doing one and with everything online now I don&amp;rsquo;t know if that makes things easier or harder. I don&amp;rsquo;t think 2021 is going to be the year for this but maybe I will take baby steps towards this goal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Twitter recently reminded me about watching a Mandlebrot generate one pixel at a time in the 1980s. I would love to explore the code used to generate them and how fast they currently are to produce.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My Google play store Xamarin forms app that uses the HIBP API has less than 100 users and I am considering closing it down, especially as I pay a monthly fee for API keys. I haven&amp;rsquo;t really decided what to do, maybe I will spend some time improving it, maybe I will close it down, maybe I will build something else.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For many people 2020 has been a hard year, I am one of those.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Building a Twitter Clone</title><link>https://blog-test.funkysi1701.com/posts/2020/building-a-twitter-clone/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 22 Dec 2020 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/building-a-twitter-clone/</guid><category term="Twitter">Twitter</category><category term="Design">Design</category><category term="Architecture">Architecture</category><description>&lt;p&gt;I saw a tweet about building a twitter clone being harder than you would think. So this of course started me thinking how I would go about building something like that.&lt;/p&gt;
&lt;p&gt;Ok so where would I start? First a few assumptions.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Development by a lone developer ie me&lt;/li&gt;
&lt;li&gt;Tech stack will be dotnet and other tech I am familiar with&lt;/li&gt;
&lt;li&gt;Database backend, probably SQL Server but I might use table storage for cost reasons should I try and actually build this. However if I design this well this should be something that could be swapped out as the system grows&lt;/li&gt;
&lt;li&gt;User accounts on the system will be small as I can&amp;rsquo;t imagine anyone ever signing up. Why sign up to a social media platform with no users?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="i-guess-the-next-question-is-what-is-twitter"&gt;I guess the next question is what is Twitter?&lt;a class="anchor ms-1" href="#i-guess-the-next-question-is-what-is-twitter" aria-label="Permalink: I guess the next question is what is Twitter?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A website that allows you to share 280 characters of text with your followers, allows you to follow other users updates and allows other user to follow your updates.&lt;/p&gt;
&lt;p&gt;It also has an API that allow you to do almost everything that you can with the website.&lt;/p&gt;
&lt;p&gt;Then there are of course mobile apps to consider but I am going to assume this is out of scope, however assuming a good enough API then this shouldn&amp;rsquo;t be a problem for future development.&lt;/p&gt;
&lt;h2 id="first-steps"&gt;First Steps&lt;a class="anchor ms-1" href="#first-steps" aria-label="Permalink: First Steps"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To start off with I would concentrate on the API, and then build a web client that makes use of the API.&lt;/p&gt;
&lt;p&gt;So what would my MVP (minimum viable product) be?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;User can authenticate with my API to get a token which allows access to other API endpoints&lt;/li&gt;
&lt;li&gt;User can create a tweet&lt;/li&gt;
&lt;li&gt;User can view own tweets&lt;/li&gt;
&lt;li&gt;User can view tweets of another user&lt;/li&gt;
&lt;li&gt;User can view tweets in their timeline&lt;/li&gt;
&lt;li&gt;User can follow/unfollow other users&lt;/li&gt;
&lt;li&gt;User can search for other users&lt;/li&gt;
&lt;li&gt;User can search for keywords in tweets&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I think that is probably sufficient to build my MVP for the API.&lt;/p&gt;
&lt;p&gt;An interesting side note is that I could use the OAuth Twitter authentication to allow users to login to my twitter clone with the real twitter login details. However this makes no sense to me as we are essentially adding a dependency on the real twitter.&lt;/p&gt;
&lt;p&gt;So what would I use for the frontend? I would start off with a Client Side Blazor frontend. Once I had a proof of concept that worked, I would think about styling and adding the UI elements that are familiar to twitter users.&lt;/p&gt;
&lt;p&gt;The beauty of Client Side Blazor is that I can host cheaply in azure storage and distribute around the world via a CDN.&lt;/p&gt;
&lt;p&gt;Due to the high number of times that follower and following count and other stats are queried I would consider storing these in the database and include a regular job to recalculate them so they don&amp;rsquo;t get out of sync with the data.&lt;/p&gt;
&lt;p&gt;Having said all of this I am very tempted to fire up Visual Studio and see how far I get, and what problems I encounter along the way.&lt;/p&gt;</description></item><item><title>#005: Twitter Cards</title><link>https://blog-test.funkysi1701.com/posts/2020/005-twitter-cards/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 12 Dec 2020 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/005-twitter-cards/</guid><category term="Twitter">Twitter</category><description>&lt;p&gt;It has been a bit of a mad week this week. I joined a new team so lots of time learning what&amp;rsquo;s what and also being pulled in two directions as usual demands come through on top of that.&lt;/p&gt;
&lt;p&gt;My blog runs on Blazor and I have been making use of JavaScript interop to update the html headers and update the page title to match the blog post article. This works great, I load the page and check the headers and they were saying what I wanted.&lt;/p&gt;
&lt;p&gt;The problem was I wanted to add tags for &lt;a href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started" target="_blank" rel="noopener noreferrer"&gt;twitter cards&lt;/a&gt;
This means that when I paste a link to my blog on twitter you get a nice preview and pic of me in the tweet. This was not working at all even though I had the correct headers.&lt;/p&gt;
&lt;p&gt;I eventually figured out that the problem was the fact I was using JavaScript to update my headers after the page had been initially loaded. Twitter was fetching my page before these headers got added and therefore couldn&amp;rsquo;t see the twitter card headers.&lt;/p&gt;
&lt;p&gt;My solution was to use invalid html. Not ideal but it works. I added the required html tags in the body of my page using Blazor/C# instead of using JavaScript to add them into the header. Twitter appears to not be fussy in finding them in the wrong place.&lt;/p&gt;
&lt;p&gt;Twitter provides a validator tool at &lt;a href="https://cards-dev.twitter.com/validator" target="_blank" rel="noopener noreferrer"&gt;Twitter Card Validator&lt;/a&gt;
which my website now passes.&lt;/p&gt;
&lt;p&gt;Not much else to say this week, apart from I am missing Visual Studio and C#, I have been mostly using VS Code on Linux and looking at php which isn&amp;rsquo;t as much fun as my usual day job.&lt;/p&gt;</description></item><item><title>Weekly Update #004</title><link>https://blog-test.funkysi1701.com/posts/2020/weekly-update-004/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 06 Dec 2020 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/weekly-update-004/</guid><category term="SQL">SQL</category><description>&lt;p&gt;I use sp_send_dbmail to send results of sql queries by email to business users. Recently an issue was raised that data was being cut off after 255 characters. To fix this I added @query_no_truncate = 1, however this stopped the column headings from being included. No idea why you can&amp;rsquo;t have all the data and column headings but there you have it.&lt;/p&gt;
&lt;p&gt;What I am doing now is running 2 queries, one to get the headings, and one to get the data. In theory you should be able to combine them with a Union however you then have datatype issues for non text columns so I gave up with that idea.&lt;/p&gt;
&lt;p&gt;My results have 60 something columns (don&amp;rsquo;t ask its for a data import into a third party system!) so I am not typing them all out. I can shove query results into a temporary table and then execute to get a list of columns.&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; tempdb.sys.columns
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; object_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; object_id(&lt;span style="color:#e6db74"&gt;&amp;#39;tempdb..#TempTable&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However I need my list to be horizontal so I can use as column headers. I can use dynamic SQL and a pivot to flip them round.&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DECLARE&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;cols &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; NVARCHAR(&lt;span style="color:#66d9ef"&gt;MAX&lt;/span&gt;), &lt;span style="color:#f92672"&gt;@&lt;/span&gt;query &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; NVARCHAR(&lt;span style="color:#66d9ef"&gt;MAX&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;cols &lt;span style="color:#f92672"&gt;=&lt;/span&gt; STUFF((&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;,&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; QUOTENAME(name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; tempdb.sys.columns
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; object_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; object_id(&lt;span style="color:#e6db74"&gt;&amp;#39;tempdb..#TempTable&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; XML PATH(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;TYPE&lt;/span&gt;).value(&lt;span style="color:#e6db74"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;NVARCHAR(MAX)&amp;#39;&lt;/span&gt;),&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; N&lt;span style="color:#e6db74"&gt;&amp;#39;SELECT &amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;cols &lt;span style="color:#f92672"&gt;+&lt;/span&gt; N&lt;span style="color:#e6db74"&gt;&amp;#39; FROM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; SELECT name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FROM tempdb.sys.columns
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; WHERE object_id = object_id(&amp;#39;&amp;#39;tempdb..#TempTable&amp;#39;&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;) x
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;PIVOT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; MAX(name)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FOR name IN (&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;cols &lt;span style="color:#f92672"&gt;+&lt;/span&gt; N&lt;span style="color:#e6db74"&gt;&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;) y&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Weekly update 003: progress notes</title><link>https://blog-test.funkysi1701.com/posts/2020/weekly-update-003/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 28 Nov 2020 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/weekly-update-003/</guid><category term="OpenSource">OpenSource</category><category term="PHP">PHP</category><description>&lt;p&gt;Been a quiet week, so wasn&amp;rsquo;t expecting to have much to write on here, however a few things happened worth talking about.&lt;/p&gt;
&lt;h2 id="my-first-pr"&gt;My First PR&lt;a class="anchor ms-1" href="#my-first-pr" aria-label="Permalink: My First PR"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A comment was made to me to do something with the postcodes that are in the system I am developing. Find out what projects have postcodes near each other, and that way work can be grouped together and reduce potential mileage costs of staff that need to visit these projects.&lt;/p&gt;
&lt;p&gt;A quick google search found &lt;a href="https://postcodes.io/" target="_blank" rel="noopener noreferrer"&gt;https://postcodes.io/&lt;/a&gt;
which has an API that returns nearby postcodes. It also has a C# wrapper &lt;a href="https://github.com/markembling/MarkEmbling.PostcodesIO" target="_blank" rel="noopener noreferrer"&gt;https://github.com/markembling/MarkEmbling.PostcodesIO&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A comparison of what was being returned from the wrapper and what the API said should be returned revealed that the distance between postcodes wasn&amp;rsquo;t being returned.&lt;/p&gt;
&lt;p&gt;As the code was on GitHub I could easily see how easy or difficult it might be to add the missing bit of information. It was easy! So, I forked the repo and made the change. I published the change to a private NuGet repo in my Azure Dev Ops account. That way I could try my revised package to check it did what I wanted.&lt;/p&gt;
&lt;p&gt;I left a message on the GitHub project letting the owner know I had a potential fix for an issue. The project hadn&amp;rsquo;t been updated in over a year, so the owner may not be interested, or the project may have been abandoned.&lt;/p&gt;
&lt;p&gt;I was in luck just 17 hours after I left a message the project owner said to create a Pull Request, which I did and shortly afterwards my code had been merged in and an updated version of the package existed in the public NuGet feed.&lt;/p&gt;
&lt;p&gt;I have been thinking about contributing to open source for a while. However, I had not seen a project I wanted to contribute to, or a problem that I knew how to fix until now that is.&lt;/p&gt;
&lt;h2 id="php"&gt;PHP&lt;a class="anchor ms-1" href="#php" aria-label="Permalink: PHP"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This week I had a call asking me if I knew PHP?&lt;/p&gt;
&lt;p&gt;I did, over ten years ago, before I got my first IT job, I spent time learning PHP and MySQL. I created a blog, and I also created a website for my Dad&amp;rsquo;s camera club. The code I created back then was awful. No shared code, all the code was associated with the page, or sorts of bugs occurred and as time went by it became increasingly hard to update. The site was well liked but I eventually lost interest and moved on to learn other things.&lt;/p&gt;
&lt;p&gt;This call led to me talking with the head of IT, and later a couple of the developers who have since granted me access to the codebase of a project.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t had time to spend a lot of time looking at the code so far, however this is nothing like the PHP I had built before.&lt;/p&gt;
&lt;p&gt;The project makes use of the &lt;a href="https://laravel.com/" target="_blank" rel="noopener noreferrer"&gt;laravel&lt;/a&gt;
framework and the first file I opened had methods and classes, so apart from the syntax you could think you were looking at C#.&lt;/p&gt;
&lt;p&gt;Another thing that interested me was the project used docker containers, it has automated builds as well. Lots of modern programming ideas that I had some ideas about. I am looking forward to learning more about this project and how I might contribute to it.&lt;/p&gt;</description></item><item><title>Weekly Update #002</title><link>https://blog-test.funkysi1701.com/posts/2020/weekly-update-002/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 21 Nov 2020 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/weekly-update-002/</guid><category term="Docker">Docker</category><category term="Azure">Azure</category><description>&lt;p&gt;I know Active Directory is fussy about clocks being in sync however not sure how todays issue happened.&lt;/p&gt;
&lt;p&gt;I run my docker compose file from Visual Studio and I get a weird error.&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SecurityTokenNotYetValidException: IDX10222: Lifetime validation failed. The token is not yet valid. ValidFrom: &amp;#39;System.DateTime&amp;#39;, Current time: &amp;#39;System.DateTime&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I deleted my containers, open and close Visual Studio a few times, nothing helps. Eventually I think to find out what the time is on my container. It has yesterday&amp;rsquo;s date. What has happened here? Surely recreating containers would have caused them to have todays date? I reboot and everything is fine again.&lt;/p&gt;
&lt;p&gt;Turns out that it is a know issue, see &lt;a href="https://thorsten-hans.com/docker-on-windows-fix-time-synchronization-issue" target="_blank" rel="noopener noreferrer"&gt;https://thorsten-hans.com/docker-on-windows-fix-time-synchronization-issue&lt;/a&gt;
I am using WSL2 and I have now changed back to using Hyper-V and the issue hasn&amp;rsquo;t come back.&lt;/p&gt;
&lt;p&gt;Earlier in the week I spotted my build step was failing.&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;task&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;NuGetToolInstaller@0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Swapping to the next version of the step is all I needed to do to fix it.&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;task&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;NuGetToolInstaller@1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My guess is that support was dropped for this earlier version or there is some other incompatability with .Net 5.&lt;/p&gt;</description></item><item><title>Weekly Update #001</title><link>https://blog-test.funkysi1701.com/posts/2020/weekly-update-001/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 14 Nov 2020 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/weekly-update-001/</guid><category term="DotNet">DotNet</category><description>&lt;p&gt;One of my favourite podcasts is Troy Hunts weekly update. In it he discusses stuff that he has been working on, plus some personal stuff. I am going to attempt to do something similar. It will probably take me a few of these before we get a look and feel that works.&lt;/p&gt;
&lt;h2 id="monday"&gt;Monday&lt;a class="anchor ms-1" href="#monday" aria-label="Permalink: Monday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A week off work, mainly to use it up before year end, plus want to get a few jobs around the house done.&lt;/p&gt;
&lt;p&gt;I did ask the following question on Twitter.&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Hey &lt;a href="https://twitter.com/hashtag/azurefamily?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#azurefamily&lt;/a&gt; and &lt;a href="https://twitter.com/hashtag/dotnet?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#dotnet&lt;/a&gt; developers how do I get more involved in mentoring?&lt;/p&gt;&amp;mdash; Simon Foster (@funkysi1701) &lt;a href="https://twitter.com/funkysi1701/status/1325742644014829568?ref_src=twsrc%5Etfw"&gt;November 9, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;As a one person dev team, my biggest weakness is working with others so any ideas of how to change that are great.&lt;/p&gt;
&lt;h2 id="tuesday"&gt;Tuesday&lt;a class="anchor ms-1" href="#tuesday" aria-label="Permalink: Tuesday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dotnet 5 is out! The latest version of dotnet is released by Microsoft and to celebrate there is &lt;a href="https://www.dotnetconf.net/" target="_blank" rel="noopener noreferrer"&gt;dotnetconf&lt;/a&gt;
to listen to. Due to time zones and family commitments, I haven&amp;rsquo;t listened to an awful lot of it but I did see the keynote and loved the 3 Scott&amp;rsquo;s chat.&lt;/p&gt;
&lt;h2 id="wednesday"&gt;Wednesday&lt;a class="anchor ms-1" href="#wednesday" aria-label="Permalink: Wednesday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My youngest son was 3 today, due to Coronavirus we didn&amp;rsquo;t do much but we celebrated as a family, and he even had a zoom call.&lt;/p&gt;
&lt;h2 id="thursday"&gt;Thursday&lt;a class="anchor ms-1" href="#thursday" aria-label="Permalink: Thursday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Blazor has a new feature &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/components/virtualization?view=aspnetcore-5.0" target="_blank" rel="noopener noreferrer"&gt;Virtualize&lt;/a&gt;
where a list of items can only load the ones on screen. I have been trying to get this to work on my blog, works great running locally but not working in production yet.&lt;/p&gt;
&lt;p&gt;Think I know what might be happening. I use Cloudflare to do my SSL, as Custom SSL certs for the cheaper Azure Web Apps is not supported. Something in Cloudflare is caching or interfering.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zimmergren.net/solved-asp-net-core-blazor-web-sites-does-not-work-with-cloudflare-html-minification/" target="_blank" rel="noopener noreferrer"&gt;https://zimmergren.net/solved-asp-net-core-blazor-web-sites-does-not-work-with-cloudflare-html-minification/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Turning off HTML minification fixed my issue!&lt;/p&gt;
&lt;p&gt;One additional thing I added to my Blog is the config page which details some of the config settings. I think this probably came from &lt;a href="https://www.hanselman.com/blog/adding-a-git-commit-hash-and-azure-devops-build-number-and-build-id-to-an-aspnet-website" target="_blank" rel="noopener noreferrer"&gt;https://www.hanselman.com/blog/adding-a-git-commit-hash-and-azure-devops-build-number-and-build-id-to-an-aspnet-website&lt;/a&gt;
but it was a while ago when I first did this on another project.&lt;/p&gt;
&lt;p&gt;At the moment we have .net Version, Commit and Build links.&lt;/p&gt;
&lt;p&gt;The .Net Version is obtained from&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few other bits of info can be obtained from System.Runtime.InteropServices.RuntimeInformation which I have included on the page for fun. There are probably security concerns with exposing all this info publicly so something to bear in mind if you try this.&lt;/p&gt;
&lt;p&gt;Build Info is passed to my code by a build step&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-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;script&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;(echo $(Build.BuildNumber) &amp;amp;&amp;amp; echo $(Build.BuildId)) &amp;gt; .buildinfo.json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;displayName&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Emit build number&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;workingDirectory&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;$(Build.SourcesDirectory)/src/WebBlog&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;failOnStderr&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This simply passed the build id and number which are stored as variabled and saves them in a text file.&lt;/p&gt;
&lt;p&gt;I then have a class that reads them and constructs a link.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Microsoft.Extensions.Hosting;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.IO;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.Linq;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.Reflection;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; WebBlog
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AppVersionInfo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; _buildFileName = &lt;span style="color:#e6db74"&gt;&amp;#34;.buildinfo.json&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;readonly&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; _buildFilePath;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; _buildNumber = &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; _buildId = &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; _gitHash = &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; _gitShortHash = &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; AppVersionInfo(IHostEnvironment hostEnvironment)
&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; _buildFilePath = Path.Combine(hostEnvironment.ContentRootPath, _buildFileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; BuildNumber
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(_buildNumber))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (File.Exists(_buildFilePath))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; fileContents = File.ReadLines(_buildFilePath).ToList();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (fileContents.Count &amp;gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _buildNumber = fileContents[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (fileContents.Count &amp;gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _buildId = fileContents[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(_buildNumber))
&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; _buildNumber = DateTime.UtcNow.ToString(&lt;span style="color:#e6db74"&gt;&amp;#34;yyyyMMdd&amp;#34;&lt;/span&gt;) + &lt;span style="color:#e6db74"&gt;&amp;#34;.0&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(_buildId))
&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; _buildId = &lt;span style="color:#e6db74"&gt;&amp;#34;123456&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; _buildNumber;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; BuildId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(_buildId))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; _ = BuildNumber;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; _buildId;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; GitHash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(_gitHash))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; version = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0.0+LOCALBUILD&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; appAssembly = &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(AppVersionInfo).Assembly;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; infoVerAttr = (AssemblyInformationalVersionAttribute)appAssembly
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .GetCustomAttributes(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(AssemblyInformationalVersionAttribute)).FirstOrDefault();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (infoVerAttr != &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; infoVerAttr.InformationalVersion.Length &amp;gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; version = infoVerAttr.InformationalVersion;
&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; _gitHash = version[(version.IndexOf(&lt;span style="color:#e6db74"&gt;&amp;#39;+&amp;#39;&lt;/span&gt;) + &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)..];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; _gitHash;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; ShortGitHash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.IsNullOrEmpty(_gitShortHash))
&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; _gitShortHash = GitHash.Substring(GitHash.Length - &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; _gitShortHash;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The BuildId and BuildNumber properties just fetch the details saved into the text file during the build. This can then be passed to build the build link.&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-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://dev.azure.com/{OrgName}/{RepoName}/_build/results?buildId=@appInfo.BuildId&amp;amp;view=results&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @appInfo.BuildNumber
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, the GitHash properties need to fetch the hash and shorthash of the commit which is a bit more complex. This is achieved using the following line in your build.&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-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;task&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;DotNetCoreCLI@2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;displayName&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;Publish&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;command&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;publish&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;publishWebProjects&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;arguments&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;--output $(Build.ArtifactStagingDirectory) /p:SourceRevisionId=$(Build.SourceVersion)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;/p:SourceRevisionId=$(Build.SourceVersion) add the revision hash to [assembly: AssemblyInformationalVersion] during the build which can then be extracted using the gitHash property above, before being passed into the commit link.&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-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://github.com/{OrgName}/{RepoName}/commit/@appInfo.GitHash&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @appInfo.ShortGitHash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Security Headers</title><link>https://blog-test.funkysi1701.com/posts/2020/security-headers/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 26 Sep 2020 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/security-headers/</guid><category term="DotNet">DotNet</category><category term="Security">Security</category><description>&lt;p&gt;Have you wondered what info you are leaking via your response headers?, do you want some kind of guide about what headers to set or remove altogether?&lt;/p&gt;
&lt;p&gt;Head on over to &lt;a href="https://securityheaders.com/" target="_blank" rel="noopener noreferrer"&gt;https://securityheaders.com/&lt;/a&gt;
This is a site created by security expert &lt;a href="https://scotthelme.co.uk" target="_blank" rel="noopener noreferrer"&gt;Scott Helme&lt;/a&gt;
that rates a URL based on what response headers it can see.&lt;/p&gt;
&lt;p&gt;I am pleased to say &lt;a href="https://www.funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;https://www.funkysi1701.com&lt;/a&gt;
is now getting an A.
&lt;img class="img-fluid" alt="Alt Text" src="https://blog-test.funkysi1701.com/images/2020/07rwumi94fz141hwessu.png" loading="lazy"
width="2434" height="496"
/&gt;
&lt;/p&gt;
&lt;p&gt;So how do you add/remove headers in dotnet core?&lt;/p&gt;
&lt;p&gt;In my configure method in Startup.cs I have the following code block.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.Use(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; next =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; context =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.Response.OnStarting(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; () =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.Response.Headers.Add(&lt;span style="color:#e6db74"&gt;&amp;#34;Permissions-Policy&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;microphone=()&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.Response.Headers.Remove(&lt;span style="color:#e6db74"&gt;&amp;#34;Server&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.Response.Headers.Remove(&lt;span style="color:#e6db74"&gt;&amp;#34;X-Powered-By&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context.Response.Headers.Remove(&lt;span style="color:#e6db74"&gt;&amp;#34;X-AspNet-Version&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Task.CompletedTask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; next(context);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have only included a few of the headers I am adding as the excellent &lt;a href="https://securityheaders.com/" target="_blank" rel="noopener noreferrer"&gt;https://securityheaders.com/&lt;/a&gt;
can tell you which headers you should add and what options you might want.&lt;/p&gt;</description></item><item><title>Returning to blogging as a developer</title><link>https://blog-test.funkysi1701.com/posts/2020/back-to-blogging/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 25 Sep 2020 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/back-to-blogging/</guid><category term="Blogging">Blogging</category><category term="Blazor">Blazor</category><category term="DotNet">DotNet</category><description>&lt;p&gt;My last blog post was over six months ago.&lt;/p&gt;
&lt;p&gt;Covid 19 has hit the world, and I will be honest I have found it a challenging time.&lt;/p&gt;
&lt;p&gt;My Blog had gotten into a bit of a mess. It had become fragmented with different versions of the same thing; I will attempt to explain what has become of my blog.&lt;/p&gt;
&lt;p&gt;The original WordPress site can currently be found at &lt;a href="https://www.pwnedpass.com/" target="_blank" rel="noopener noreferrer"&gt;https://www.pwnedpass.com/&lt;/a&gt;
I would prefer it to be on a sub-domain of funkysi1701.com but for some reason I haven&amp;rsquo;t been able to get that to work, not sure if it is a limitation of my hosting package. I like WordPress, it is very flexible, easy to get blog posts out there. But I want to write content about development and having a site I can tinker with is important to me.&lt;/p&gt;
&lt;p&gt;Most of my WordPress blogs have been imported into dev.to and a few extra have been written on this platform. I like dev.to it is a wonderful place to share content and it has one or two extra features I like.&lt;/p&gt;
&lt;p&gt;dev.to has an integration with Stackbit/Netlify and this became &lt;a href="https://www.funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;https://www.funkysi1701.com&lt;/a&gt;
. I like having a personal site, but having the same content as dev.to. To add content to this site all I need to do is write it on dev.to and some magic will go on behind the scenes and new content will be published.&lt;/p&gt;
&lt;p&gt;However, as a developer I don&amp;rsquo;t like magic, I want to understand what is going on a fiddle with all the settings and make it do what I want.&lt;/p&gt;
&lt;p&gt;dev.to has an API, I can build a site in .Net Core and make API calls to fetch the content I want. I understand APIs, I understand .Net and can customise my site exactly how I want it, plus play about with a .net website. This is what &lt;a href="https://www.funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;https://www.funkysi1701.com&lt;/a&gt;
is now.&lt;/p&gt;
&lt;p&gt;So what have I built so far. I have a Server Side Blazor site running .Net 5. Why Server Side and not Client Side I hear you ask? Well only because I have more experience with Server Side and know how to quickly create a website with that technology, I may change it as time goes by, but we will see.&lt;/p&gt;
&lt;p&gt;I have two pages a list of my blog posts and a page that displays the content. Both of these use the dev.to API. I lied, there is a third page I hacked together to do some page redirection from the WordPress URLs. This is something I will change as time goes on.&lt;/p&gt;
&lt;p&gt;There are lots of improvements I want to do, there are probably also lots of broken images or links as well. Hopefully, this will result in a good platform to blog about as well as on.&lt;/p&gt;</description></item><item><title>Testing expiring SSL certificates</title><link>https://blog-test.funkysi1701.com/posts/2020/testing-for-expiring-ssl-certificates/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 03 Mar 2020 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2020/testing-for-expiring-ssl-certificates/</guid><category term="Security">Security</category><category term="SSL">SSL</category><category term="Testing">Testing</category><description>&lt;p&gt;Let&amp;rsquo;s Encrypt is amazing, you can easily add SSL certificates to any website and automate the renewal process. I have talked &lt;a href="https://www.funkysi1701.com/posts/2018/lets-encrypt-is-awesome/" target="_blank" rel="noopener noreferrer"&gt;before&lt;/a&gt;
about how impressive it is.&lt;/p&gt;
&lt;p&gt;Once you start adding SSL certificates to your production sites however you may want to check when they expire so you don&amp;rsquo;t get caught out. You can always open your site in your favourite browser and view the certificate information and expiry date.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="SSL Cert" src="https://blog-test.funkysi1701.com/images/2020/jb78re4fmm1ofx81f3mu.jpg" loading="lazy"
width="671" height="608"
/&gt;
However there is a way to automate this check.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;[Fact]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; IsSSLExpiring()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; handler = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; HttpClientHandler
&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; ServerCertificateCustomValidationCallback = CustomCallback
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; client = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; HttpClient(handler);
&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; HttpResponseMessage response = client.GetAsync(&lt;span style="color:#e6db74"&gt;&amp;#34;https://www.example.com&amp;#34;&lt;/span&gt;).GetAwaiter().GetResult();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Assert.True(response.IsSuccessStatusCode);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; CustomCallback(HttpRequestMessage arg1, X509Certificate2 arg2, X509Chain arg3, SslPolicyErrors arg4)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; now = DateTime.UtcNow;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; expire = arg2.NotAfter;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; diff = (expire - now).TotalDays;
&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; Assert.InRange(diff, &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; arg4 == SslPolicyErrors.None;
&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;This code gets the SSL expiry date from &lt;a href="https://www.example.com" target="_blank" rel="noopener noreferrer"&gt;https://www.example.com&lt;/a&gt;
and will fail the xunit test if the expiry date is less than 30 days in the future. I then schedule my tests to run regularly on all my environments with a Let&amp;rsquo;s Encrypt Certificate and this gives me advanced warning if a SSL certificate is about to expire.&lt;/p&gt;
&lt;p&gt;The Assert.InRange(diff, 30, 1000) line will fail the test if the expiry date is less than 30 days or greater than 1000, but as the default expiry for Let&amp;rsquo;s Encrypt certificates is three months it will never be greater than 1000 days even with a freshly installed certificate. These values can be tweaked to suit your use case, however 30 days is enough time for me to investigate what is happening.&lt;/p&gt;
&lt;p&gt;To execute my tests I use a scheduled build in Azure DevOps, but anything that regularly can run your tests will do the job.&lt;/p&gt;
&lt;p&gt;The code above is just a simple example to get your started for my purposes I have put all my URLs into config files and just pass these into my tests, so I don&amp;rsquo;t need a custom test for every different URL.&lt;/p&gt;</description></item><item><title>Picard is back!</title><link>https://blog-test.funkysi1701.com/posts/2019/picard-is-back/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 08 Aug 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/picard-is-back/</guid><category term="StarTrek">StarTrek</category><category term="Picard">Picard</category><category term="PatrickStewart">PatrickStewart</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2018/08/download.jpg"/><description>&lt;p&gt;It has just been announced at the annual Star Trek Las Vegas (&lt;a href="https://twitter.com/hashtag/STLV" target="_blank" rel="noopener noreferrer"&gt;#STLV&lt;/a&gt;
) convention that Patrick Stewart is going to return to his role as Jean-Luc Picard in a new TV Show.&lt;/p&gt;
&lt;iframe title="YouTube video: Patrick Stewart on the return of Jean-Luc Picard" type="text/html" width="662" height="373" src="https://www.youtube.com/embed/aCKQp1sGVRQ?version=3&amp;amp;rel=1&amp;amp;fs=1&amp;amp;autohide=2&amp;amp;showsearch=0&amp;amp;showinfo=1&amp;amp;iv_load_policy=1&amp;amp;wmode=transparent" allowfullscreen="true" style="border:0;"&gt;&lt;/iframe&gt;
&lt;p&gt;Few other details have been announced other than the TV show will take place 20 years after the film Star Trek: Nemesis and will feature the character of Jean-Luc Picard.&lt;/p&gt;
&lt;p&gt;Lets run though a few things I would like to see from this new show.&lt;/p&gt;
&lt;h2 id="low-on-action"&gt;Low on Action&lt;a class="anchor ms-1" href="#low-on-action" aria-label="Permalink: Low on Action"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Star Trek: Discovery is a great show and has brought Star Trek back to our TV shows. However it is an action show, it zooms along so fast and with so much action I would appreciate a show that can takes its time a bit more.&lt;/p&gt;
&lt;p&gt;I want a show that can show Picard carefully considering some moral issue and making a decision. Something we were used to seeing on TNG.&lt;/p&gt;
&lt;h2 id="feature-picards-excellent-speeches"&gt;Feature Picard’s excellent speeches&lt;a class="anchor ms-1" href="#feature-picards-excellent-speeches" aria-label="Permalink: Feature Picard’s excellent speeches"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the best features I can think of Jean-Luc Picard is his ability to make speeches about one issue or other.&lt;/p&gt;
&lt;p&gt;Lets look at a few examples:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Insurection&lt;/strong&gt; : Picard speaks about the forced relocation of a group of people.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How many people does it take, Admiral, before it becomes wrong? Hmm? A thousand, fifty thousand, a million? How many people does it take, Admiral?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt; &lt;strong&gt;Contact&lt;/strong&gt; : Picard is hell bent on revenge for what the Borg have done to him and refuses to destroy the Enterprise to save his crew.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I will not sacrifice the Enterprise. We’ve made too many compromises already. Too many retreats. They invade our space and we fall back. They assimilate entire worlds, and we fall back. Not again! The line must be drawn here, …this far, no further! And I will make them pay for what they’ve done.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Measure of a Man&lt;/strong&gt; : Picard argues for the rights of Data.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You see, he’s met two of your three criteria for sentience, so what if he meets the third. Consciousness in even the smallest degree. What is he then? I don’t know. Do you? (to Riker) Do you? (to Phillipa) Do you? Well, that’s the question you have to answer. Your Honour, the courtroom is a crucible. In it we burn away irrelevancies until we are left with a pure product, the truth for all time. Now, sooner or later, this man or others like him will succeed in replicating Commander Data. And the decision you reach here today will determine how we will regard this creation of our genius. It will reveal the kind of a people we are, what he is destined to be. It will reach far beyond this courtroom and this one android. It could significantly redefine the boundaries of personal liberty and freedom, expanding them for some, savagely curtailing them for others. Are you prepared to condemn him and all who come after him to servitude and slavery? Your Honour, Starfleet was founded to seek out new life. Well, there it sits. Waiting. You wanted a chance to make law. Well, here it is. Make a good one.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="ask-important-questions"&gt;Ask important questions&lt;a class="anchor ms-1" href="#ask-important-questions" aria-label="Permalink: Ask important questions"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We live in uncertain times. There are lots of pressures on today’s world and we need to acknowledge these. Picard is an excellent character to use to ask important questions of the day.&lt;/p&gt;
&lt;p&gt;What does it mean to be human?&lt;br&gt;
How should we treat people that are different to us?&lt;br&gt;
How should we react to extremism?&lt;/p&gt;
&lt;h2 id="deal-with-his-age"&gt;Deal with his age&lt;a class="anchor ms-1" href="#deal-with-his-age" aria-label="Permalink: Deal with his age"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the last episode of TNG a future version of Picard is shown 25 years into the future. This is a similar time period so it will be interesting to compare the two. Have Picard look back on his life and ask questions about his life choices.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Picard" src="https://blog-test.funkysi1701.com/images/2018/08/all-good-things.jpg" loading="lazy"
width="320" height="320"
/&gt;
&lt;/p&gt;
&lt;h2 id="be-consistent-with-his-past"&gt;Be consistent with his past&lt;a class="anchor ms-1" href="#be-consistent-with-his-past" aria-label="Permalink: Be consistent with his past"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Picard is a well known character. So writers please don’t change him. I want a character we know, not a character that looks like Picard but acts in a way contrary to what we would expect.&lt;/p&gt;
&lt;p&gt;Picard has a history we know, he served on the stargazer and of course the Enterprise, he has an artificial heart, he was assimiliated by the Borg. All&lt;/p&gt;
&lt;h2 id="reference-50-years-of-star-trek"&gt;Reference 50 years of Star Trek&lt;a class="anchor ms-1" href="#reference-50-years-of-star-trek" aria-label="Permalink: Reference 50 years of Star Trek"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Discovery and Enterprise are TV shows which have a problem. There is Trek going on after them which imposes a few rules on what can and can’t be done.&lt;/p&gt;
&lt;p&gt;This is a TV Show that will take place after every other Trek TV and Film and can do whatever the creators want. This gives freedom, but it also gives the responsibility to reference what has gone before.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Picard" src="https://blog-test.funkysi1701.com/images/2018/08/download.jpg" loading="lazy"
width="275" height="183"
/&gt;
&lt;/p&gt;
&lt;p&gt;The 2009 Star Trek film features the destruction of Romulus and Spock travelling back in time. How about Picard dealing with surviving Romulans helping rebuild their society, continuing the work that Spock started in the TNG episode Unification.&lt;/p&gt;
&lt;p&gt;I look forward to finding out what the Star Trek production team has in store for us. If they have Patrick Stewart convinced I am sure it is going to be good.&lt;/p&gt;
&lt;p&gt;Did you know you can track episodes from TNG and Picard in &lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Create Azure resources via Terraform</title><link>https://blog-test.funkysi1701.com/posts/2019/infrastructure-as-code-creating-azure-resources-with-terraform/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 11 May 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/infrastructure-as-code-creating-azure-resources-with-terraform/</guid><category term="Azure">Azure</category><category term="Infrastructure">Infrastructure</category><category term="Terrafrom">Terrafrom</category><category term="DevOps">DevOps</category><description>&lt;p&gt;Terraform is a way to script the creation of Azure Resources. By scripting the creation of your resources you can run them again and again and be certain that everything is configured exactly the same as the script has specified. No more forgetting to tick the tick box, if it’s in your script then it will be deployed with exactly the same configuration.&lt;/p&gt;
&lt;p&gt;The process of executing a terraform script follows this basic process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;terraform init&lt;/strong&gt; – Initialises the terraform directory
&lt;strong&gt;terraform plan&lt;/strong&gt; – generates and displays what will be executed
&lt;strong&gt;terraform apply&lt;/strong&gt; – applies the terraform script to your Azure subscription
&lt;strong&gt;terraform destroy&lt;/strong&gt; – deletes your Azure resource that were created in the previous step&lt;/p&gt;
&lt;p&gt;Lets look at how you might execute a terraform script from your build or release pipeline.&lt;/p&gt;
&lt;p&gt;I am executing my terraform scripts from my release pipeline and as I don’t want to check binaries into my source code I am going to add a bit of plumbing to get things in the right places. The terraform binary can be obtained from &lt;a href="https://www.terraform.io/downloads.html" target="_blank" rel="noopener noreferrer"&gt;https://www.terraform.io/downloads.html&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;To start with I am executing a Powershell script to download the terraform binary, this is in the form of a zip file, so i need to download and unzip it.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#Download&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$url = &lt;span style="color:#e6db74"&gt;&amp;#34;https://releases.hashicorp.com/terraform/0.11.13/terraform_0.11.13_windows_amd64.zip&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$output = &lt;span style="color:#e6db74"&gt;&amp;#34;terraform.zip&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(New-Object System.Net.WebClient).DownloadFile($url, $output)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#Unzip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Add-Type -AssemblyName System.IO.Compression.FileSystem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#66d9ef"&gt;System.IO.Compression.ZipFile&lt;/span&gt;]::ExtractToDirectory($output, Get-Location)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that I have the terraform binaries I can just run Azure Cli and execute the terraform commands above.&lt;/p&gt;
&lt;p&gt;Now it is time to look at the the terraform script. This particular script creates a resource group, an app service plan and a webapp.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Configure the Microsoft Azure Provider
provider &amp;#34;azurerm&amp;#34; {
subscription_id = &amp;#34;&amp;#34;
client_id = &amp;#34;&amp;#34;
client_secret = &amp;#34;&amp;#34;
tenant_id = &amp;#34;&amp;#34;
}
resource &amp;#34;azurerm_resource_group&amp;#34; &amp;#34;rg&amp;#34; {
name = &amp;#34;resource-group&amp;#34;
location = &amp;#34;northeurope&amp;#34;
}
resource &amp;#34;azurerm_app_service_plan&amp;#34; &amp;#34;plan&amp;#34; {
name = &amp;#34;planname&amp;#34;
location = &amp;#34;${azurerm_resource_group.rg.location}&amp;#34;
resource_group_name = &amp;#34;${azurerm_resource_group.rg.name}&amp;#34;
sku {
tier = &amp;#34;Standard&amp;#34;
size = &amp;#34;S1&amp;#34;
}
}
resource &amp;#34;azurerm_app_service&amp;#34; &amp;#34;webapp&amp;#34; {
name = &amp;#34;example-app-service&amp;#34;
location = &amp;#34;${azurerm_resource_group.rg.location}&amp;#34;
resource_group_name = &amp;#34;${azurerm_resource_group.rg.name}&amp;#34;
app_service_plan_id = &amp;#34;${azurerm_app_service_plan.plan.id}&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are four guids that you need to fill in from your azure subscription and to find these you need to run a few commands from Azure Cli. Check out
&lt;a href="https://learn.microsoft.com/en-us/azure/virtual-machines/linux/terraform-install-configure" target="_blank" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/virtual-machines/linux/terraform-install-configure&lt;/a&gt;
for more detail on these commands.&lt;/p&gt;
&lt;p&gt;Run these either from Azure Cloud Shell or from Powershell command prompt after Azure Cli has been installed.&lt;/p&gt;
&lt;p&gt;az login – to login to azure a browser window will open up.&lt;/p&gt;
&lt;p&gt;az account show –query &amp;ldquo;{subscriptionId:id, tenantId:tenantId}&amp;rdquo;
This will show you your subscription id.&lt;/p&gt;
&lt;p&gt;az account set –subscription=&amp;quot;${SUBSCRIPTION_ID}&amp;quot;
Where ${SUBSCRIPTION_ID} is the subscription id you found in the last step.&lt;/p&gt;
&lt;p&gt;az ad sp create-for-rbac –role=&amp;ldquo;Contributor&amp;rdquo; –scopes=&amp;quot;/subscriptions/${SUBSCRIPTION_ID}&amp;quot;
Where ${SUBSCRIPTION_ID} is the subscription id you found in the last step and assumes you have permission to the subscription.&lt;/p&gt;
&lt;p&gt;This last command will about a series of Guids which you need to fill in at the top of your terraform file appId = client_id, password = client_secret, tenant = tenant_id and subscription_id you already have.&lt;/p&gt;
&lt;p&gt;This just gives you a taste of what you can do with terraform. Looking at the &lt;a href="https://docs.microsoft.com/en-us/azure/terraform/" target="_blank" rel="noopener noreferrer"&gt;Azure Terraform docs&lt;/a&gt;
there are loads of different resources you can create and even a &lt;a href="https://github.com/terraform-providers/terraform-provider-azurerm" target="_blank" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;
with some samples.&lt;/p&gt;</description></item><item><title>Gated Release</title><link>https://blog-test.funkysi1701.com/posts/2019/gated-release/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 05 Apr 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/gated-release/</guid><category term="Azure">Azure</category><category term="API">API</category><category term="ApplicationInsights">ApplicationInsights</category><category term="DevOps">DevOps</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2019/04/image.png"/><description>&lt;p&gt;Automated releases of software are great but how can we add an element of feedback so only good releases go live.&lt;/p&gt;
&lt;p&gt;I have been using Azure DevOps to release my PwnedPass android app to the Google Play Store for a while now. There are options to deploy to the alpha, Beta or Production tracks and even to set % of users to target. For the full range of options check out the Google Play &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vsclient.google-play" target="_blank" rel="noopener noreferrer"&gt;extension&lt;/a&gt;
for Azure DevOps.&lt;/p&gt;
&lt;p&gt;My release starts by publishing to 10% of users on the production track, my next step makes use of the increase rollout option to increase this %, you can have as many of these additional steps as you want until you reach 100% of your users.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/04/image.png" loading="lazy"
width="1540" height="271"
/&gt;
&lt;/p&gt;
&lt;p&gt;Now if you run this release now it will just run through each of the steps one after the other. Now of course you can add a pre or post approval to your pipeline but this just adds a manual dependency to your release. Whoever does the approving needs to check things are working before approving or worse just approves regardless.&lt;/p&gt;
&lt;p&gt;Azure DevOps has the concept of &lt;a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/release/deploy-using-approvals?view=azure-devops" target="_blank" rel="noopener noreferrer"&gt;gated releases&lt;/a&gt;
which allows you to add automated checks before or after a release happens. These automated checks can be any of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Azure Function&lt;/li&gt;
&lt;li&gt;A Rest API call&lt;/li&gt;
&lt;li&gt;Azure Monitor Alert&lt;/li&gt;
&lt;li&gt;Query Work Items&lt;/li&gt;
&lt;li&gt;Security and Compliance Assessment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are going to make use of the Azure Monitor Alert, to create an alert from your Application Insights data and only continue the rollout if no failures are detected.&lt;/p&gt;
&lt;p&gt;Open up your application insights resource in the Azure portal and look in alerts. Click add new alert rule.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/04/image-1.png" loading="lazy"
width="1616" height="1347"
/&gt;
&lt;/p&gt;
&lt;p&gt;Select your application insights resource in Resource, In Condition choose a condition to check, I chose Failed Requests, so every time a failure is registered in my API I can stop the deployment. The exact criteria you want to use is entirely up to you.&lt;/p&gt;
&lt;p&gt;Create an action group, I just set my alert to send an email to myself but there are other alert actions you may want to try. Give your alert a name and description and click save.&lt;/p&gt;
&lt;p&gt;Now all we need to do is make Azure DevOps make use of this alert. In your release pipeline select the pre-deployment conditions of your second step and open up the Gates section.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/04/image-2.png" loading="lazy"
width="1107" height="833"
/&gt;
&lt;/p&gt;
&lt;p&gt;Choose a suitable time to evaluate, I have been using something long like 12 or 24 hours so if there are problems there is time for it to be noticed. Choose Version 1 of the task (I was not able to get it to work with Version 0)&lt;/p&gt;
&lt;p&gt;Now select your Azure subscription and Resource Group and leave the rest of the settings as they are. Now your Deployment will stop and analyse application insights for any Failed requests and will halt if it finds any.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/04/image-3.png" loading="lazy"
width="1748" height="232"
/&gt;
&lt;/p&gt;
&lt;p&gt;I am still testing this out but it will take a few days to figure out if this what I want due to the large time scales involved. I feel this is going to be an improvement of manually approving release steps.&lt;/p&gt;</description></item><item><title>Documenting your API</title><link>https://blog-test.funkysi1701.com/posts/2019/documenting-your-api/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 27 Mar 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/documenting-your-api/</guid><category term="Swagger">Swagger</category><category term="API">API</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2019/03/image-3.png"/><description>&lt;p&gt;So you have created a super API that does something amazing. How do you document it so people will use it?&lt;/p&gt;
&lt;p&gt;One way of easily documenting your API is to install the Swashbuckle package.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Install-Package Swashbuckle.AspNetCore
Install-Package Swashbuckle.AspNetCore.Swagger
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then in you startup.cs add the following lines&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//In ConfigureServices&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services.AddSwaggerGen(c =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c.SwaggerDoc(&lt;span style="color:#e6db74"&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Info { Title = &lt;span style="color:#e6db74"&gt;&amp;#34;API&amp;#34;&lt;/span&gt;, Version = &lt;span style="color:#e6db74"&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;, Description = &lt;span style="color:#e6db74"&gt;&amp;#34;An API Description&amp;#34;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c.IncludeXmlComments(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Format(&lt;span style="color:#e6db74"&gt;@&amp;#34;{0}\API.xml&amp;#34;&lt;/span&gt;, System.AppDomain.CurrentDomain.BaseDirectory));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//In Configure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.UseSwagger();
&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;app.UseSwaggerUI(c =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c.SwaggerEndpoint(&lt;span style="color:#e6db74"&gt;&amp;#34;/swagger/v1/swagger.json&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;API V1&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c.RoutePrefix = &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;.Empty;
&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;Now when you browse to your API you will see the swagger documentation system.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/03/image-3.png" loading="lazy"
width="883" height="602"
/&gt;
&lt;/p&gt;
&lt;p&gt;The RoutePrefix setting controls the path in which swagger will display. I have my docs at the root, but you might want them under the /docs or similar path.&lt;/p&gt;
&lt;p&gt;The IncludeXmlComments setting from the ConfigureServices method allows you to load in any XML comments you have added to methods. For this to work you need to enable a setting to your build.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/03/image-4.png" loading="lazy"
width="997" height="822"
/&gt;
&lt;/p&gt;
&lt;p&gt;The XML documentation file must be ticked and contain a path. Everytime you do a build, a XML file will be generated which contains all the comment blocks you have added to your code.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/03/image-5.png" loading="lazy"
width="610" height="184"
/&gt;
&lt;/p&gt;
&lt;p&gt;Swagger will then use this XML documentation file to produce lovely looking documentation without you having to do anything extra.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/03/image-6.png" loading="lazy"
width="1796" height="705"
/&gt;
&lt;/p&gt;</description></item><item><title>Azure Key Vault</title><link>https://blog-test.funkysi1701.com/posts/2019/azure-key-vault/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 19 Mar 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/azure-key-vault/</guid><category term="Website">Website</category><category term="Security">Security</category><category term="Azure">Azure</category><description>&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-gb/azure/key-vault/" target="_blank" rel="noopener noreferrer"&gt;Azure Key Vault&lt;/a&gt;
is a secure way of storing your keys, certificates and secrets so your application can access everything it needs to but you don’t have them being stored insecurely anywhere such as in source control.&lt;/p&gt;
&lt;p&gt;I have been wanting to give Azure Key Vault a try for a while now as it can make use of Azure Active Directory to give your web app an identity so it can authenticate itself into the key vault to access secrets. Pretty clever but with a lot of moving parts a bit complex.&lt;/p&gt;
&lt;p&gt;For my example I am just going to connect to my Key Vault and get a secret and display it somewhere on a web page. This is of course not what you want to do as secrets are secret and shouldn’t be displayed just used to authenticate into whatever, however it is an easy way to prove I am connecting to the Key Vault and everything is working.&lt;/p&gt;
&lt;p&gt;Lets look at some code. I have a .net core application and to start with lets install three nuget packages.&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Microsoft.Azure.KeyVault
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Microsoft.Azure.Services.AppAuthentication
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Microsoft.Extensions.Configuration.AzureKeyVault
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I’ve not include version numbers as these will no doubt get updated over time but hopefully it will still work.&lt;/p&gt;
&lt;p&gt;Now in your Program.cs add the following code, replacing [KeyVaultName] with the name of your Key Vault.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Main(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;[] args)
&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; CreateWebHostBuilder(args).Build().Run();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; IWebHostBuilder CreateWebHostBuilder(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;[] args) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WebHost.CreateDefaultBuilder(args)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .ConfigureAppConfiguration((context, config) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; builtConfig = config.Build();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; azureServiceTokenProvider = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; AzureServiceTokenProvider();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; keyVaultClient = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; KeyVaultClient(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; KeyVaultClient.AuthenticationCallback(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; azureServiceTokenProvider.KeyVaultTokenCallback));
&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; config.AddAzureKeyVault(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;$&amp;#34;https://[KeyVaultName].vault.azure.net/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; keyVaultClient,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; DefaultKeyVaultSecretManager());
&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; .UseApplicationInsights()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .UseStartup&amp;lt;Startup&amp;gt;();
&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;Now all you need to do is look at your configuration to pull out secrets from your Azure Key Vault. If you have a secret called AppSecret then you can use the following code snippet to retrieve its value, assuming _configuration is an implementation of Microsoft.Extensions.Configuration.IConfiguration.&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;_configuration[&amp;#34;AppSecret&amp;#34;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if you do all of this and run from an Azure Web App or run locally it will fail to pull anything from the Key Vault. You need to give your web app an identity and configure your key vault to allow access from that identity.&lt;/p&gt;
&lt;p&gt;Once my code has been deployed to an Azure Web App I get the following error.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/image.png" loading="lazy"
width="1102" height="486"
/&gt;
&lt;/p&gt;
&lt;p&gt;Lets look at fixing that, first lets give my web app an Identity. Open up the Azure portal and find the identity section of your web app and turn the setting on.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/image-1.png" loading="lazy"
width="1218" height="728"
/&gt;
&lt;/p&gt;
&lt;p&gt;Now you need to grant that identity permission to your key vault. In the portal open up Access Policies in your key vault and click add Policy, select the identity of your web app in the principal box and select the following settings to grant access to your secret.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Image" src="https://blog-test.funkysi1701.com/images/2019/image-2.png" loading="lazy"
width="411" height="855"
/&gt;
&lt;/p&gt;
&lt;p&gt;Now you have a website that can pull secrets out of Key Vault but only that unique identity. Anyone who has access to your source code will not have access to your secrets, even if they push your code to a different Azure Web App.&lt;/p&gt;</description></item><item><title>Tech I want to learn more about</title><link>https://blog-test.funkysi1701.com/posts/2019/technology-i-want-to-learn-more-about/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 05 Mar 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/technology-i-want-to-learn-more-about/</guid><category term="C-Sharp">C-Sharp</category><category term="Azure">Azure</category><category term="Security">Security</category><description>&lt;p&gt;While at &lt;a href="https://www.funkysi1701.com/posts/2019/microsoft-ignite-the-tour-london" target="_blank" rel="noopener noreferrer"&gt;Microsoft Ignite&lt;/a&gt;
I heard about a lot of cool tech that I want to know more about. The best way to learn something is use it to solve a problem.&lt;/p&gt;
&lt;p&gt;So what can I build that is both useful and will let me play with some new tech?&lt;/p&gt;
&lt;p&gt;I have a Xamarin Forms app Pwned Pass that has over 500 downloads on Google Play and over 80 downloads on the Microsoft Store. This has given me a small user base that I can use to make use of whatever I build.&lt;/p&gt;
&lt;p&gt;My app makes use of the &lt;a href="https://haveibeenpwned.com/API/v3" target="_blank" rel="noopener noreferrer"&gt;HIBP API&lt;/a&gt;
created by Troy Hunt. I am going to build my own API, initially it will just make calls to the HIBP API. Building this will give me experience of building something with .net Core from design to deployment. I have made a start already on doing this, I have an empty .net core API project which deploys to an Azure web app using the build and release pipelines from Azure DevOps.&lt;/p&gt;
&lt;p&gt;You may be wondering why I am not making use of Azure Functions to build this API. Azure functions is certainly a great technology that is worth learning about. However I have done a little bit with them in the past and I don’t believe I would be able to learn all the things I want to if I used Azure Functions. My primary goal is learning and sharing that learning via this blog. It may well be I move to using Azure Functions later on.&lt;/p&gt;
&lt;p&gt;Another tech I am keen to learn more about is &lt;a href="https://learn.microsoft.com/en-gb/azure/key-vault/" target="_blank" rel="noopener noreferrer"&gt;Azure Key Vault&lt;/a&gt;
. This is a technology that allows the securing of keys, connection strings and certificates. I want my app to securely get keys and security information without any of it having to be committed to source code or shared insecurely.&lt;/p&gt;
&lt;p&gt;Monitoring my app is also a key learning from me. I use application insights already, but I would like to extend my understanding of this so telemetry can be fed back into the build and bad deployments stopped.&lt;/p&gt;
&lt;p&gt;Below is my complete list of learning and tech I want to touch on. It is a long list and I imagine it will get longer as I work through it. I want to regularly blog and share what I have been working on. I currently have a working build and release pipeline but nothing of note to build or release. I know Key Vault needs looking at early as the identity of the website in Azure is key to getting that tech working correctly.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build API with .net core&lt;/li&gt;
&lt;li&gt;Add build and release pipeline&lt;/li&gt;
&lt;li&gt;Make use of Azure KeyVault for secrets, connection strings etc&lt;/li&gt;
&lt;li&gt;Plugin My Xamarin app to make use of it&lt;/li&gt;
&lt;li&gt;Monitor my API with Application Insights&lt;/li&gt;
&lt;li&gt;Secure it with CSPs and log this into &lt;a href="https://report-uri.com/" target="_blank" rel="noopener noreferrer"&gt;Report URI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Consider building a web frontend to my API using a javascript library or framework. Maybe react but this can be decided later.&lt;/li&gt;
&lt;li&gt;Dockerize the API and add the creation of docker images to the build/release pipeline&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Microsoft Ignite | The Tour – London</title><link>https://blog-test.funkysi1701.com/posts/2019/microsoft-ignite-the-tour-london/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 26 Feb 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/microsoft-ignite-the-tour-london/</guid><category term="Conference">Conference</category><category term="Azure">Azure</category><category term="Microsoft">Microsoft</category><category term="DevOps">DevOps</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2019/02/D0UTj08XgAEo1YJ.jpg"/><description>&lt;p&gt;I have just spent the first day at the conference Microsoft Ignite | The Tour.
&lt;img class="img-fluid" alt="Alt Text" src="https://blog-test.funkysi1701.com/images/2019/02/D0UTj08XgAEo1YJ.jpg" loading="lazy"
width="1534" height="1018"
/&gt;
The conference was free I just needed to arrange travel and accommodation. Microsoft have really looked after me and all the other guests, breakfast and lunch has been provided, I got a free t-shirt, coffee (or tea) all day plus a beer or glass of wine to end the day. And that’s before you collect any free stuff the vendors are giving away.&lt;/p&gt;
&lt;p&gt;The first session was Designing resilient cloud applications with &lt;a href="https://twitter.com/CodeMillMatt" target="_blank" rel="noopener noreferrer"&gt;Matt Soucoup&lt;/a&gt;
and talked about some cloud technologies like Azure key vault and serving static files from blob storage. Unfortunately this had a few technical issues with the demos. I think it was just connectivity with the MongoDB backend but this slightly spoiled the session. As this was the only technical problem I noticed all day I can let it pass.&lt;/p&gt;
&lt;p&gt;Next was a session on Azure DevOps mainly build and release pipelines called Deploying your application faster and safer with &lt;a href="https://twitter.com/bbenz" target="_blank" rel="noopener noreferrer"&gt;Brian Benz&lt;/a&gt;
. A lot of this I knew but good to reinforce I am doing things correctly.&lt;/p&gt;
&lt;p&gt;Next was a session on Application Insights called Detecting application anomalies with Telemetry with Matt Soucoup.&lt;/p&gt;
&lt;p&gt;Probably the most useful session was on Docker and Kubernetes called Integrate containers and Kubernetes into your Azure DevOps build and release model with &lt;a href="https://twitter.com/crad77" target="_blank" rel="noopener noreferrer"&gt;Marco De Sanctis&lt;/a&gt;
. Going to spend some time looking through the examples from this session.&lt;/p&gt;
&lt;p&gt;A session on Serverless covered Azure Functions, Azure Logic apps and the other Azure Serverless offerings. Investing in Serverless: less servers, more code with &lt;a href="https://twitter.com/simona_cotin" target="_blank" rel="noopener noreferrer"&gt;Simona Cotin&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Lastly was a panel discussion on the changes facing IT Pros and SysAdmins. What is the future of the IT Pro in a DevOps &amp;amp; Cloudy world? with &lt;a href="https://twitter.com/jenstirrup" target="_blank" rel="noopener noreferrer"&gt;Jennifer Stirrup&lt;/a&gt;
, &lt;a href="https://twitter.com/bakionur" target="_blank" rel="noopener noreferrer"&gt;Baki Onur Okutucu&lt;/a&gt;
, &lt;a href="https://twitter.com/AmyKateNicho" target="_blank" rel="noopener noreferrer"&gt;Amy Boyd&lt;/a&gt;
and &lt;a href="https://twitter.com/TheOpsMgr" target="_blank" rel="noopener noreferrer"&gt;Stephen Thair&lt;/a&gt;
. Should they learn to code, how should they make sure they keep up.&lt;/p&gt;
&lt;p&gt;Tomorrow I have a loads more sessions, including ones about mental health, Azure pipelines, more Kubernetes stuff and dealing with failure.&lt;/p&gt;</description></item><item><title>Yaml Builds on Azure DevOps</title><link>https://blog-test.funkysi1701.com/posts/2019/yaml-builds-on-azure-devops/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 31 Jan 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/yaml-builds-on-azure-devops/</guid><category term="CI">CI</category><category term="Build">Build</category><category term="Azure">Azure</category><category term="DevOps">DevOps</category><category term="AzureDevOps">AzureDevOps</category><description>&lt;p&gt;I have been using Azure DevOps (Or VSTS or VSO etc) for a while now and one of the great features is doing automatic builds with every check-in. This is more commonly known as a CI (continuous integration) build.&lt;/p&gt;
&lt;p&gt;More recently I have started playing about with creating my build using YAML files instead of using the web user interface to create my build.&lt;/p&gt;
&lt;h2 id="why"&gt;Why?&lt;a class="anchor ms-1" href="#why" aria-label="Permalink: Why?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may wonder why go to the effort of learning the YAML syntax when you can just create the build in Azure DevOps and then forget about it.&lt;/p&gt;
&lt;p&gt;Mostly it is because the build changes over time and you shouldn’t just forget about it. If something changes over time then you might want to version control it, or look at a previous version.&lt;/p&gt;
&lt;p&gt;Lets say you create a pull request that replaces a .net 4.7 web service with a .net core web service. If you have a CI build this PR will fail because it won’t build. If you change the build first any other builds going on will fail. What you want in this case is the build to be associated with that branch or PR. Any builds before you merge this change in will continue to work and any after this change will also work.&lt;/p&gt;
&lt;h2 id="how"&gt;How?&lt;a class="anchor ms-1" href="#how" aria-label="Permalink: How?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;How do you get started with YAML builds? Well the first thing is to make sure that YAML builds are turned on, as I write this I believe they are still a feature you can turn on or off. Have a look in Preview features and make sure they are turned on.&lt;/p&gt;
&lt;p&gt;Next look at any of your existing builds and click the View YAML link. This will show you an example YAML file of your existing build. You could just save this as azure-pipelines.yml and checkin to the root of your project. You can also click the add new build pipeline option, this will give you some templates to start you off.&lt;/p&gt;
&lt;p&gt;The YAML file consists of a series of build steps usually called tasks, with a few settings before to configure things like parameters or build agents. Detailed docs about the syntax of the file can be found &lt;a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&amp;amp;tabs=schema" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;For my mobile app my YAML files consist of downloading nuget packages, building the solution, building specific projects with desired settings, running powershell or other scripts to set things up and finally publishing the results of the build as artifacts so that they can be used in any releases.&lt;/p&gt;
&lt;h2 id="secure-it"&gt;Secure It!&lt;a class="anchor ms-1" href="#secure-it" aria-label="Permalink: Secure It!"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Avoid committing passwords and secure keys into source control. I have found you can upload secure files via Azure DevOps and then add a download secure files step at the start of your build. This allows the secure file to be used during the build but the contents of the file can’t be viewed by anyone with access to the source code.&lt;/p&gt;
&lt;p&gt;I find it often takes a bit of thinking about how to achieve this, but it is usually possible to keep keys and secrets secure.&lt;/p&gt;</description></item><item><title>Pwned Pass Update</title><link>https://blog-test.funkysi1701.com/posts/2019/pwned-pass-update/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 23 Jan 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/pwned-pass-update/</guid><category term="Xamarin">Xamarin</category><category term="Android">Android</category><category term="PwnedPass">PwnedPass</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2019/01/image.png"/><description>&lt;p&gt;Its been a while since I first released Pwned Pass so lets have a look at where we are now.&lt;/p&gt;
&lt;p&gt;We are very close to 500 Downloads from Google Play and we have recently smashed past 100 active installs, peaking at 116 and even now we are still over 100. I have had 9 reviews (6 x 5*, 2 x 1 * and a 4 *) which averages out at 4 *
&lt;img class="img-fluid" alt="Alt Text" src="https://blog-test.funkysi1701.com/images/2019/01/image.png" loading="lazy"
width="906" height="832"
/&gt;
Over Christmas I released a UWP version that can be found in the Microsoft Store. This has currently had 9 downloads and even had a download to Windows Mobile (someone out there still likes the platform!)
&lt;img class="img-fluid" alt="Alt Text" src="https://blog-test.funkysi1701.com/images/2019/01/image-1.png" loading="lazy"
width="876" height="845"
/&gt;
I have a fairly smooth deployment process using Azure DevOps. After every check in of code a build runs which compiles the UWP and Android versions. The build also increments the version numbers that is required to deploy to either of the app stores.&lt;/p&gt;
&lt;p&gt;Every successful build of the master branch will kick off a release to the Beta track of Google Play. If I am happy I then release to 10% of the Production track, which can then be increased to 100% (or halted). The release to Microsoft Store happens after the Beta track of Google Play. Only reason for this order is that there isn’t a beta area for UWP apps so I want to quickly test change on android before rolling out for windows.&lt;/p&gt;
&lt;p&gt;All these steps require confirmation by me before proceeding and often don’t get further than the beta track.&lt;/p&gt;
&lt;p&gt;A further development is that I have open sourced the source code to &lt;a href=""&gt;github&lt;/a&gt;
do take a look if you are curious or want to contribute. With the purchase by Microsoft there are easy ways to connect github repositories to Azure DevOps. Once I create a Pull Request in github it creates a build in Azure DevOps and all the build and release steps can happen.&lt;/p&gt;
&lt;p&gt;I am still not 100% sure if I want to keep my bug and issue tracking in github or Azure DevOps as both have features for doing so.&lt;/p&gt;
&lt;p&gt;One future improvement I want to make is to automate the creation of screenshots. When I create a new feature and it gets checked in. I would like to automatically created screenshots of the key pages and submit them to the different app stores. Currently I am not sure if this is possible or how to go about it. I have some ideas to experiment with so we will see what I can do.&lt;/p&gt;</description></item><item><title>What I planned to achieve in 2019</title><link>https://blog-test.funkysi1701.com/posts/2019/lets-see-what-2019-can-do/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 01 Jan 2019 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2019/lets-see-what-2019-can-do/</guid><category term="Goals">Goals</category><category term=""/><description>&lt;p&gt;This is my annual lets make some goals for the new year blog post. So in no particular order.&lt;/p&gt;
&lt;h2 id="improve-house"&gt;Improve House&lt;a class="anchor ms-1" href="#improve-house" aria-label="Permalink: Improve House"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I can’t outdo last years goal of buying a house but I can continue to make efforts to improve it. I was going to put something about decorating or doing something to our bedrooms, however today I spotted a hole in the roof so this may well absorb most of my home improvement budget.&lt;/p&gt;
&lt;h2 id="connect-with-local-area"&gt;Connect with local area&lt;a class="anchor ms-1" href="#connect-with-local-area" aria-label="Permalink: Connect with local area"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since we moved in October we haven’t really connected with our local area yet. My only interaction with my neighbours was when my car blocked his drive!&lt;/p&gt;
&lt;p&gt;I am going to make efforts to change this in 2019. I don’t exactly know how yet, but I have some ideas. My son starts nursery and later school this year so could be one way to meet other parents and teachers. I want to connect with a local church, so far this hasn’t happened so need to make more effort with this. There are other local groups that put on child friendly events which would be good to attend.&lt;/p&gt;
&lt;h2 id="lightning-talk"&gt;Lightning Talk&lt;a class="anchor ms-1" href="#lightning-talk" aria-label="Permalink: Lightning Talk"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I failed last year to do this so it is back on my list. I know I must have stuff of value to share so going to try again on this.&lt;/p&gt;
&lt;p&gt;A lightning talk is a very short talk or presentation given at a conference or user group. I am not a natural public speaker so this is a step out of my comfort zone, however I am going to start small and see what happens.&lt;/p&gt;
&lt;p&gt;##Family Holiday
As always we Fosters are going to have a holiday in the summer and have some quality family time. I also want to take the boys to London for a weekend.&lt;/p&gt;
&lt;h2 id="blogging"&gt;Blogging&lt;a class="anchor ms-1" href="#blogging" aria-label="Permalink: Blogging"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This blog has taken a bit of a backseat in 2018 so I want to try and refocus it for 2019. My commitment is for 12 blog posts in 2019, that is one a month. It doesn’t sound like much but I know how easily life can get in the way.&lt;/p&gt;
&lt;p&gt;Having said that my log has had record views this year. 7159 views. However I believe this number to be incorrect and has been inflated by my app development and some of the automated processes taking place.&lt;/p&gt;
&lt;h2 id="routine"&gt;Routine&lt;a class="anchor ms-1" href="#routine" aria-label="Permalink: Routine"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last goal is to try a get more of a routine going. With two small boys, one of which is starting school in September a routine is going to be essential and will allow all of us all a chance to get more things done.&lt;/p&gt;</description></item><item><title>Looking back at 2018</title><link>https://blog-test.funkysi1701.com/posts/2018/looking-back-at-2018/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 27 Dec 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/looking-back-at-2018/</guid><category term="C-Sharp">C-Sharp</category><category term="Home">Home</category><category term="Family">Family</category><category term="Goals">Goals</category><description>&lt;p&gt;As 2018 starts to draw to a close let’s look at some of the highlights from the past year.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;New Home - I started 2018 with the goal of buying my own home and I managed it. At the end of October I actually moved in but it was months of looking at houses, speaking to estate agents, saving, packing and unpacking. There is more I want to do to my home in 2019 so this is only really the beginning.&lt;/li&gt;
&lt;li&gt;New Job - Another goal was to kick my career up a notch and this happened in June. It has been great working as part of a large team and I have learnt loads, there is much more I want to learn and contribute to so 2019 should be great on that front.&lt;/li&gt;
&lt;li&gt;New Car - Not a goal that I achieved as unfortunately in October I was involved in a car accident, no one was seriously hurt but this was a horrible experience to go through. My car was written off which gave me an excuse to buy a new car.&lt;/li&gt;
&lt;li&gt;See more of family was a goal, I am not sure if I really achieved this. However family have been around loads for us during our move and we do live closer so hopefully I can work on this some more.&lt;/li&gt;
&lt;li&gt;Celebrate 5 years of marriage. It hasn&amp;rsquo;t been an easy year for me and the wife due to moving house and all the stress that involved plus with two children she was diagnosed with Postnatal Depression which as a family we are still dealing with. All that said we had a fab weekend away and we so need to do something similar again soon.&lt;/li&gt;
&lt;li&gt;Family. 2018 has included many great times with my two boys. It&amp;rsquo;s been amazing seeing them grow, in September we had a thanksgiving service for them and in July we had our annual holiday.&lt;/li&gt;
&lt;li&gt;Lightning Talk. This is the only thing I mentioned as a goal that didn&amp;rsquo;t happen, it&amp;rsquo;s on my 2019 list so hopefully I can kick myself into action but with everything else I achieved something had to slip.   &lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Run SQL Server in a Linux container</title><link>https://blog-test.funkysi1701.com/posts/2018/running-sql-server-on-a-linux-container-using-docker-for-windows/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 05 Nov 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/running-sql-server-on-a-linux-container-using-docker-for-windows/</guid><category term="Windows">Windows</category><category term="Docker">Docker</category><category term="SQL">SQL</category><category term="Linux">Linux</category><description>&lt;p&gt;Recently I have been investigating what all the fuss is about Docker and it has been well worth my time as Docker is pretty awesome for automating stuff.&lt;/p&gt;
&lt;p&gt;My development environment has typically required installing SQL Server. SQL is a bit of a beast with lots of options and takes time to setup how you want.&lt;/p&gt;
&lt;p&gt;However since Microsoft have now created a version of SQL Server that runs on Linux you can run SQL Server in a Linux container with only a few commands.&lt;/p&gt;
&lt;p&gt;I am going to assume you already have Docker for windows installed on your development machine. If not head over to &lt;a href="https://docs.docker.com/docker-for-windows/install/#where-to-go-next" target="_blank" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;
and find out how.&lt;/p&gt;
&lt;p&gt;The Microsoft guide to setting up SQL Server in a Linux container can be found &lt;a href="https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-2017" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;First you need to download the image. In a powershell window run:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;docker pull mcr.microsoft.com/mssql/server:2017-latest
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This downloads the latest sql server image.&lt;/p&gt;
&lt;p&gt;To run this image run the following:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;docker run -e &amp;#34;ACCEPT_EULA=Y&amp;#34; -e &amp;#34;SA_PASSWORD=password&amp;#34;
-p 1433:1433 --name sql
-d mcr.microsoft.com/mssql/server:2017-latest
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run a SQL Server image you are required to accept the terms and conditions and set a default sa password. These are added as environment variables with the -e flag.&lt;/p&gt;
&lt;p&gt;You also need to set the ports that your container will run on (1433 is the default SQL port) and give your container a name, in this case &amp;ldquo;sql&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;If you have already installed SQL Server you will not be able to run the container on the same port as your local install. To solve this you can select a different port.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;docker run -e &amp;#34;ACCEPT_EULA=Y&amp;#34; -e &amp;#34;SA_PASSWORD=password&amp;#34;
-p 1434:1433 --name sql
-d mcr.microsoft.com/mssql/server:2017-latest
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;-p 1434:1433 maps the 1433 port on the container to port 1434 of your local environment.&lt;/p&gt;
&lt;p&gt;Once you have run this command you can connect SQL Server Management Studio (SSMS) to (local) or (local),1434 if you are using a different port using the credentials you provided and execute any SQL you like.&lt;/p&gt;
&lt;p&gt;If your development environment requires windows authentication this of course is not for you, if it doesn’t you are good to go.&lt;/p&gt;
&lt;p&gt;The development environment I have been using has various powershell scripts for setting things up. These assume windows auth. However I have adapted them to take custom credentials.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$credential = Get-Credential $server.ConnectionContext.LoginSecure=$false
$server.ConnectionContext.set_Login($credential.UserName)
$server.ConnectionContext.set_SecurePassword($credential.Password)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Get-Credential command creates a dialog where you can enter SQL credentials, this is then stored in a variable and used in the rest of the script.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I restore a backup file to my container?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;docker exec -it sql mkdir /var/opt/mssql/backup
docker cp database.bak sql:/var/opt/mssql/backup
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This creates a backup folder and copies a backup file from your local environment to the container. You can then use management studio to restore the backup file (or you could write a sql script to do it). One thing to note when restoring databases, make sure the files are restored to Linux locations not windows locations.&lt;/p&gt;
&lt;p&gt;The only issues I have encountered so far are the lack of support for SSIS packages and no windows auth. There are sql server windows images available which I haven’t tried yet which may work better with some of these options.&lt;/p&gt;</description></item><item><title>2018 The Story So far</title><link>https://blog-test.funkysi1701.com/posts/2018/2018-the-story-so-far/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 28 Jul 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/2018-the-story-so-far/</guid><category term="Career">Career</category><category term="Home">Home</category><category term="Family">Family</category><category term="Job">Job</category><category term="Goals">Goals</category><description>&lt;p&gt;Remember me? I used to write blog posts but somehow life got in the way. So much has happened this year, lets have a look at my &lt;a href="https://blog-test.funkysi1701.com/posts/2018/lets-see-2018-can"&gt;goals&lt;/a&gt;
for 2018 and see how far we have got with them.&lt;/p&gt;
&lt;h2 id="buy-a-house"&gt;Buy a house&lt;a class="anchor ms-1" href="#buy-a-house" aria-label="Permalink: Buy a house"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My first goal for 2018 was to buy a house. Well so much progress has been made with this goal.&lt;/p&gt;
&lt;p&gt;We looked at a few houses, and have made an offer, had it accepted and are waiting for the last few things to get arranged before we start arranging to move in.&lt;/p&gt;
&lt;p&gt;The location we decided upon was &lt;a href="https://www.google.co.uk/maps/place/Thorne,&amp;#43;Doncaster/" target="_blank" rel="noopener noreferrer"&gt;Thorne&lt;/a&gt;
. This is about an hour from York where most of our friends are and my wife has lived all her life, and also an hour from where my family live. I have tried my best to balance location and size of property and we think our new home is going to be a good balance but only time will tell.&lt;/p&gt;
&lt;p&gt;I have a bit of a mammoth time ahead of me getting everything we own packed up and moved to our new home so wish me luck, but we will get there it is just going to be hard work.&lt;/p&gt;
&lt;h2 id="new-job"&gt;New Job&lt;a class="anchor ms-1" href="#new-job" aria-label="Permalink: New Job"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In June 2018 I started a new job. This was slightly later than I had hoped but I believe it has been worth the wait.&lt;/p&gt;
&lt;p&gt;My new job has lots of perks. Finish early on a Friday (1pm), On site canteen, Cool air-conditioned office, Flexible working hours, Part of a big development team.&lt;/p&gt;
&lt;p&gt;The main benefit is that I am part of a big development team. I have a huge list of things to learn both in terms of technology and how large development teams function. The team is about to finish the first sprint that I have contributed to. My contributions have been very small. A bug fix here, a tweak of an API there. But the important thing is that I am making a contribution and learning along the way.&lt;/p&gt;
&lt;p&gt;I have also started asking questions about deployment and how this could be automated. Something that interests me, especially with the sysadmin and devops background. I have been tasked with learning &lt;a href="https://docs.docker.com/" target="_blank" rel="noopener noreferrer"&gt;docker&lt;/a&gt;
, so expect some blog posts on this topic in the near future.&lt;/p&gt;
&lt;h2 id="see-more-of-family"&gt;See more of family&lt;a class="anchor ms-1" href="#see-more-of-family" aria-label="Permalink: See more of family"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This one I am going to count as a miss. I have seen family a few times this year, but my efforts have been more on the first two items in this list. Hopefully this will change as things settle down.&lt;/p&gt;
&lt;h2 id="celebrate-5-years-of-marriage"&gt;Celebrate 5 years of Marriage&lt;a class="anchor ms-1" href="#celebrate-5-years-of-marriage" aria-label="Permalink: Celebrate 5 years of Marriage"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Me and the wife had a great weekend away to celebrate our wedding anniversary.&lt;/p&gt;
&lt;h2 id="celebrate-my-two-children"&gt;Celebrate my two children&lt;a class="anchor ms-1" href="#celebrate-my-two-children" aria-label="Permalink: Celebrate my two children"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not happened yet but it is booked and we just need to arrange a few more details.&lt;/p&gt;
&lt;h2 id="lightning-talk"&gt;Lightning Talk&lt;a class="anchor ms-1" href="#lightning-talk" aria-label="Permalink: Lightning Talk"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have made no effort to do a talk and this is going to be a goal for 2019 I think. Most of the reason is concentrating on the other areas above, but also because I am not a natural speaker and I don’t like stepping out of my comfort zone. But I will do it, I just need to wait for other things to calm down a bit first.&lt;/p&gt;
&lt;h2 id="family-holiday"&gt;Family Holiday&lt;a class="anchor ms-1" href="#family-holiday" aria-label="Permalink: Family Holiday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We had a great week away at the start of July. The weather was really great (and still is) and we had lots of time doing things as a family.&lt;/p&gt;</description></item><item><title>Casting and Converting between types</title><link>https://blog-test.funkysi1701.com/posts/2018/casting-and-converting-between-types/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 07 May 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/casting-and-converting-between-types/</guid><category term="C-Sharp">C-Sharp</category><category term="Casting">Casting</category><category term="Convert">Convert</category><description>&lt;p&gt;Recently I was asked how to convert a number to a string. Let&amp;rsquo;s look at a few ways of approaching this problem.&lt;/p&gt;
&lt;p&gt;Most objects in c# have a method called ToString() which displays the string representation of that object. This is because of inheritance, all objects inherit from System.Object which defines ToString().&lt;/p&gt;
&lt;p&gt;Int32 is a struct so it inherits from System.ValueType which also inherits from System.Object&lt;/p&gt;
&lt;p&gt;so in code&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; a = &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; b = a.ToString();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now let&amp;rsquo;s look at the reverse. However the reverse runs the risk of throwing an error, let&amp;rsquo;s look at why.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; b = &lt;span style="color:#e6db74"&gt;&amp;#34;9&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; c = &lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; d = &lt;span style="color:#e6db74"&gt;&amp;#34;two&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All are valid strings but only one can be converted to a number. Use the TryParse method to convert to a number.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;.TryParse(&lt;span style="color:#e6db74"&gt;&amp;#34;9&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;out&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; e);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;TryParse will not throw an exception if the conversion fails, if it succeeds variable e will contain the result. Note an earlier version of c# required you to define the out parameter before using it with TryParse.&lt;/p&gt;
&lt;p&gt;int.Parse exists to do the same thing however it will throw exceptions if a conversion is not possible. The same is true if you use Convert.ToInt32(&amp;ldquo;two&amp;rdquo;);&lt;/p&gt;
&lt;h2 id="casting"&gt;Casting&lt;a class="anchor ms-1" href="#casting" aria-label="Permalink: Casting"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Casting is a way to explicitly telling the compiler that a type is actually another type and you are aware data loss will occur.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;double&lt;/span&gt; x = &lt;span style="color:#ae81ff"&gt;4.5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; y = (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;)x;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However it is not possible to cast a string to a number format as a string can contain any character not just number characters.&lt;/p&gt;</description></item><item><title>Let’s Encrypt is awesome</title><link>https://blog-test.funkysi1701.com/posts/2018/lets-encrypt-is-awesome/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 30 Apr 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/lets-encrypt-is-awesome/</guid><category term="DevOps">DevOps</category><category term="SSL">SSL</category><category term="Security">Security</category><description>&lt;p&gt;Let’s Encrypt is a free way to get a SSL certificate onto your website and until recently I had never tried it. It is very easy and I think it is awesome.&lt;/p&gt;
&lt;p&gt;IIS is the web server software the Microsoft include with Windows 10 and Windows Server. I have it installed on my laptop and it displays the default IIS page.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Default welcome page for IIS on Windows" src="https://blog-test.funkysi1701.com/images/2018/iis.jpg" loading="lazy"
width="2170" height="1311"
/&gt;
&lt;/p&gt;
&lt;p&gt;It is not really a good idea to host websites on your laptop, use a dedicated web server, or host with a hosting company, however the techniques are the same and it gives me something to write about!&lt;/p&gt;
&lt;p&gt;In order to point a domain name at what IIS on my machine was serving up I did the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do a google search for “whats my IP”, this will return your public IP. Most residential ISPs use dynamic IPs so it may change over time, (which is another reason not to host a website on your laptop!)&lt;/li&gt;
&lt;li&gt;Add an A record on a domain with the IP address you have just got&lt;/li&gt;
&lt;li&gt;Your public IP most likely points at your router not your laptop so enable port forwarding of port 80 and port 443 to the internal IP of your laptop (something like 192.168.0.11 etc)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now comes the fun Let’s Encrypt stuff!&lt;/p&gt;
&lt;p&gt;First you need a Let’s Encrypt client, there are a lot of them out there mostly for linux flavours, however a bit of googling found a windows one. Go to &lt;a href="https://github.com/PKISharp/win-acme/releases" target="_blank" rel="noopener noreferrer"&gt;https://github.com/PKISharp/win-acme/releases&lt;/a&gt;
and download the zip file and unzip it.&lt;/p&gt;
&lt;p&gt;Run the executable from the zip file and follow the onscreen prompts.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="win-acme client prompt to create a new Let&amp;rsquo;s Encrypt certificate" src="https://blog-test.funkysi1701.com/images/2018/letsencrypt.jpg" loading="lazy"
width="1174" height="733"
/&gt;
&lt;/p&gt;
&lt;p&gt;Press N to create a new certificate.&lt;/p&gt;
&lt;p&gt;Then press 1 to bind to single website found in your IIS setup&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="win-acme client prompt to bind a certificate to an IIS website" src="https://blog-test.funkysi1701.com/images/2018/letsencrypt2.jpg" loading="lazy"
width="1147" height="1024"
/&gt;
&lt;/p&gt;
&lt;p&gt;And now magically Let’s Encrypt knows what you have setup in IIS.&lt;/p&gt;
&lt;p&gt;Now all you need to do is enter an email address incase a renewal fails and agree to the let’s encrypt terms and you are all setup.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="win-acme client confirming Let&amp;rsquo;s Encrypt certificate setup" src="https://blog-test.funkysi1701.com/images/2018/letsencrypt3.jpg" loading="lazy"
width="957" height="1147"
/&gt;
&lt;/p&gt;
&lt;p&gt;How awesome and easy is that for getting your websites working with a SSL certificate. If you have IIS configured on a server, give it a try and you can SSL all your things.&lt;/p&gt;</description></item><item><title>DNS for Developers</title><link>https://blog-test.funkysi1701.com/posts/2018/dns-for-developers/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 09 Apr 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/dns-for-developers/</guid><category term="DNS">DNS</category><category term="DevOps">DevOps</category><description>&lt;p&gt;DNS is the backbone of the internet and as such I believe every developer should know something about the basics and not just leave it for the sysadmin to sort.&lt;/p&gt;
&lt;h2 id="what-is-dns"&gt;What is DNS?&lt;a class="anchor ms-1" href="#what-is-dns" aria-label="Permalink: What is DNS?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DNS or Domain Name System is what translates Domain names to IP addresses and vice versa.&lt;/p&gt;
&lt;h2 id="wait-what-is-an-ip-address-and-what-are-domain-names"&gt;Wait what is an IP address and what are domain names?&lt;a class="anchor ms-1" href="#wait-what-is-an-ip-address-and-what-are-domain-names" aria-label="Permalink: Wait what is an IP address and what are domain names?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You do realise this is a developer blog? An IP address is a unique address on the internet and a domain name is a user friendly label for one or more of these.&lt;/p&gt;
&lt;p&gt;An example might be google.com which for me resolves to 216.58.204.14&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;a class="anchor ms-1" href="#how-it-works" aria-label="Permalink: How it works"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="DNS lookup flow diagram showing how a browser resolves a domain name" src="https://blog-test.funkysi1701.com/images/2018/dns-rev-1.gif" loading="lazy"
width="360" height="320"
/&gt;
When your browser makes a request to google.com it makes a request to your ISPs DNS Servers. This resolves google.com to 216.58.204.14&lt;/p&gt;
&lt;p&gt;In more detail your ISPs DNS server will forward the DNS query to another DNS server and will cache the results for a set amount of time. This is the TTL or Time To Live. Next time the ISP DNS Server will be able to reply directly without needing to forward requests.&lt;/p&gt;
&lt;p&gt;This forwarding and caching is what makes making a DNS change not instantaneous. The TTL needs to be reached so that no results are still being fetched from the cache of DNS servers across the globe.&lt;/p&gt;
&lt;h2 id="dns-records"&gt;DNS Records&lt;a class="anchor ms-1" href="#dns-records" aria-label="Permalink: DNS Records"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now we know roughly how DNS works let’s look at the most common type of records&lt;/p&gt;
&lt;h3 id="a"&gt;A&lt;a class="anchor ms-1" href="#a" aria-label="Permalink: A"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A (Host) records are the most simple records which translate domain names to IPs&lt;/p&gt;
&lt;p&gt;eg &lt;a href="https://www.google.com" target="_blank" rel="noopener noreferrer"&gt;www.google.com&lt;/a&gt;
to 216.58.204.14&lt;/p&gt;
&lt;h3 id="cname"&gt;CNAME&lt;a class="anchor ms-1" href="#cname" aria-label="Permalink: CNAME"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A CNAME (Canonical Name) record is different to an A record in that it maps a domain name to another domain name when no A record exists.&lt;/p&gt;
&lt;p&gt;eg &lt;a href="https://www.google.com" target="_blank" rel="noopener noreferrer"&gt;www.google.com&lt;/a&gt;
to somethingelse.google.com&lt;/p&gt;
&lt;p&gt;Typically Azure makes use of CNAMEs for many of its services especially adding a custom domain name&lt;/p&gt;
&lt;h3 id="mx"&gt;MX&lt;a class="anchor ms-1" href="#mx" aria-label="Permalink: MX"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MX stands for Mail Exchange and is used for configuring email&lt;/p&gt;
&lt;h3 id="name-server"&gt;Name Server&lt;a class="anchor ms-1" href="#name-server" aria-label="Permalink: Name Server"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every domain has a number of Name Servers which tells you what servers control the DNS settings for that domain. If you change your Name Servers then the new Name servers will be where you can change your DNS settings.&lt;/p&gt;
&lt;p&gt;If you want to use a service like &lt;a href="https://dnsimple.com/" target="_blank" rel="noopener noreferrer"&gt;DNSimple&lt;/a&gt;
instead of &lt;a href="https://www.123-reg.co.uk/" target="_blank" rel="noopener noreferrer"&gt;123reg&lt;/a&gt;
or where ever you registered your domain then all you need to do is change your Name servers.&lt;/p&gt;
&lt;h3 id="aaaa"&gt;AAAA&lt;a class="anchor ms-1" href="#aaaa" aria-label="Permalink: AAAA"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Like A record but for ipv6&lt;/p&gt;
&lt;h2 id="what-next"&gt;What next?&lt;a class="anchor ms-1" href="#what-next" aria-label="Permalink: What next?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Want to put some different DNS records into practise? Buy a domain name and publish some content to it. Check out my previous post about &lt;a href="https://www.funkysi1701.com/posts/2017/creating-dns-records-programmatically/" target="_blank" rel="noopener noreferrer"&gt;programmatically adding records&lt;/a&gt;
. Want an SSL certificate? Get a wildcard one and then you can apply it to any subdomain you add to your domain.&lt;/p&gt;
&lt;p&gt;If you have a new website you want to publish consider which of the following is better:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://www.example.com/newsite&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://newsite.example.com&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I much prefer the second option, it looks cleaner, there is no potential conflict with the parent site, no subfolder issues between production and development.&lt;/p&gt;</description></item><item><title>Code Reviews</title><link>https://blog-test.funkysi1701.com/posts/2018/codereviews/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 02 Apr 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/codereviews/</guid><category term="Git">Git</category><category term="VisualStudio">VisualStudio</category><description>&lt;p&gt;Reviewing code is a great habit to get into. Code reviews help share knowledge between your team members and help catch bugs before they get into production. But how do you get into the habit of reviewing and avoid the we don’t have time to do this mentality?&lt;/p&gt;
&lt;p&gt;Visual Studio Team Services (VSTS) has some great options that can help make code reviews second nature.&lt;/p&gt;
&lt;h2 id="pull-requests"&gt;Pull Requests&lt;a class="anchor ms-1" href="#pull-requests" aria-label="Permalink: Pull Requests"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A lot of source control systems have the concept of pull requests. This is where you request others to review your code usually in a branch and if they approve it, merge it into a main branch.&lt;/p&gt;
&lt;p&gt;To create a pull request in VSTS go to the Code section and select Pull Requests. Often VSTS will make a suggestion of what branch to make a pull request for, if you don’t see this just click the New Pull request button.&lt;/p&gt;
&lt;p&gt;Select a branch you want to merge from and a branch that should be merged into (usually you merge into master from a feature branch). Give your pull request a title and description and select who should review your code, this can either be an individual or a group of people. You can also review all the changes that will be reviewed so you can make any last minute changes before it is reviewed.&lt;/p&gt;
&lt;p&gt;Now if you are anything like me you want your code merged in as soon as you have created your pull request and there is nothing stopping you reviewing your own code and clicking approve and merge on your own pull request. However &lt;a href="https://docs.microsoft.com/en-us/vsts/git/branch-policies?view=vsts" target="_blank" rel="noopener noreferrer"&gt;branch policies&lt;/a&gt;
is a way around this problem.&lt;/p&gt;
&lt;h2 id="branch-policies"&gt;Branch Policies&lt;a class="anchor ms-1" href="#branch-policies" aria-label="Permalink: Branch Policies"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Branch Policy" src="https://blog-test.funkysi1701.com/images/2018/save-policy-changes.png" loading="lazy"
width="599" height="901"
/&gt;
&lt;/p&gt;
&lt;p&gt;Branch policies allow you to specify how your code gets merged in.&lt;/p&gt;
&lt;p&gt;Go to the list of branches in VSTS and select branch policy and you will see a whole host of options to customise the merge process. If you do this on the master branch you will not be able to commit any changes to master without it going through a pull request.&lt;/p&gt;
&lt;p&gt;The first option enables you to select how many reviewers are needed on your code. If no one else works on your project best not setting this, but for everyone else setting at least one person to review your code is a great practice.&lt;/p&gt;
&lt;p&gt;Next you can ensure that your pull request is linked to a work item, this helps keep ensure you are actually fixing issues and not just making change for the sake of it.&lt;/p&gt;
&lt;p&gt;Check for comment resolution is a good setting to enable. This ensures that if your reviewer has commented about you needing to change this line here, it ensures that you do.&lt;/p&gt;
&lt;p&gt;Enforce merge strategy allows you to choose between fast forward merge or squash merge.&lt;/p&gt;
&lt;p&gt;Build validation enables the code to be built using a build definition you have configured. This is a great way to check code builds or tests pass before it gets merged in.&lt;/p&gt;
&lt;p&gt;The last two options allow you to specify code reviewers and third party external services.&lt;/p&gt;</description></item><item><title>Android Development Options</title><link>https://blog-test.funkysi1701.com/posts/2018/android-development-options/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 26 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/android-development-options/</guid><category term="Cordova">Cordova</category><category term="Android">Android</category><category term="CrossPlatform">CrossPlatform</category><category term="Manifest">Manifest</category><category term="Xamarin">Xamarin</category><description>&lt;p&gt;A friend asked me how to get started in Android Development and I thought I might have a go at answering that question here.&lt;/p&gt;
&lt;p&gt;I am by no means an expert in Android development, I do have an app in the play store so I know something.&lt;/p&gt;
&lt;h2 id="manifest-file"&gt;Manifest File&lt;a class="anchor ms-1" href="#manifest-file" aria-label="Permalink: Manifest File"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is probably the easiest option and also doesn’t actually create an android app so I am not sure if it should be included in this list of not.&lt;/p&gt;
&lt;p&gt;If you have a website and you want to create an app for that you could just create a manifest file and add this to your website.&lt;/p&gt;
&lt;p&gt;Once your website has a manifest file, if you visit your website using a mobile phone or tablet you will get the option to add a shortcut to the home screen. You then have an app like experience in that you can click an icon to launch your website.&lt;/p&gt;
&lt;p&gt;A manifest file is a simple text file which specifies a few settings like the icon size, filename, what page loads when clicked and name of your “app”&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.google.com/web/fundamentals/web-app-manifest/" target="_blank" rel="noopener noreferrer"&gt;More information&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="visual-studio"&gt;Visual Studio&lt;a class="anchor ms-1" href="#visual-studio" aria-label="Permalink: Visual Studio"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the option I know most about as is what I have used.&lt;/p&gt;
&lt;p&gt;If you are familiar with Visual Studio you can use the Xamarin Forms software to create your app in C#. Xamarin Forms allows you to easily create cross platform apps that run on Android, IOS and windows phone. So far I have only experimented with Android but it should be relatively easy to extend my code to run on other platforms.&lt;/p&gt;
&lt;p&gt;Xamarin Forms allows you to write one a single codebase that can be compiled to run on the different platforms. Xamarin requires the use of XAML a XML like markup language for designing UI elements.&lt;/p&gt;
&lt;p&gt;More Information on &lt;a href="https://www.visualstudio.com/" target="_blank" rel="noopener noreferrer"&gt;Visual Studio&lt;/a&gt;
, &lt;a href="https://dotnet.microsoft.com/en-us/apps/xamarin" target="_blank" rel="noopener noreferrer"&gt;Xamarin Forms&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="android-studio"&gt;Android Studio&lt;a class="anchor ms-1" href="#android-studio" aria-label="Permalink: Android Studio"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I don’t know much about this option so do correct me if I don’t get the details correct.&lt;/p&gt;
&lt;p&gt;Android Studio can be downloaded from Google this allows you to create java code to run directly on an android device. From what I know this is fairly similar experience to Visual Studio but instead of writing your code in C# you use Android Studio and write it directly in java.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developer.android.com/studio/index.html" target="_blank" rel="noopener noreferrer"&gt;More information&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="cordova"&gt;Cordova&lt;a class="anchor ms-1" href="#cordova" aria-label="Permalink: Cordova"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cordova allows you to use HTML, CSS and javascript to create cross platform apps. I have no idea why I haven’t heard of this technology until today as it sounds very flexible especially if you know a little bit of javascript.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cordova.apache.org/docs/en/latest/guide/overview/" target="_blank" rel="noopener noreferrer"&gt;More information&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;To summarize there are lots of different options available to create an android app. What you choose depends on what you want to build, what language and experience you have and if your app needs to be cross platform.&lt;/p&gt;</description></item><item><title>Tips for Developing Yourself</title><link>https://blog-test.funkysi1701.com/posts/2018/tips-for-developing-yourself/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 19 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/tips-for-developing-yourself/</guid><category term="Blogging">Blogging</category><category term="Goals">Goals</category><description>&lt;p&gt;For a while I have been mentoring a friend and I thought I might share some top tips I have implemented in my career so far.&lt;/p&gt;
&lt;h2 id="hard-work"&gt;Hard Work&lt;a class="anchor ms-1" href="#hard-work" aria-label="Permalink: Hard Work"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At school I was told: “&lt;em&gt;Only in the dictionary does Success come before Work&lt;/em&gt;“. Yes it is a bit of a corny saying however it has stuck in my head and it’s true. If you want to get anywhere you need to work at it. For many years I just drifted along, but as soon as I knuckled down and worked hard my career started going somewhere.&lt;/p&gt;
&lt;h2 id="write-a-blog"&gt;Write a Blog&lt;a class="anchor ms-1" href="#write-a-blog" aria-label="Permalink: Write a Blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Writing is an important skill that you need to work at to improve. If you commit to writing one blog post a week this will help to improve this skill. Even after 150+ blog posts I still feel I need to improve. Not only that it will also help others learn something from you and shows a willingness to contribute to the community. If a Hiring Manager reads your blog he can see some of the stuff you know or care about and may help give you the edge over more experienced candidates.&lt;/p&gt;
&lt;h2 id="soft-skills"&gt;Soft Skills&lt;a class="anchor ms-1" href="#soft-skills" aria-label="Permalink: Soft Skills"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is one I need to work on but you should concentrate on the so called “&lt;em&gt;Soft Skills&lt;/em&gt;“. Soft Skills are the skills you have for dealing with others. Are you good at talking to people? Or good at getting requirements out of business owners? If so you have some soft skills, don’t underestimate the value that these bring to a team and keep developing them.&lt;/p&gt;
&lt;h2 id="build-a-side-project"&gt;Build a Side Project&lt;a class="anchor ms-1" href="#build-a-side-project" aria-label="Permalink: Build a Side Project"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start building a side project, it doesn’t matter what it is but start building something. I started building a Xamarin app but I have learnt loads of other connected things while doing this, ViewModels, APIs, Build and Deployment processes, Azure Functions. It also gives you ammunition for things to blog about. If you are short of ideas try solving a problem or rebuild something you use.&lt;/p&gt;
&lt;h2 id="use-your-spare-time"&gt;Use your spare time&lt;a class="anchor ms-1" href="#use-your-spare-time" aria-label="Permalink: Use your spare time"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During the day there are moments you can reclaim for learning stuff. There are lots of &lt;a href="https://www.funkysi1701.com/podcasts" target="_blank" rel="noopener noreferrer"&gt;podcast&lt;/a&gt;
which discuss useful development topics, listen to these while driving to work. Subscribe to &lt;a href="https://www.funkysi1701.com/posts/2018/pluralsight/" target="_blank" rel="noopener noreferrer"&gt;pluralsight&lt;/a&gt;
and listen to this while washing up. Don’t get too concerned with learning everything, however think how much more you are learning than not listening at all.&lt;/p&gt;
&lt;h2 id="im-not-ready"&gt;I’m not ready!&lt;a class="anchor ms-1" href="#im-not-ready" aria-label="Permalink: I’m not ready!"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We are never ready to take that next step, it is so easy to make excuses like I need to learn x, or know y. The only way to know if you are ready is to try and to keep trying. Iterate as you go so you keep improving yourself. If you wait before you start trying you will end up waiting forever. If you start trying now you will make some small progress and have a better idea of what you need to do to achieve your goals.&lt;/p&gt;</description></item><item><title>Heroes</title><link>https://blog-test.funkysi1701.com/posts/2018/heroes/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 16 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/heroes/</guid><category term="StephenHawking">StephenHawking</category><category term="Hero">Hero</category><description>&lt;p&gt;&lt;strong&gt;Who was your hero growing up?&lt;/strong&gt; Mine was Stephen Hawking.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Stephen Hawking" src="https://blog-test.funkysi1701.com/images/2018/Hawking-ZeroG_web-1.jpg" loading="lazy"
width="1024" height="415"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is a hero?&lt;/strong&gt; A lot is said in the media about “Heroes”. Often the sportsperson of the hour is described as a hero. I don’t like this definition and I think there is far more to being a hero than that. One definition I saw describes a hero as &lt;em&gt;A person who is admired for their courage, outstanding achievements, or noble qualities.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Hawking?&lt;/strong&gt; As a kid I thought I was pretty smart (Not really just above average), I liked Star Trek and science so Hawking was a pretty obvious choice. I remember reading all about Hawking and his life fascinated me. A brilliant man was struck down by motor neurone disease in his early twenties, however this did not stop him and he completed his doctorate and became the famous physicist we all know and love.&lt;/p&gt;
&lt;p&gt;My physics career was fairly short lived ending with an undergraduate course at University of York, however I really enjoyed learning the concepts that he described about space and time and was definitely a driving factor for me to learn as much as I did about Physics.&lt;/p&gt;
&lt;p&gt;How heroic is it to be given 2 years to live and then not only survive but to expand our understanding of the universe without being able to speak or move without the aid of technology?&lt;/p&gt;
&lt;p&gt;I can not imagine what it must be like to not be able to communicate without the use of a computer, but this has been Stephen Hawkings world for over 30 years. His computer system has undergone various upgrades over the years however his synthetic computer voice has continued as he identified with it and prefered it.&lt;/p&gt;
&lt;p&gt;Stephen Hawking had an immense intellect, I would probably describe him as one of the cleverest people on the planet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who are your heroes?&lt;/strong&gt; What kind of person is your hero, is it a scientist or engineer? The world contains some very clever people who will inspire and excite young people to strive towards something. I am hopeful that my sons can be inspired even if it’s only a small way by someone like Stephen Hawking.&lt;/p&gt;</description></item><item><title>New version of Pwned Pass</title><link>https://blog-test.funkysi1701.com/posts/2018/new-version-pwned-pass/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 05 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/new-version-pwned-pass/</guid><category term="Android">Android</category><category term="PwnedPass">PwnedPass</category><category term="App">App</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/google/pwned-pass-icon.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Pwned Pass" src="https://blog-test.funkysi1701.com/images/google/pwned-pass-icon.png" loading="lazy"
width="506" height="900"
/&gt;
A new version of Pwned Pass is available from Google Play.&lt;/p&gt;
&lt;p&gt;A couple of weeks ago &lt;a href="https://www.troyhunt.com/ive-just-launched-pwned-passwords-version-2/" target="_blank" rel="noopener noreferrer"&gt;Troy Hunt&lt;/a&gt;
released V2 of Pwned Pass onto his &lt;a href="https://haveibeenpwned.com/" target="_blank" rel="noopener noreferrer"&gt;haveibeenpwned&lt;/a&gt;
website. There are now over half a billion passwords that have appeared in data breaches for you to search.&lt;/p&gt;
&lt;p&gt;This time Troy has included information about how many times a password has appeared in his data. So “password” returns a value of 3,303,003 so is a really, really bad choice of password to use. However the password “windows 10” has only appeared twice so is much better, however I would still recommend avoiding using it.&lt;/p&gt;
&lt;p&gt;One of the great things about the internet is that on the day of release I was tweeting Troy so I could get my android app updated to take advantage of these new features. I even helped him identify an issue with the documentation on his site. He has also kindly add a link to my app onto his website.&lt;/p&gt;
&lt;p&gt;That conversation and link has lead to a massive increase in app downloads. Before I was going steady on about 14 installs, now I have 86 active installs. I am not sure if this will increase anymore but if you are reading this because you downloaded my app, then thank you.&lt;/p&gt;
&lt;p&gt;My app has four main features:&lt;/p&gt;
&lt;p&gt;Password Check – this allows you to search a password and see if it has appeared in a data breach and also the number of times that password has appeared.&lt;/p&gt;
&lt;p&gt;Email Check – this allows you to search your email address and see which data breach it has been involved in.&lt;/p&gt;
&lt;p&gt;List of Data Breaches – this lists the data breaches from haveibeenpwned.com you can also sort by Date Added, Number of accounts and name.&lt;/p&gt;
&lt;p&gt;Calendar of Breaches – this shows a github like chart of what days breaches are added&lt;/p&gt;
&lt;p&gt;If you like my app do let me know. I have received a few ratings on google play it would be great to get a few more. If you want me to add a feature or have ideas of how I could improve it let me know as well.&lt;/p&gt;
&lt;p&gt;To download take a look at &lt;a href="https://play.google.com/store/apps/details?id=pwnedpasswords.pwnedpasswords" target="_blank" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=pwnedpasswords.pwnedpasswords&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Refactoring if statements</title><link>https://blog-test.funkysi1701.com/posts/2018/refactoringifstatements/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 26 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/refactoringifstatements/</guid><category term="Design">Design</category><category term="Class">Class</category><category term="Interface">Interface</category><description>&lt;p&gt;The code base I am working on contains a huge if block. By huge I mean 77 if statements one after the other, each if checks to see what page id you are on and loads different content. This is not easy to maintain and I want to refactor it.&lt;/p&gt;
&lt;p&gt;One option would be to replace the if statements with a switch block. However this is just as unmanageable as the huge if block. Lets look at a better option.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Polymorphism&lt;/strong&gt; is where you create a base class and then create sub classes from it. In my case I created an interface IPage with a single method CreateContent.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;IPage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; CreatePageContent();
&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;and then create 77 classes for each page which implemented this single method.&lt;/p&gt;
&lt;p&gt;Now comes the fun bit how do I call the correct page class from my original code?&lt;/p&gt;
&lt;p&gt;I created a dictionary than maps page ids to the class names.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; Dictionary&amp;lt;PageIds, Type&amp;gt; PageIdToClass = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Dictionary&amp;lt;PageIds, Type&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PageIds.HomePage,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(HomePage)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PageIds.ContactPage,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(ContactPage)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//etc &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the one step I am not 100% happy with as I think it may be possible to remove or simplify this step.&lt;/p&gt;
&lt;p&gt;Now I have a way to map ids to classes I can write a class to do 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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyPage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IPage _repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; MyPage(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; pageId)
&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; PageIds p = (PageIds)pageId;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Type t = PageIdToClass[p];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ConstructorInfo constructor = t.GetConstructor(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Type[] { });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _repo = (IPage)constructor.Invoke(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; Create()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; _repo.CreatePageContent();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So in my constructor I take the pageId and pass it to my dictionary to get which subclass to load. I then get its Constructor and invoke it.&lt;/p&gt;
&lt;p&gt;Now I can remove the huge if block and replace it with a single line of code.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; page = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; MyPage(pageId);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On the face of it this change might look like a lot of work for not much gain as we started off with one file and now we have the original file, an interface, 77 subclasses and the MyPage class. However the original file is a lot more manageable and each sub class can be altered independently of each other.&lt;/p&gt;
&lt;p&gt;This is a big step towards making this code more maintainable, there is always more that can be done but that can wait for another day.&lt;/p&gt;</description></item><item><title>Chrome distrusts SSL Certificates</title><link>https://blog-test.funkysi1701.com/posts/2018/ssl-distrusts/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 19 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/ssl-distrusts/</guid><category term="Certificates">Certificates</category><category term="SSL">SSL</category><category term="Security">Security</category><category term="DevOps">DevOps</category><description>&lt;p&gt;One of the websites I have been working on has been displaying an error in the console. The error reads as follows.&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The SSL certificate used to load resources from https://example.com will be distrusted in M70. Once distrusted, users will be prevented from loading these resources. See https://g.co/chrome/symantecpkicerts for more information.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But what does this mean? Well let’s start by looking at the &lt;a href="https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
provided.&lt;/p&gt;
&lt;p&gt;In January 2017 it was revealed that Certificate Authorities run by Symantec which include Thawte, VeriSign, Equifax, GeoTrust, and RapidSSL had been issuing certificates that did not comply with baseline standards.&lt;/p&gt;
&lt;p&gt;Starting with Chrome 66, Google has decided to remove trust for these certificates. Chrome 66 is due for release around 17th April. My error mentions M70 so what does that refer to?&lt;/p&gt;
&lt;p&gt;Chrome 70 which is due to be released in October 2018 will removed the trust for another batch of Symantec certificates.&lt;/p&gt;
&lt;p&gt;If you are getting one of these errors because you are using a certificate that is going to be distrusted what will your site look like in Chrome 66 or Chrome 70?&lt;/p&gt;
&lt;p&gt;Well Chrome 66 is now in the dev channel so we can give it a try.
&lt;img class="img-fluid" alt="Chrome browser warning that a Symantec SSL certificate is distrusted" src="https://blog-test.funkysi1701.com/images/2018/tempsnip.png.jpg" loading="lazy"
width="1673" height="1119"
/&gt;
&lt;/p&gt;
&lt;p&gt;Not very nice for your users is it? Now is the time to order a new SSL certificate to avoid this happening to your site.&lt;/p&gt;
&lt;p&gt;I first saw this error a few months ago and have been reading up about it and waiting for Chrome 66 to reach the dev channel so I could test what it did to my site. However now that I have Chrome 66 installed I spotted the intranet for the company I work for is also affected. I do not directly work on the intranet so I notified the security team that they may want to look into this.&lt;/p&gt;
&lt;p&gt;Unfortunately the response I received has been that Google needs to fix this before Chrome 66 is released. I am not criticising my employer or the security team, however this isn’t something Google can just “ &lt;strong&gt;fix&lt;/strong&gt; “.&lt;/p&gt;
&lt;p&gt;The certificates issued were issued by a CA that had issues so in order to maintain the trustworthiness of all certificates Google had little choice but to distrust them. Google and security experts need to be making more of a fuss about this and I am joining in on making a fuss by writing this blog. &lt;a href="https://scotthelme.co.uk/are-you-ready-for-the-symantec-distrust/" target="_blank" rel="noopener noreferrer"&gt;Scott Helme&lt;/a&gt;
estimates that there are about 7000 websites which may be affected by the M66 and M70 distrusts.&lt;/p&gt;</description></item><item><title>Content Security Policies</title><link>https://blog-test.funkysi1701.com/posts/2018/content-security-policies/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 12 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/content-security-policies/</guid><category term="CSP">CSP</category><category term="ReportURI">ReportURI</category><category term="Security">Security</category><description>&lt;p&gt;A content Security Policy or CSP is a HTTP response header that defines what sources of content can be loaded on a web page. It is a way to combat Cross Site Scripting (XSS) attacks.&lt;/p&gt;
&lt;h2 id="what-is-a-xss-attack-then"&gt;What is a XSS attack then?&lt;a class="anchor ms-1" href="#what-is-a-xss-attack-then" aria-label="Permalink: What is a XSS attack then?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you load a webpage it also loads various other resources like images, some css style sheets, various javascript files that you want to run and probably many other things.&lt;/p&gt;
&lt;p&gt;How do you know that you can trust all of these things? If you created them and they live under you control then the answer is probably yes. However these days you will probably want to use resources from across the internet, like youtube videos, google analytics, disqus comments, jquery libraries from a cdn etc and you can’t be sure exactly what they are doing.&lt;/p&gt;
&lt;p&gt;Imagine you had a page which you could add any text into a form which would then be displayed. A malicious user could add evil javascript or get the browser to load evil code from anywhere on the internet.&lt;/p&gt;
&lt;h2 id="csp-to-the-rescue"&gt;CSP to the rescue!&lt;a class="anchor ms-1" href="#csp-to-the-rescue" aria-label="Permalink: CSP to the rescue!"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A CSP allows the browser to only load from sources that you specify. You could specify that resources from your own site will load but the evil script will not.&lt;/p&gt;
&lt;p&gt;Let’s look at some examples&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Content-Security-Policy: script-src &amp;#39;self&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This allows &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags to only load from the current webhost. script-src is not the only keyword you can use, let’s look at some of the others.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;script-src&lt;/strong&gt; – control what &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags will load&lt;br&gt;
&lt;strong&gt;style-src&lt;/strong&gt; – control what css will load&lt;br&gt;
&lt;strong&gt;img-src&lt;/strong&gt; – control what images will load&lt;br&gt;
&lt;strong&gt;frame-src&lt;/strong&gt; – control what frames will load&lt;br&gt;
&lt;strong&gt;font-src&lt;/strong&gt; – control what fonts will load&lt;br&gt;
&lt;strong&gt;object-src&lt;/strong&gt; – control what object tags will load&lt;br&gt;
&lt;strong&gt;connect-src&lt;/strong&gt; – control what resources a script can connect to&lt;br&gt;
&lt;strong&gt;media-src&lt;/strong&gt; – controls what media (audio/video) will load&lt;br&gt;
&lt;strong&gt;default-src&lt;/strong&gt; – if no specific rule exists then the default directive will run&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Content-Security-Policy: default-src https
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This allows any content to be loaded from any site as long as it comes from a secure (https) site&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Content-Security-Policy: default-src https://example.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This allows any content to be loaded from &lt;a href="https://example.com" target="_blank" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt;
only.&lt;/p&gt;
&lt;h2 id="how-do-i-use-this-on-my-site"&gt;How do I use this on my site?&lt;a class="anchor ms-1" href="#how-do-i-use-this-on-my-site" aria-label="Permalink: How do I use this on my site?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have added CSPs into my web.config which works great for my .Net Framework code.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; &amp;lt;system.webServer&amp;gt; &amp;lt;httpProtocol&amp;gt; &amp;lt;customHeaders&amp;gt; &amp;lt;add name=&amp;#34;Content-Security-Policy&amp;#34; value=&amp;#34;default-src https://example.com&amp;#34; /&amp;gt; &amp;lt;/customHeaders&amp;gt; &amp;lt;/httpProtocol&amp;gt; &amp;lt;/system.webServer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For .net core it is a bit more complex as you don’t tend to use web.config files, however check out Anthony Chu’s &lt;a href="https://anthonychu.ca/post/aspnet-core-csp/" target="_blank" rel="noopener noreferrer"&gt;post&lt;/a&gt;
, which has a solution to that problem.&lt;/p&gt;
&lt;h2 id="report-only"&gt;Report Only&lt;a class="anchor ms-1" href="#report-only" aria-label="Permalink: Report Only"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One last thing about CSPs to mention is the Report Only flag.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Content-Security-Policy-Report-Only
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This does the same as the above but doesn’t enforce anything, so you can fix any problems before you break anything.&lt;/p&gt;
&lt;p&gt;To view your issues just look in the developer tools in your favourite browser. Or you can configure all your reports to be collated in one place with a report-uri directive.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Content-Security-Policy: default-src https://example.com; report-uri https://example.report-uri.com/r/d/csp/reportOnly;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Scott Helme and Troy Hunt have a site called &lt;a href="https://report-uri.com/" target="_blank" rel="noopener noreferrer"&gt;report-uri&lt;/a&gt;
which offer a service for collating and viewing all your CSP violations so check it out if you want to know more about CSPs.&lt;/p&gt;</description></item><item><title>Pluralsight</title><link>https://blog-test.funkysi1701.com/posts/2018/pluralsight/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 05 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/pluralsight/</guid><category term="Learning">Learning</category><category term="Training">Training</category><category term="Pluralsight">Pluralsight</category><category term="C-Sharp">C-Sharp</category><description>&lt;p&gt;Earlier this year I signed up for pluralsight. If you want to sign up to pluralsight as well use this link &lt;a href="https://referral.pluralsight.com/mQd8BJ4" target="_blank" rel="noopener noreferrer"&gt;https://referral.pluralsight.com/mQd8BJ4&lt;/a&gt;
to get money off.&lt;/p&gt;
&lt;p&gt;Pluralsight is a website that sells training videos on a wide variety of technical topics. You sign up for a monthly or annual subscription and you can watch over 6000 courses whenever and where ever you like.&lt;/p&gt;
&lt;p&gt;I am not a big fan of videos as if I am sat in front of a screen I would rather be building something, however I do spend a lot of time listening to podcasts. So I have decided to convert this time to listening to pluralsight videos.&lt;/p&gt;
&lt;p&gt;If we assume that by not seeing the visual portion of the videos you lose out on 75% of the learning (This is just a guesstimate I am not sure what the exact figure is or how you would calculate it). However this is still 25% more learning than if I hadn’t signed up at all.&lt;/p&gt;
&lt;p&gt;Since I signed up I have listened to over 27 hours of technical videos. These have covered topics like C#, Security, Xamarin, MVVM, Interfaces, Getting Involved and Clean architecture. The number one thing I have learnt is that there is a lot that I still don’t understand.&lt;/p&gt;
&lt;p&gt;That said I would like to think that since starting to listen to pluralsight concepts have gone from being unknown unknowns (I don’t know about them and I don’t understand them) to known unknowns (I know about them but don’t yet fully understand them)&lt;/p&gt;
&lt;p&gt;To keep track of your learning pluralsight has some tests which you can complete. I am particularly proud of my score on the Azure test which ranks me as an expert.&lt;/p&gt;
&lt;p&gt;Why not check out what you can learn from pluralsight?&lt;/p&gt;</description></item><item><title>Flexible architecture and interfaces</title><link>https://blog-test.funkysi1701.com/posts/2018/flexible-architecture/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 29 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/flexible-architecture/</guid><category term="Architecture">Architecture</category><category term="Azure">Azure</category><description>&lt;p&gt;I have blogged a few times about &lt;a href="https://www.funkysi1701.com/posts/2017/interfaces/" target="_blank" rel="noopener noreferrer"&gt;interfaces&lt;/a&gt;
, and how useful they are for producing good quality maintainable code. Let’s look at a problem and the solution I came up with which I am quite proud of.&lt;/p&gt;
&lt;p&gt;As previously mentioned I am in the process of moving &lt;a href="https://www.funkysi1701.com/posts/2018/moving-blobs-cloud-suppliers/" target="_blank" rel="noopener noreferrer"&gt;images&lt;/a&gt;
from AWS to Azure blob storage. Now that the actual files themselves have been moved I need to change the code that references them.&lt;/p&gt;
&lt;p&gt;Now I could find all the code that uses the AWS API and replace it with the Azure API but I am not very good at predicting the future, we may stay on Azure for a while, we may move to AWS or Google Cloud, or we may want to go back to files sitting on a server.&lt;/p&gt;
&lt;p&gt;Lets try and code a solution that is as flexible as possible. As you have probably guessed I am going to create an interface.&lt;/p&gt;
&lt;p&gt;At first I thought about creating an interface called &lt;strong&gt;ICloudStorage&lt;/strong&gt; , however this isn’t flexible enough as what happens if we go back to sticking files on a server so instead I created &lt;strong&gt;IStorage&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I created three classes that implemented IStorage, &lt;strong&gt;AWSStorage&lt;/strong&gt; , &lt;strong&gt;AzureStorage&lt;/strong&gt; and mostly for testing at the moment &lt;strong&gt;FileStorage&lt;/strong&gt;. I then created a class Storage that would call these three classes. Initially I created it like 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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Storage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; IStorage _repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Storage(IStorage repo)
&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; _repo = repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However this would require I call it like Storage(new AzureStorage()) and I would need to know everywhere in my code which implementation I want to use. This isn’t too bad as when we change from AWS to Azure we would need to do a find and replace throughout the code and replace all AWSStorage and make them AzureStorage.&lt;/p&gt;
&lt;p&gt;However we can do better than that.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Storage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; IStorage _repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Storage()
&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; Type obj = Type.GetType(ConfigurationManager.AppSettings[&lt;span style="color:#e6db74"&gt;&amp;#34;DefaultStorageRepository&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ConstructorInfo constructor = obj.GetConstructor(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Type[] { });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _repo = (IStorage)constructor.Invoke(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code will read from the web.config which implementation to use and that will decide which class to call. This means that to change from AWS to Azure we do not need to redeploy any code, all we need to do is change the web.config.&lt;/p&gt;
&lt;p&gt;Let’s look at the three lines and see if we can understand what is happening.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type.GetType()&lt;/strong&gt; looks straight forward and gets the type from the web.config&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;obj.GetConstructor()&lt;/strong&gt; This gets the constructor for the type we have just found.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;constructor.Invoke&lt;/strong&gt; This then invokes the constructor and it then gets cast to the interface so can be used by the _repo variable.&lt;/p&gt;
&lt;p&gt;This is all fairly simple and makes sense, however it has produced some very flexible code and allows the code to be extended without recompiling.&lt;/p&gt;
&lt;p&gt;Let’s look at a hypothetical example. We want to add support for Google Cloud Storage. All we need to do is create a class library which implements the IStorage interface, place the compiled binary in the website and update the web.config to reference it. I haven’t tried this hypothetical example so it might be more complex than I think but in theory it should work.&lt;/p&gt;
&lt;p&gt;I am pretty excited at how flexible this code can be, hopefully I will use code like this more often now I understand it.&lt;/p&gt;</description></item><item><title>Moving files into blob storage</title><link>https://blog-test.funkysi1701.com/posts/2018/moving-blobs-cloud-suppliers/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 22 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/moving-blobs-cloud-suppliers/</guid><category term="DevOps">DevOps</category><category term="Azure">Azure</category><description>&lt;p&gt;We are in the process of moving our companies websites onto the Azure platform. One of the challenges was to move image files out of the website project into blob storage. This week I have moved 150,000 of them.&lt;/p&gt;
&lt;p&gt;One thing I keep banging on about is that your source code should not contain data. If it does every time you do a deployment you need to consider where these images are located and ensure you don’t overwrite or loose any. It also goes without saying that deployments of a few Mb are a lot quicker than deployments of 100s of Mb.&lt;/p&gt;
&lt;p&gt;Azure blob storage also gives you advantages like distributing storage across multiple datacenters which would be impossible with traditional files on a server.&lt;/p&gt;
&lt;p&gt;So now that we have established that this is a good idea lets look at how we could move large amounts of data. In my case all the filenames are stored in a SQL database so the plan of action was to simply loop through the files in the database, download from current storage (either locally or other cloud storage), upload to Azure and tidy up afterwards. Due to the number of images I am going to update the database and mark when a file has been processed so I can do the move over several days.&lt;/p&gt;
&lt;p&gt;This is my code&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; source = &lt;span style="color:#e6db74"&gt;&amp;#34;https://example.com/images/&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; tmp = Server.MapPath(&lt;span style="color:#e6db74"&gt;&amp;#34;~/tmp/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (!Directory.Exists(tmp))
&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; Directory.CreateDirectory(tmp);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; fixturePhotos = db.Images.Where(x =&amp;gt; x.Moved == &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; || x.Moved == &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;).Take(id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; photo &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; fixturePhotos)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; path = getFilePath(photo.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (!Directory.Exists(Server.MapPath(&lt;span style="color:#e6db74"&gt;&amp;#34;~/tmp/&amp;#34;&lt;/span&gt; + path)))
&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; Directory.CreateDirectory(Server.MapPath(&lt;span style="color:#e6db74"&gt;&amp;#34;~/tmp/&amp;#34;&lt;/span&gt; + path));
&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; WebClient WebClient = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; WebClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WebClient.DownloadFile(source + photo.FileName, tmp + photo.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FileUploader f = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; FileUploader(tmp + photo.FileName, photo.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; System.IO.File.Delete(tmp + photo.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; photo.Moved = &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; photo.Moved = &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db.SaveChanges();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (Directory.Exists(tmp))
&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; Directory.Delete(tmp, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First of all I create a tmp folder in the root of my website if it doesn’t exist to store my images temporarily.&lt;/p&gt;
&lt;p&gt;I then use an entity framework model to query the database that haven’t been moved, and I use the take() method to limit how many results I process. (I have been passing in 1000 at a time)&lt;/p&gt;
&lt;p&gt;I then use a foreach loop over all these files to perform the following actions.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create additional subfolders if the filename variable stored in the database isn’t actually a filename but a filepath, note you will have to split filename and filepath which I haven’t included code for here.&lt;/li&gt;
&lt;li&gt;Download file from the original url and save into the temporary folder&lt;/li&gt;
&lt;li&gt;Upload to Azure&lt;/li&gt;
&lt;li&gt;Delete temporary file&lt;/li&gt;
&lt;li&gt;Update database giving a success or fail&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the foreach is finished I commit the database changes and delete the temporary folder. I am sure there must be other ways to do this transfer but this was quick and easy to setup and now I have a copy of all the files in Azure storage so I can test out other issues with my website.&lt;/p&gt;
&lt;p&gt;One last tip about how to schedule this code. I called the above code from a MVC controller and then wrote a Azure Function to call this code on a schedule.&lt;/p&gt;</description></item><item><title>Website UI Testing</title><link>https://blog-test.funkysi1701.com/posts/2018/website-ui-testing/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 15 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/website-ui-testing/</guid><category term="Testing">Testing</category><category term="Website">Website</category><category term="UI">UI</category><description>&lt;p&gt;Last week I looked at testing the &lt;a href="https://dev.to/funkysi1701/mobile-app-ui-testing-jgg-temp-slug-9433902" target="_blank" rel="noopener noreferrer"&gt;UI of mobile apps&lt;/a&gt;
, this week lets look at how we could do a similar thing for websites.&lt;/p&gt;
&lt;p&gt;Testing the user interface is not an excuse for a lack of &lt;a href="https://dev.to/funkysi1701/writing-your-first-test-53gi-temp-slug-2645725" target="_blank" rel="noopener noreferrer"&gt;unit tests&lt;/a&gt;
. Testing the user interface takes longer so for keep creating your small unit tests that can be run after ever build. That said lets look at how you create a UI test.&lt;/p&gt;
&lt;p&gt;Create a Unit Test project as normal. Now install the following nuget packages&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Selenium.WebDriver.ChromeDriverSelenium.WebDriverSelenium.WebDriver.PhantomJS.Xplatform
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I am going to be using Selenium to achieve my website testing and I am going to concentrate on the Chrome browser. However packages exist for other browsers so have a look at the following and I expect there are others as well.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Selenium.WebDriver.IEDriverSelenium.Firefox.WebDriver
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://seleniumhq.org/" target="_blank" rel="noopener noreferrer"&gt;Selenium&lt;/a&gt;
started life as a plugin for Firefox to help create automated tests, however the latest version of Firefox is not compatible with the plugin as I write this. I have not had to install any plugins or extensions to my browsers to achieve my testing.&lt;/p&gt;
&lt;p&gt;Enough talk lets write a test. First we create two instance variables to store the baseURL and the driver for the browser you are using.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; baseURL = &lt;span style="color:#e6db74"&gt;&amp;#34;https://www.example.com/&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; RemoteWebDriver driver;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next we need to set things up for the test to run. This creates an instance of the chrome driver, maximizes the window and sets it to wait 30 seconds before timing out.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;[TestInitialize()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; MyTestInitialize()
&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; driver = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ChromeDriver();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver.Manage().Window.Maximize();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now comes the actual test. We navigate to a URL and then compare the title of the page loaded with a know value with a Assert statement like you would find in a unit test.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; CheckBrowserTitle()
&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; driver.Navigate().GoToUrl(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.baseURL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Assert.AreEqual(&lt;span style="color:#e6db74"&gt;&amp;#34;Home Page&amp;#34;&lt;/span&gt;, driver.Title);
&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;Finally we need to tidy up after ourselves.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;[TestCleanup()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; MyTestCleanup()
&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; driver.Quit();
&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;If you are used to writing tests you will know that the are usually constructed in three sections Arrange, Act and Assert. The Arrange is done in the initialize method, which makes the actual test much simpler, the first line does the Act and the last line does the Assert.&lt;/p&gt;
&lt;p&gt;Now we have written a simple test lets look at something more complex.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;driver.FindElementByLinkTest(&lt;span style="color:#e6db74"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This finds any Link on the page which is click. Be careful as the string need to be exactly what appears on screen it may well be easier to specify by id or class or something that doesn’t change as often. By adding .click() on the end of this command Selenium will click on the link and you can navigate to a new page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What about submitting form data?&lt;/strong&gt; Well you can find the element you want to fill in and add .SendKeys(&amp;ldquo;example text&amp;rdquo;) or .Submit() and this will fill in and submit form data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What about a screenshot?&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Screenshot ss = driver.GetScreenshot();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ss.SaveAsFile(&lt;span style="color:#e6db74"&gt;&amp;#34;test.jpg&amp;#34;&lt;/span&gt;,System.Drawing.Imaging.ImageFormat.Jpeg);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have only just started playing around with web UI tests but you can see there is a fair bit you can do.&lt;/p&gt;</description></item><item><title>Mobile App UI Testing</title><link>https://blog-test.funkysi1701.com/posts/2018/mobile-app-ui-testing/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 08 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/mobile-app-ui-testing/</guid><category term="Android">Android</category><category term="Azure">Azure</category><category term="App">App</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2018/01/01-newproject-vs.png"/><description>&lt;p&gt;Since I started creating an android app I have been writing simple UI tests.&lt;/p&gt;
&lt;p&gt;I have been taking advantage of the Visual Studio App Center which allows you to test against hundreds of different devices in the &lt;strong&gt;Test Cloud&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Xamarin UI tests" src="https://blog-test.funkysi1701.com/images/2018/01/01-newproject-vs.png" loading="lazy"
width="1371" height="834"
/&gt;
In order to write a UI test create a UI Test App, this makes use of the nuget package Xamarin UI Test. By default you will now have a test called AppLaunches which will take a screenshot of you app after it starts.&lt;/p&gt;
&lt;p&gt;You can now run this test against any device from Visual Studio assuming you have it physically plugged into your machine. However, how do you run against the Test Cloud?&lt;/p&gt;
&lt;p&gt;To run against the Test Cloud you need to first install node.js. Now you can install the appcenter cli with the following command.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;**npm** install -g appcenter-cli
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run the tests in the Test Cloud run the following command&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;**appcenter** test run uitest --app &amp;#34;&amp;lt;username&amp;gt;/&amp;lt;appname&amp;gt;&amp;#34; --devices &amp;#34;&amp;lt;username&amp;gt;/&amp;lt;deviceset&amp;gt;&amp;#34; --app-path _pathToFile.apk_ --test-series &amp;#34;master&amp;#34; --locale &amp;#34;en_US&amp;#34; --build-dir _pathToUITestBuildDir_
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;where &lt;username&gt; is your appcenter username, is the name of your app in appcenter and is the group of apps you have created in app center to test against.&lt;/p&gt;
&lt;p&gt;Look at device sets in the test section of the appcenter and click the new device set button. You can then search for any device you like and add it to a set, as I write this there are 244 devices you can test against.&lt;/p&gt;
&lt;p&gt;It is currently not possible within app center to run tests against a new build, however if you build your app in VSTS as well you can create build or release step that runs it. As the Visual Studio app center is still under development I wouldn’t be surprised if it is added at some point.&lt;/p&gt;
&lt;p&gt;In VSTS look for Mobile Center Test in the definitions and you can specify the same variables as specified in the command line above.&lt;/p&gt;
&lt;p&gt;Now how do you actually write a useful UI test? I mentioned above you get a default test which contains the following code, this takes a screenshot of your app. However you don’t have to include this when using the Test Cloud as screenshots are included for free.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;app.Screenshot(&amp;#34;First screen.&amp;#34;);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Lets look at what else is included in app&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;app.Repl();
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This starts an interactive REPL (Read-Eval-Print-Loop) which lets you explore what is on screen in your app and pauses execution. I don’t include this in my tests, however I do make use of it to explore what is on screen and what tests I might make use of.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;app.Tap(c =&amp;gt; c.Marked(&amp;#34;Button&amp;#34;));
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This taps an element on screen called Button. There is also a method called TapCoordinates which would allow you to click anywhere you like.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;app.WaitForElement(c =&amp;gt; c.Marked(&amp;#34;View&amp;#34;));
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After clicking a button you are probably going to want to wait for the app to load extra data or a new screen. The WaitForElement waits for an element to appear on screen. There are also methods that wait a period of time or wait until an element no longer exists.&lt;/p&gt;
&lt;p&gt;These are the main methods I have used so far, however there is an extensive list including methods for scrolling, swiping, pinching and adjusting the volume buttons. So you should be able to test all manner of app functionality and if you make use of the Test Clouds will know which devices are causing problems.&lt;/p&gt;</description></item><item><title>Lets see what 2018 can do!</title><link>https://blog-test.funkysi1701.com/posts/2018/lets-see-2018-can/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/lets-see-2018-can/</guid><category term="Career">Career</category><category term="Family">Family</category><category term="Marriage">Marriage</category><category term="Goals">Goals</category><description>&lt;p&gt;It is 2018 so it must be time to think about what my plans and goals are for the new year.&lt;/p&gt;
&lt;h2 id="buy-a-house"&gt;Buy a house&lt;a class="anchor ms-1" href="#buy-a-house" aria-label="Permalink: Buy a house"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="House" src="https://blog-test.funkysi1701.com/images/2018/LEGO-Classic-10703-Creative-Building-Box-Yellow-House.jpg" loading="lazy"
width="720" height="720"
/&gt;
&lt;/p&gt;
&lt;p&gt;This a huge goal for me. For many years I was content with renting and thought owning my own home wasn’t for me, but then I went and started a family and my career started going in the right direction and my thoughts about this have changed.&lt;/p&gt;
&lt;p&gt;It is going to take a lot of work to make this goal happen in 2018. First I need to save enough money for the deposit, which is far from easy with a wife and two children. Second I need to get our current place sorted ready to physically move which again won’t be easy. Third I need to make a decision which will affect where I live for the next 25 years. At the moment I am torn between the size of property and its physical location, I need to balance both of these and meet the requirements from the rest of the family.&lt;/p&gt;
&lt;p&gt;I do think this is an achievable goal so wish me luck.&lt;/p&gt;
&lt;h2 id="progress-in-my-career"&gt;Progress in my career&lt;a class="anchor ms-1" href="#progress-in-my-career" aria-label="Permalink: Progress in my career"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I need to be careful how I phrase this in case past, current or future employers are reading. I have been working hard at my current role for over a year and I am starting to wonder what is next for me. I am not entirely sure what form this is going to take yet, I have a few ideas on the go and hopefully I can reveal more soon.&lt;/p&gt;
&lt;p&gt;Another one that is very achievable, as long as I have it in the back of my mind as the year goes on progress should be made.&lt;/p&gt;
&lt;h2 id="see-more-of-family"&gt;See more of family&lt;a class="anchor ms-1" href="#see-more-of-family" aria-label="Permalink: See more of family"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I recently missed a family celebration due to the expansion of my own family and it reminded me that there are aunts, uncles and cousins that I haven’t seen in years and it would be nice to reconnect. Also as my own boys get older and are learning to interact it would be great if they could get to know my own family better.&lt;/p&gt;
&lt;p&gt;I don’t have a clear idea how to achieve this one as it takes two but I am going to make more of an effort.&lt;/p&gt;
&lt;h2 id="celebrate-5-years-of-marriage"&gt;Celebrate 5 years of marriage&lt;a class="anchor ms-1" href="#celebrate-5-years-of-marriage" aria-label="Permalink: Celebrate 5 years of marriage"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Wow how has it been five years since we got married? At some point in 2018 I will take time out from the usual and spend it with the wife away from the boys. I won’t give away more details as I want that to be a surprise.&lt;/p&gt;
&lt;h2 id="celebrate-the-birth-of-my-two-sons"&gt;Celebrate the birth of my two sons&lt;a class="anchor ms-1" href="#celebrate-the-birth-of-my-two-sons" aria-label="Permalink: Celebrate the birth of my two sons"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Celebrate James and Edward" src="https://blog-test.funkysi1701.com/images/2018/james5.jpg" loading="lazy"
width="1080" height="810"
/&gt;
&lt;/p&gt;
&lt;p&gt;I don’t want to get my boys christened as I would like them to make up their own minds when they are old enough, however I do want to celebrate all that they are with a thanksgiving service. Not sure when we are going to sort this, however it is my hope that it will be soon.&lt;/p&gt;
&lt;h2 id="family-holiday"&gt;Family holiday&lt;a class="anchor ms-1" href="#family-holiday" aria-label="Permalink: Family holiday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not much of a goal but in the summer I will take time out to spend a week away with the family. In previous years we have done scotland, wales and northumberland. This year I am thinking of somewhere not too far away as Edward is still small, but maybe near where I grew up.&lt;/p&gt;
&lt;h2 id="lightning-talk"&gt;Lightning Talk&lt;a class="anchor ms-1" href="#lightning-talk" aria-label="Permalink: Lightning Talk"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A lightning talk is a very short talk or presentation given at a conference or user group. Friends of mine are having lots of success talking about what they know about and I think it might be time for me to have a go. I am not a natural public speaker so this is a step out of my comfort zone, however I am going to start small and see what happens. At the moment I don’t know what my subject or topic is going to be, my suspicion is that it will be devops related as that interest me more but watch this space.&lt;/p&gt;</description></item><item><title>Looking back at 2017</title><link>https://blog-test.funkysi1701.com/posts/2017/looking-back-at-2017/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 28 Dec 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/looking-back-at-2017/</guid><category term="StarTrek">StarTrek</category><category term="Goals">Goals</category><category term="Azure">Azure</category><category term="Baby">Baby</category><category term="C-Sharp">C-Sharp</category><description>&lt;p&gt;As 2017 starts to draw to a close let’s look at some of the highlights from the past year.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Edward" src="https://blog-test.funkysi1701.com/images/2017/DSC_0376-e1510563039193-225x300.jpg" loading="lazy"
width="225" height="300"
/&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Edward&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In November I became a father again and celebrated the arrival of Edward into the world. Before the birth I was worried how well my first son James would adapt to the new arrival but I am happy to say I didn’t need to, he mostly ignores the new arrival.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Star Trek&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In September the latest Star Trek TV series Discovery arrived on Netflix. I have been very positive so far about the show, I am still positive however there are things that annoy me about the new show, however I am keen to see the next episode each week so they are definitely doing something right.&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Office move&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In May I helped my employer move to brand new &lt;a href="https://www.funkysi1701.com/posts/2017/office-move/" target="_blank" rel="noopener noreferrer"&gt;offices&lt;/a&gt;
. This was a lot of hard work, but everything went as planned and our new home is great.&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Side projects
&lt;img class="img-fluid" alt="Google Play" src="https://blog-test.funkysi1701.com/images/2017/googleplay.jpg" loading="lazy"
width="512" height="512"
/&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I blogged in February about having a side project but it wasn’t until later in the year that this solidified into what I am working on now. It started as a way to understand &lt;a href="https://www.funkysi1701.com/posts/2017/interfaces/" target="_blank" rel="noopener noreferrer"&gt;interfaces&lt;/a&gt;
this then led to learning Xamarin and creating an android app to help promote this blog. Troy Hunt expanded his HIBP API to include passwords that have been in data breaches, I then started working on pwned passwords which is a simple android frontend for this.&lt;/p&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Learning R&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In Feb I also experimented with a new programming language &lt;a href="https://www.funkysi1701.com/posts/2017/learning-r/" target="_blank" rel="noopener noreferrer"&gt;R&lt;/a&gt;
. It started with a problem about converting exchange rates and ended with a SQL stored procedure that executed some R code, I still want to learn lots more but it was a good example of the sorts of thing you can build with R.&lt;/p&gt;
&lt;ol start="6"&gt;
&lt;li&gt;DNS programmatically&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One of my most successful blogs was about how you can create &lt;a href="https://www.funkysi1701.com/posts/2017/creating-dns-records-programmatically/" target="_blank" rel="noopener noreferrer"&gt;dns&lt;/a&gt;
records within your application eg sites that have yourname.domain in the url. It was a great chance to look at how dns works and learn more about what azure can do to manage this. I want to expand on this and build something.&lt;/p&gt;
&lt;p&gt;So that was 2017, for some ideas about what 2018 might have in store for me look out for my next blog post.&lt;/p&gt;</description></item><item><title>Getting started with Azure Tables</title><link>https://blog-test.funkysi1701.com/posts/2017/azure-table-storage/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 17 Dec 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/azure-table-storage/</guid><category term="Azure">Azure</category><category term="SQL">SQL</category><category term="TableStorage">TableStorage</category><category term="Database">Database</category><description>&lt;p&gt;Azure Table storage is cheap way to store data, however it has some drawbacks that you should be aware of.&lt;/p&gt;
&lt;p&gt;Azure Table storage is a simple way to store NoSQL data with key/attribute pairs. I am very familiar with storing data in SQL databases and would still choose SQL over Table storage, however Table storage is significantly cheaper so could be worth investigating depending on your project.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.troyhunt.com/working-with-154-million-records-on/" target="_blank" rel="noopener noreferrer"&gt;Troy Hunt&lt;/a&gt;
makes use of Table storage for his Have I been pwned? website so there are projects out there that make use of it to great affect.&lt;/p&gt;
&lt;p&gt;To work with Table storage you need to use a nuget package &lt;strong&gt;WindowsAzure.Storage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Install-Package WindowsAzure.Storage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To load data from a Table in Azure Table storage I use the following code&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CloudTable table = tableClient.GetTableReference(&lt;span style="color:#e6db74"&gt;&amp;#34;tablename&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TableOperation retrieveOperation = TableOperation.Retrieve&amp;lt;Entity&amp;gt;(PartitionKey, Rowkey);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;table.CreateIfNotExists();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TableResult retrievedResult = table.Execute(retrieveOperation);
&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;Example eg = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Example();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (retrievedResult.Result != &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; eg.ID = ((Entity)retrievedResult.Result).Id;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; eg.Date = ((Entity)retrievedResult.Result).Date;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; eg;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You need to create a class (called Entity in the example above) derived from TableEntity which defines the Partitionkey and Rowkey, plus and other columns you want to store in table storage. The row key and partition key uniquely identify the data in the table, think of this as the primary key of the table if you are used to SQL. This class must also contain a parameterless constructor.&lt;/p&gt;
&lt;p&gt;This is the only way to retrieve data, using the partitionkey and rowkey. If you want to retrieve a specific piece of data you would need to retrieve all rows and then search them for what you need. For me this is not a big problem as I only have 150 rows but if you have millions of rows you may need to think carefully how to use this.&lt;/p&gt;
&lt;p&gt;To save data I use a very similar piece of code&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CloudStorageAccount storageAccount = CloudStorageAccount.Parse(path);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CloudTable table = tableClient.GetTableReference(&lt;span style="color:#e6db74"&gt;&amp;#34;tablename&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Entity post = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Entity(ID, DateTime.Now);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TableOperation insertOperation = TableOperation.InsertOrReplace(post);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;table.CreateIfNotExists();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;table.Execute(insertOperation);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I create a Entity object and then pass this as a parameter into the InsertOrReplace method.&lt;/p&gt;
&lt;p&gt;To delete data it is also very similar, you create an entity object and pass this as a parameter to the Delete method.&lt;/p&gt;
&lt;p&gt;When debugging my table storage code I found the &lt;a href="https://azure.microsoft.com/en-gb/features/storage-explorer/" target="_blank" rel="noopener noreferrer"&gt;Azure Storage Explorer&lt;/a&gt;
very useful for seeing what data actually existed in the table and what might be throwing an error, usually something wrong with my Entity.&lt;/p&gt;
&lt;p&gt;I mentioned earlier that Table Storage was cheaper than SQL Azure. Well for my simple playing about with things I have found my monthly charge of £10+ has been reduced to £1+ If I were to build anything that is more than just me learning about how it works I would probably continue to use SQL but for the cost of learning new tech it is well worth giving table storage a try.&lt;/p&gt;</description></item><item><title>Zero code changes outside of git</title><link>https://blog-test.funkysi1701.com/posts/2017/get-zero-code-changes-outside-source-control/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 13 Nov 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/get-zero-code-changes-outside-source-control/</guid><category term="Git">Git</category><category term="SQL">SQL</category><category term="VisualStudio">VisualStudio</category><category term="SourceCode">SourceCode</category><description>&lt;p&gt;Source control is bread and butter for web developers, however not so much for SQL developers and other business people. One of my goals for the coming year is to get the whole of my team using source control processes.&lt;/p&gt;
&lt;p&gt;One of the arguments against using source control is there will always be a few exceptions where it won’t be used. Lets look at a few scenarios to help make the case for source control.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scenario One&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Web Dev 1 makes a change in production to fix an issue and doesn’t use source control. Web Dev 2 is working on a new feature and makes use of source control. He is given the sign-off to deploy his new feature and in the process undoes Web Dev 1’s fix.&lt;/p&gt;
&lt;p&gt;Management blames Web Dev 2 as they “broke” stuff during the deployment. Web Dev 2 doesn’t understand what happened and Web Dev 1 is oblivious to the entire scenario despite in reality being part of the problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scenario Two&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A SQL Dev works all night to fix a problem. He deploy to production and doesn’t notice a missed where clause due to lack of sleep.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;Let’s look at these two scenarios done with the whole team buying into source control.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scenario One&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Web Dev 1 makes a change in production to fix an issue and also commits to source control. This takes him an extra 5 minutes (if that!) Web Dev 2 is working on a new feature and makes use of source control. He is given the sign-off to deploy his new feature and in the process merges Web Dev 1’s fix before he deploys to production.&lt;/p&gt;
&lt;p&gt;Management is happy with Web Dev 1, nothing is broken and new functionality has made the website better not worse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scenario Two&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A SQL Dev works all night to fix a problem. He deploy to production and doesn’t notice a missed where clause due to lack of sleep, he also commits to source control this takes him an extra 5 minutes (if that!).&lt;/p&gt;
&lt;p&gt;In the morning a colleague looks through the commits made during the night and queries the missing where clause. A fix is made in source control and deployed, management and the client are unaware that a problem was created and fixed.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;These are simple scenarios but I cannot think of any situation where the outcome would be better to not use source control. These examples assume no continuous deployment, adding this to the system before every team has bought into source control would cause bugs and issues all over the place.&lt;/p&gt;
&lt;p&gt;However with a team that is 100% behind source control continuous deployment can achieve an amazing productivity boost. After every commit code could be automatically tested, reviewed by other members of the team and deployed to test environments for further analysis. Only tested code that has been reviewed can get anywhere near production environments.&lt;/p&gt;
&lt;p&gt;Having said all this there are ways especially on the SQL side to mitigate loosing changes while you work on training individuals and convincing management. Before any code is deployed to production do a schema compare. If you only see changes you have made you can proceed, if you don’t shout at your team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Code Reviews&lt;br&gt;
Team awareness of what is being changed&lt;br&gt;
History of changes&lt;br&gt;
Smoother Deployments&lt;br&gt;
Automation&lt;br&gt;
Better Teamwork&lt;br&gt;
Diff changes between different versions&lt;br&gt;
Many more&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disadvantages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Time to learn tools&lt;br&gt;
Remember to commit changes&lt;br&gt;
Technologies that use binary files harder to version control&lt;/p&gt;</description></item><item><title>SQL with Visual Studio Code</title><link>https://blog-test.funkysi1701.com/posts/2017/sql-with-visual-studio-code/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 06 Nov 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/sql-with-visual-studio-code/</guid><category term="Database">Database</category><category term="SQL">SQL</category><category term="VisualStudio">VisualStudio</category><description>&lt;p&gt;Writing SQL queries is typically done with SQL Management Studio (SSMS). However this tool is a bit of a beast so let’s look at how you could use Visual Studio Code instead.&lt;/p&gt;
&lt;p&gt;Visual Studio Code is a free text editor but it is so much more than just a text editor. VS Code can be downloaded from &lt;a href="https://code.visualstudio.com/Download" target="_blank" rel="noopener noreferrer"&gt;https://code.visualstudio.com/Download&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;To work with SQL Server download the mssql extension. Press &lt;strong&gt;CTRL+SHIFT+P&lt;/strong&gt; and then Select &lt;strong&gt;Install Extension&lt;/strong&gt; and type &lt;strong&gt;mssql&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Intellisense in Visual Studio Code is brilliant, better than SSMS. Lets look at how to get it all set up.&lt;/p&gt;
&lt;p&gt;Create a new file and set the language type to SQL (Press &lt;strong&gt;CTRL+K,M&lt;/strong&gt; )&lt;/p&gt;
&lt;p&gt;Open the command palette, &lt;strong&gt;CTRL+SHIFT+P&lt;/strong&gt; and type SQL to show the mssql commands. Select the Connect command.&lt;/p&gt;
&lt;p&gt;Then select &lt;strong&gt;Create Connection Profile&lt;/strong&gt; , this creates a profile to connect with your SQL Server. Follow the prompts to get it all setup.&lt;/p&gt;
&lt;p&gt;Look in the bottom right corner of the status bar and you should see you are connected.&lt;/p&gt;
&lt;p&gt;Now if you type sql you will see a long list of SQL code snippets that you could use.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="SQL Code snippets" src="https://blog-test.funkysi1701.com/images/2017/vscode-sql-snippets.png" loading="lazy"
width="1016" height="534"
/&gt;
&lt;/p&gt;
&lt;p&gt;Choose a snippet to create, and edit it as required. When you are happy press **CTRL+SHIFT+E ** to execute.&lt;/p&gt;
&lt;p&gt;This is basically all there is to it. However this is an incredibly powerful way of working, the intellisense instantly tells you what database objects you can use in your query and there is a wealth of different snippets you can use.&lt;/p&gt;
&lt;p&gt;When returning data you get a similar view to SSMS but you can save as Excel, CSV or JSON.&lt;/p&gt;
&lt;p&gt;SSMS is a very graphical way of doing things, you can double click a table and see its columns or indexes. VS Code relies on TSQL commands but you have access to exactly the same information.&lt;/p&gt;
&lt;p&gt;For more information about VS Code and the mssql extension check out &lt;a href="https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-develop-use-vscode" target="_blank" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-develop-use-vscode&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Interfaces are cool!</title><link>https://blog-test.funkysi1701.com/posts/2017/interfaces-are-cool/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 31 Oct 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/interfaces-are-cool/</guid><category term="BadDesign">BadDesign</category><category term="Interface">Interface</category><description>&lt;p&gt;A while back I &lt;a href="https://www.funkysi1701.com/posts/2017/interfaces/" target="_blank" rel="noopener noreferrer"&gt;blogged&lt;/a&gt;
about learning about interfaces as I didn’t really understand the value of them. I do now.&lt;/p&gt;
&lt;p&gt;I created an application that used interfaces so I could learn how it worked. I created a Logger Interface and created multiple classes that implemented that interface so I could swap out the different implementations easily. I created a SQL Logger and a File Logger and my code could be written and be completely unaware of which implementation it was using.&lt;/p&gt;
&lt;p&gt;This application uses SQL Azure and so I have a monthly bill to pay. Wouldn’t it be cool if I could reduce this bill? How about using the cheaper table storage instead?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Easy!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a new class that implements my interface and all I need to do is write the three methods defined in my interface and I can swap from SQL Azure to table storage.&lt;/p&gt;
&lt;p&gt;Another benefit to interfaces is testing. Say I have an interface called inotification for sending notifications, I can have several implementations of this email, twitter, slack etc&lt;/p&gt;
&lt;p&gt;None of these implementations should be used in unit tests, as you don’t want a tweet being sent every time you run your tests. Why not create an implementation that simply returns something for each method call and doesn’t actually do anything. I can then run my tests with my fake implementation which tests my code logic but not the implementation I have chosen (this can be tested later on with integration tests or user testing if required).&lt;/p&gt;
&lt;p&gt;This is pretty much all I have to say about interfaces. I just like how I can swap different implementations.&lt;/p&gt;
&lt;p&gt;It does take a bit of work to get the interface setup. I found that when writing the second implementation the interface would need to change slightly, mostly as it was badly designed to begin with. I think for beginners there may be some value to writing multiple implementations of an interface so you can be sure your interface is good, however I am sure with experience this will not be required.&lt;/p&gt;</description></item><item><title>Create DNS records programmatically</title><link>https://blog-test.funkysi1701.com/posts/2017/creating-dns-records-programmatically/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 16 Oct 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/creating-dns-records-programmatically/</guid><category term="Azure">Azure</category><category term="DNS">DNS</category><description>&lt;p&gt;DNS is the backbone of the internet. It converts domain names into IP addresses. But how can we do clever things with it?&lt;/p&gt;
&lt;p&gt;Making DNS changes has always been a pain. You have to remember what company you registered your domain name with, then locate the login details for their website, login and fill in some web form and wait for the changes to replicate across the internet.&lt;/p&gt;
&lt;p&gt;There are various websites that assign you a custom subdomain name like name.domain.com, obviously they must do this programmatically, they don’t have a guy following the above process.&lt;/p&gt;
&lt;p&gt;Lets see how we could do this.&lt;/p&gt;
&lt;p&gt;My first thought was to make use of the DNSimple API. &lt;a href="https://developer.dnsimple.com/v2/" target="_blank" rel="noopener noreferrer"&gt;https://developer.dnsimple.com/v2/&lt;/a&gt;
The API allows all sort of DNS changes to be made, however this is a paid service so let’s look at other options.&lt;/p&gt;
&lt;p&gt;Azure now has a DNS section. You can go to the portal, add a DNS zone, and then add as many A, CNAME and MX records as you need. This is of course no better than doing it manually.&lt;/p&gt;
&lt;p&gt;Azure offers a &lt;a href="https://learn.microsoft.com/en-us/azure/dns/dns-sdk" target="_blank" rel="noopener noreferrer"&gt;SDK&lt;/a&gt;
and an example Visual Studio project. Let&amp;rsquo;s look at how it works.&lt;/p&gt;
&lt;p&gt;First you need to setup some credentials to use your Azure subscription. The easiest way to do this is with powershell.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Login&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;AzureRmAccount
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sp = New-AzureRmADServicePrincipal &lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;DisplayName exampleapp &lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;Password &lt;span style="color:#e6db74"&gt;&amp;#34;{provide-password}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sleep &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;New-AzureRmRoleAssignment &lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;RoleDefinitionName Contributor &lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;ServicePrincipalName $sp.ApplicationId
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will create a AD Service Principal which has access to your Azure subscription.&lt;/p&gt;
&lt;p&gt;You need to get the following IDs from the Azure portal.&lt;/p&gt;
&lt;p&gt;subscriptionId for your subscription&lt;br&gt;
tenantId or the Azure AD Directory ID&lt;br&gt;
applicationId of the service principal created above&lt;br&gt;
password you entered into the powershell script above&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; serviceCreds = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; ApplicationTokenProvider.LoginSilentAsync(tenantId, clientId, secret);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; dnsClient = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; DnsManagementClient(serviceCreds);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dnsClient.SubscriptionId = subscriptionId;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; recordSetParams = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; RecordSet();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recordSetParams.TTL = &lt;span style="color:#ae81ff"&gt;3600&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recordSetParams.ARecords = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; List&amp;lt;ARecord&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recordSetParams.ARecords.Add(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ARecord(&lt;span style="color:#e6db74"&gt;&amp;#34;1.2.3.4&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; recordSet = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; dnsClient.RecordSets.CreateOrUpdateAsync(resourceGroupName, &lt;span style="color:#e6db74"&gt;&amp;#34;funkysi1701.com&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;, RecordType.A, recordSetParams);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above code connects to Azure and creates an A record for test.funkysi1701.com that points at the ip address 1.2.3.4.&lt;/p&gt;
&lt;p&gt;Other DNS records can be created in a similar way.&lt;/p&gt;
&lt;p&gt;The above example creates a new RecordSet but you can use the following to delete or get existing records.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; recordSet = dnsClient.RecordSets.Get(resourceGroupName, &lt;span style="color:#e6db74"&gt;&amp;#34;funkysi1701.com&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;, RecordType.A);
&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;dnsClient.RecordSets.Delete(resourceGroupName, &lt;span style="color:#e6db74"&gt;&amp;#34;funkysi1701.com&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;, RecordType.A);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now I have found out that I can write a console app to edit my DNS records I need to change the nameservers for all my domains so I can take advantage of this new feature.&lt;/p&gt;</description></item><item><title>Discovery – My thoughts so far</title><link>https://blog-test.funkysi1701.com/posts/2017/discovery-my-thoughts-so-far/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 10 Oct 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/discovery-my-thoughts-so-far/</guid><category term="StarTrek">StarTrek</category><category term="Discovery">Discovery</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2017/DAD0hTKUAAAUkTP.jpg"/><description>&lt;p&gt;I tried to resist but I am going to have to write about the new Star Trek series Discovery. Warning this post is going to include SPOILERS. If you read on you have been warned.&lt;/p&gt;
&lt;p&gt;I watched the first two episodes of the brand new Star Trek TV show. As I am an international viewer I used Netflix, if you are from the US you need to use CBS All Access.
&lt;img class="img-fluid" alt="Promotional image from Star Trek Discovery" src="https://blog-test.funkysi1701.com/images/2017/DAD0hTKUAAAUkTP.jpg" loading="lazy"
width="1199" height="663"
/&gt;
&lt;/p&gt;
&lt;p&gt;I have heard a lot of complaining that the show is not free to watch. CBS is making Star Trek Discovery to make money, if they don’t make money they will stop making it. Its as simple as that.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.netflix.com" target="_blank" rel="noopener noreferrer"&gt;Netflix&lt;/a&gt;
costs £5.99 per month and &lt;a href="https://www.paramountplus.com/home/" target="_blank" rel="noopener noreferrer"&gt;CBS All Access&lt;/a&gt;
costs $5.99 per month. I don’t believe this is a lot of money. The 5.99 above allows you to watch any of the 726 Star Trek episodes at any time of day whenever you want as many times as you want, plus you have access to all the other movies or TV shows available. I don’t think this is too much to ask.&lt;/p&gt;
&lt;p&gt;Back to Discovery. I loved it! It felt like Star Trek. I had feared it might only share the name and would be an action filled TV show that had little in common with what he had seen before. I was wrong this is definitely a show that can proudly call itself Star Trek.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Klingons&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When it was first announced that the Klingons would feature in the new show I was a bit “meh”. We had done lots with the Klingons before and they had never been my favourite alien race.
&lt;img class="img-fluid" alt="Redesigned Klingons from Star Trek Discovery" src="https://blog-test.funkysi1701.com/images/2017/star-trek-discovery-klingons-1002567-1280x0.jpg" loading="lazy"
width="1280" height="704"
/&gt;
&lt;/p&gt;
&lt;p&gt;The look of the Klingons was also going to be changed, I have to admit this didn’t bother me. Klingons have had their look updated before. In 1966 Klingons had dark faces and smooth foreheads, in 1979 the forehead ridges were added as the first Star Trek movie was made, and now Discovery has removed all hair from Klingons. I can explain it away as productional changes, I don’t need an on screen explanation like we had on Enterprise (or even DS9).&lt;/p&gt;
&lt;p&gt;What I have seen so far is a menacing alien race that fits with what we have seen before with lots of references to honor, Kahless and speaking Klingon. I must admit reading all the subtitles is getting a bit tiresome, but that is a minor issue.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conflict&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Historically Star Trek has not featured conflict between the main starfleet characters due to the idea that humanity has evolved beyond this. DS9 got round this by having Odo and Kira who are not starfleet characters so can have a little bit of conflict. Discovery has completely abandoned this idea.&lt;/p&gt;
&lt;p&gt;In the pilot episode, the Michael Burnham commits mutiny on her captain, even attacking her with a vulcan nerve pinch. In the third episode we finally meet the discovery crew. Gone are the TNG days where the ships crew are like a family, I am not sure I can think of a single character that would call another character “friend”. We are in a time of war so this would be expected, however I do hope we see deepening friendships form between characters.&lt;/p&gt;
&lt;p&gt;I am OK with the change to feature more conflict. I must admit the darkness of the third episode, did stop to make me think a bit, however by the fourth episode I was won over.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cast&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The story is concentrated around Michael Burnham, so I do worry that other characters won’t get a look in. However from what I have seen Michael Burnham is a great character. She is a strong female character, with a intriguing back story relating to Sarek and possibly also Spock.&lt;/p&gt;
&lt;p&gt;Saru the alien character on the show, played by the very tall Doug Jones is great. From the trailers he was all about sensing death, but there is far more to him than that. I am looking forward to learn more about him and his threat ganglia.&lt;/p&gt;
&lt;p&gt;As the show has gone on we have started to learn about the other characters like Captain Lorca, Tilly and Paul Stamets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Title Sequence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I don’t like the opening title sequence, it feels very cheap like a draft version which hasn’t been finished yet. I was looking forward to a title sequence that would show off the USS Discovery, maybe like TNG where it warps around our own solar system. What we see is some of the tech that features in Star Trek which is nice but I want more. The theme tune while great that it features parts from the classic theme doesn’t stand on its own. I can hum all the other TV shows themes, and now after 4 episodes would struggle to do that.&lt;/p&gt;
&lt;p&gt;However I expect that after a while I will grow to like this more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overall&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I like Discovery and I will keep watching it. I want to find out what happens to the characters. There are no annoying characters like other shows have had. There is character development, none of the characters are going to finish where they started. I want more friendship between characters, but I expect that will come, I want more exploring and doing Star Trek stuff, but most of all I want more episodes, roll on next weeks show.&lt;/p&gt;
&lt;p&gt;Other things I noticed&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sound effects on the bridge are awesome, it makes me feel at home&lt;/li&gt;
&lt;li&gt;The USS Discovery doesn’t feature in the first two episodes despite being the title of the show.&lt;/li&gt;
&lt;li&gt;Others have noted that Captain Georgiou has books on her shelf which feature classic episode titles&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Did you know you can track episodes from Star Trek Discovery in &lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Star Trek is back with Discovery</title><link>https://blog-test.funkysi1701.com/posts/2017/star-trek-is-back-with-discovery/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 22 Sep 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/star-trek-is-back-with-discovery/</guid><category term="StarTrek">StarTrek</category><category term="Discovery">Discovery</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2017/gqojtfz1dhmxoiri7g8p.png"/><description>&lt;p&gt;In &lt;a href="https://www.funkysi1701.com/posts/2015/star-trek-is-back-in-2017/" target="_blank" rel="noopener noreferrer"&gt;November 2015&lt;/a&gt;
it was announced that a new Star Trek series was going to be launched. It has been a long wait with multiple delays but Star Trek Discovery is finally here.&lt;/p&gt;
&lt;p&gt;Star Trek Discovery launches in the US on 24th September and in the UK on 25th September.&lt;/p&gt;
&lt;iframe title="YouTube video: Star Trek Discovery trailer" src="https://www.youtube.com/embed/UoV3kc05Nwc?rel=0" width="560" height="315" frameborder="0" allowfullscreen="allowfullscreen"&gt;&lt;/iframe&gt;
&lt;p&gt;Lets have a look back how we got here.&lt;/p&gt;
&lt;p&gt;Star Trek was created by Gene Roddenberry in the 1960s. He imagined a show where we would explore the galaxy while also exploring the human condition. He described it as a wagon train to the stars. However it was cancelled after 79 episodes and three seasons due to budget cuts and low viewers.&lt;/p&gt;
&lt;p&gt;After cancellation its popularity boomed in reruns. In the mid 1970s an animated series was created. But demand for Star Trek continued until a new Star Trek show was commissioned called Phase Two.&lt;/p&gt;
&lt;p&gt;In 1977 Star Wars came out, and the phase two idea was cancelled and turned into a movie. In 1979 we got Star Trek The Motion Picture. It went massively over budget and failed to really capture the Star Trek spirit.&lt;/p&gt;
&lt;p&gt;A much cheaper sequel was created in 1982 Star Trek II: The Wrath of Khan with Roddenberry taking more of a back seat. A film widely considered to be one of the best trek films. Four more feature films starring the original cast were made.&lt;/p&gt;
&lt;p&gt;However in 1987 Gene Roddenberry teamed up with Rick Berman and The Next Generation was created with a brand new cast. The series ran for seven seasons set roughly a century after the adventures of Kirk and Spock.&lt;/p&gt;
&lt;p&gt;Popularity of Star Trek soured and this led Rick Berman to help create the spin off series Deep Space 9, Voyager and lastly Enterprise along with four feature films continuing the adventures of the TNG cast. When Enterprise was cancelled in 2005, Star Trek appeared to be dead after 18 years on TV.&lt;/p&gt;
&lt;p&gt;However in 2009 movie creator JJ Abrams recast the classic crew for the big screen. The film was big on action, but took place in an alternative timeline allowing for familiar characters to have new adventures without interfering with events depicted in the TV shows.&lt;/p&gt;
&lt;p&gt;Two sequels to this film have been produced and are bringing Star Trek back into popularity. This has given rise to Discovery. Star Trek is returning to the TV screen and it is going to be great.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Discovery" src="https://blog-test.funkysi1701.com/images/2017/gqojtfz1dhmxoiri7g8p.png" loading="lazy"
width="800" height="450"
/&gt;
&lt;/p&gt;</description></item><item><title>Azure Friday</title><link>https://blog-test.funkysi1701.com/posts/2017/azure-friday/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 18 Sep 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/azure-friday/</guid><category term="Azure">Azure</category><category term="ApplicationInsights">ApplicationInsights</category><description>&lt;p&gt;I think Azure is great, but there is loads to it so I can never know about all of its features. There is a video series hosted by Scott Hanselman called &lt;a href="https://learn.microsoft.com/en-us/shows/azure-friday" target="_blank" rel="noopener noreferrer"&gt;Azure Fridays&lt;/a&gt;
which I have started to watch in an effort to keep more up to date about some of its cool features.&lt;/p&gt;
&lt;iframe title="Azure Friday: Debug .NET apps in production with the Snapshot Debugger in Application Insights" src="https://learn.microsoft.com/en-us/shows/azure-friday/debug-net-apps-in-production-snapshot-debugger-in-application-insights/player" width="960" height="540" frameborder="0" allowfullscreen="allowfullscreen"&gt;&lt;/iframe&gt;
&lt;p&gt;I watched this video recently and it is all about application insights and new ways you can debug your web applications by creating snapshots. I am a big fan of application insights so adding extra ways to debug my apps is a big win for me. Once I get this feature working in my code I will no doubt blog about it.&lt;/p&gt;</description></item><item><title>Azure Functions</title><link>https://blog-test.funkysi1701.com/posts/2017/azure-functions/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 12 Sep 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/azure-functions/</guid><category term="Azure">Azure</category><category term="DevOps">DevOps</category><description>&lt;p&gt;I recently blogged about using &lt;a href="https://www.funkysi1701.com/posts/2017/using-azure-webjobs-to-automate-stuff/" target="_blank" rel="noopener noreferrer"&gt;Azure Web Jobs&lt;/a&gt;
, Azure Function is another way of doing the same thing, lets look at how they work.&lt;/p&gt;
&lt;p&gt;(Sorry its been a while since I blogged but I suspect an erratic schedule will continue for the next few months.)&lt;/p&gt;
&lt;p&gt;To create an Azure Function go to the Azure portal and click add new and search for &amp;ldquo;Function App&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Give your app a name and select the usual resource group and location settings.&lt;/p&gt;
&lt;p&gt;Now when you open Function Apps you should see your new app.&lt;/p&gt;
&lt;p&gt;I want my Function App to run on a schedule so I clicked the + next to functions and selected TimerTrigger. I am a c# programmer so I selected this option as well.&lt;/p&gt;
&lt;p&gt;Give your function a name and specify using the usual cron notation how often it should run. I want mine to run at 9.30pm each night so use 0 30 21 * * *&lt;/p&gt;
&lt;p&gt;Now comes the code bit. By default you get a window with the following code in it&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Run(TimerInfo myTimer, TraceWriter log)
&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; log.Info(&lt;span style="color:#e6db74"&gt;$&amp;#34;C# Timer trigger function executed at: {DateTime.Now}&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is entirely up to you what you get your function to do. In my case I just wanted to call a URL on a schedule so I created some code that used httpclient.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.Net.Http;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; Task Run(TimerInfo myTimer, TraceWriter log)
&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; log.Info(&lt;span style="color:#e6db74"&gt;$&amp;#34;Buffer 0 function executed at: {DateTime.Now}&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; HttpClient client = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; HttpClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; result = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; client.GetAsync(&lt;span style="color:#e6db74"&gt;&amp;#34;URL&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; resultContent = &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; result.Content.ReadAsStringAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; log.Info(resultContent);
&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;Once you have created your app and it has run you can use the monitor section to view success and failures.&lt;/p&gt;
&lt;p&gt;There is loads more you can do with Azure Function but this is a good place to start.&lt;/p&gt;</description></item><item><title>Pwned Pass available on Play Store</title><link>https://blog-test.funkysi1701.com/posts/2017/pwned-pass-available-from-the-play-store/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 14 Aug 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/pwned-pass-available-from-the-play-store/</guid><category term="Android">Android</category><category term="Mobile">Mobile</category><category term="App">App</category><category term="PwnedPass">PwnedPass</category><description>&lt;p&gt;Pwned Pass is now available from the Google Play Store.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Pwned Pass" src="https://blog-test.funkysi1701.com/images/2017/Screenshot_20170813-205152.png" loading="lazy"
width="1080" height="1920"
/&gt;
&lt;/p&gt;
&lt;p&gt;Pwned Pass is a simple android app that allows you to type in a password and tells you if it has been used in a data breach.&lt;/p&gt;
&lt;p&gt;Troy Hunt of &lt;a href="https://haveibeenpwned.com/" target="_blank" rel="noopener noreferrer"&gt;Have I Been Pwned?&lt;/a&gt;
recently added a new API to his website which allows you to search his extensive database of pwned passwords, 306 million of them. I have simply created a Android frontend to this API.&lt;/p&gt;
&lt;p&gt;The API itself takes a SHA1 hash of the password and either returns a HTTP 200 if the password is found or a HTTP 404 if the password does not exist in the HIBP database. For more details of how Troy Hunt created this check out his &lt;a href="https://www.troyhunt.com/introducing-306-million-freely-downloadable-pwned-passwords/" target="_blank" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;My app simply generates a SHA1 hash of anything that is typed in and then passes this to Troy Hunt’s API. I then get the HTTP return code so I know if the password exists or not.&lt;/p&gt;
&lt;p&gt;It should be noted that: &lt;strong&gt;Do not send any password you actively use to a third-party service – even this one!&lt;/strong&gt; I don’t log anything that you type into my app and all I am then doing is passing a SHA1 hash over SSL to HIBP. However you shouldn’t trust my word alone.&lt;/p&gt;
&lt;p&gt;The app itself is written in Visual Studio with Xamarin Forms in a similar fashion to the app I talked about &lt;a href="https://www.funkysi1701.com/posts/2017/android-app-development-and-the-visual-studio-mobile-centre/" target="_blank" rel="noopener noreferrer"&gt;last week&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;As I am using Xamarin Forms there is the potential that I may develop iPhone or UWP versions of this code in the future. With that in mind I have made use of interfaces for the android specific parts of the code.&lt;/p&gt;
&lt;p&gt;I also make use of the &lt;a href="https://www.nuget.org/packages/modernhttpclient/" target="_blank" rel="noopener noreferrer"&gt;modernhttpclient&lt;/a&gt;
nuget package due to problems I encountered with httpclient and SSL. This is due to limitations of what libraries are available in mono and what has been implemented, I suspect there are better ways to solve this but that is all part of the fun.&lt;/p&gt;
&lt;p&gt;Please do have a look at Pwned Pass and let me know what you think. Especially if it doesn’t work or throws errors. I would like to spend time making this app as good as I can make it.&lt;/p&gt;</description></item><item><title>Android apps with Mobile Centre</title><link>https://blog-test.funkysi1701.com/posts/2017/android-app-development-and-the-visual-studio-mobile-centre/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 07 Aug 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/android-app-development-and-the-visual-studio-mobile-centre/</guid><category term="App">App</category><category term="Azure">Azure</category><category term="Android">Android</category><description>&lt;p&gt;For the past week or so I have been playing around with Xamarin and creating an android app.&lt;/p&gt;
&lt;p&gt;Well I now have an app in the Google Play Store.
&lt;img class="img-fluid" alt="Screenshot of my Android app listing in the Google Play Store" src="https://blog-test.funkysi1701.com/images/2017/Screenshot_20170806-190053.png" loading="lazy"
width="1080" height="1920"
/&gt;
&lt;/p&gt;
&lt;p&gt;Before you rush and download the app I must warn you that it doesn’t do much yet. It displays some content that is on my website and there are a few links to allow sharing of content. I have some ideas to display content from my blog and allow sharing. I also have some other ideas for apps that might actually be useful to people that are not me. If you have ideas or feature requests do let me know.&lt;/p&gt;
&lt;p&gt;Ok how did I go about creating this app and getting it in the app store?&lt;/p&gt;
&lt;p&gt;Xamarin is now part of Visual Studio so step one is install all the Xamarin features to Visual Studio and build an app.&lt;/p&gt;
&lt;p&gt;Next I wanted to monitor my app. Now I know Application Insights doesn’t support apps so what tools are out there? HockeyApp is something I had heard of but they are in the process of being replaced with &lt;code&gt;https://appcenter.ms/apps&lt;/code&gt;. (Edit: Visual Studio App Center was retired on March 31, 2025)&lt;/p&gt;
&lt;p&gt;It was relatively easy to hook up my app to Visual Studio Mobile Centre. First install the required nuget packages. Then add using statements and the following line to your MainActivity.cs file (these instructions are available on the Mobile Centre)&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Microsoft.Azure.Mobile;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Microsoft.Azure.Mobile.Analytics;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Microsoft.Azure.Mobile.Crashes;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Microsoft.Azure.Mobile.Distribute;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Microsoft.Azure.Mobile.Push;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MobileCenter.Start(&lt;span style="color:#e6db74"&gt;&amp;#34;[Unique ID]&amp;#34;&lt;/span&gt;,&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(Analytics), &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(Crashes), &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(Distribute), &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt;(Push));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you can connect the Mobile Centre to your source code (VSTS in my case) and get it to run a build for every commit.&lt;/p&gt;
&lt;p&gt;One complexity of the build is that you need to supply a keystore file (basically a certificate to digitally sign your app). I found the best way to do this was to use Visual Studio to create the file.&lt;/p&gt;
&lt;p&gt;In VS2017 there is a option called Archive Manager under the tools menu. In here click the distribute button and select Ad-hoc. In the signing identity section you can create a keystore file. Enter a few details and a keystore file will be created in AppData\Local\Xamarin\Mono for Android\Keystore[keystore name][keystore name.keystore]&lt;/p&gt;
&lt;p&gt;Once you have added the keystore file to your build you can enable the distribute option. Now you will get an email after every build with a link to install your app.&lt;/p&gt;
&lt;p&gt;Every time your app crashes the details will be logged in the crashes section for you to explore and fix the issues.&lt;/p&gt;
&lt;p&gt;The Analytics section allows you to explore how your app is being used. You can also add Analytics.TrackEvent(&amp;ldquo;Feature X&amp;rdquo;) to measure the usage of different features.&lt;/p&gt;
&lt;p&gt;There are more things you can do which I will explore more at another time along with how to get your app into the Google Play Store.&lt;/p&gt;</description></item><item><title>Creating NuGet packages with VSTS</title><link>https://blog-test.funkysi1701.com/posts/2017/creating-nuget-packages/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 31 Jul 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/creating-nuget-packages/</guid><category term="NuGet">NuGet</category><category term="C-Sharp">C-Sharp</category><category term="VisualStudio">VisualStudio</category><description>&lt;p&gt;For a while I have found myself writing the same bits of code for different web projects. This annoys me as it goes against the DRY principle (don’t repeat yourself).&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Nuget" src="https://blog-test.funkysi1701.com/images/2017/nuget.png" loading="lazy"
width="444" height="135"
/&gt;
One possible solution is to write your own nuget packages. You can then add this piece of code to any project you work on.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.nuget.org/" target="_blank" rel="noopener noreferrer"&gt;nuget.org&lt;/a&gt;
is the public nuget feed where any developer can download nuget packages. You could publish your nuget package here, but your might want to restrict access so better to create a private nuget feed.&lt;/p&gt;
&lt;p&gt;Lets look at how we create a nuget feed in Visual Studio. First thing you need to do is install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms.feed" target="_blank" rel="noopener noreferrer"&gt;Package Management&lt;/a&gt;
extension to Visual Studio Team Services (its free for less than 5 users), this will add a packages section under the build menu.&lt;/p&gt;
&lt;p&gt;Before you can start using this new feature you need to add a Package Management License in the users hub.&lt;/p&gt;
&lt;p&gt;Once that is done you can create a feed. You need to give your feed a name, decide if only members of the current project or everyone in your account should have access to read and contribute to.&lt;/p&gt;
&lt;p&gt;Now you have a feed you could use the nuget package command to create a nupkg file and then nuget push command to add it to your feed. A better way is to get Visual Studio Team Services to do all the hard work.&lt;/p&gt;
&lt;p&gt;Create a new project in Visual Studio Team Service to house your nuget package. In the build section add an empty build definition. Choose a build agent, I am using the Hosted VS2017. Then add the following steps nuget restore, Visual Studio Build, nuget pack and nuget push.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nuget restore – this step is only needed if your code depends on other packages. If it depends on other packages that are only in your feed you must specify your feed in the feeds and authentication section.&lt;/li&gt;
&lt;li&gt;Visual Studio Build – this builds your code like you would in Visual Studio. The only config I made to this step was to specify Release in configuration.&lt;/li&gt;
&lt;li&gt;nuget pack – this creates the nupkg file from your built project. In configuration to package specify the same as you specified in the previous step (in my case Release)&lt;/li&gt;
&lt;li&gt;nuget push – this publishes to your feed, so of course you need to specify your feed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One last thing to configure is to enable the continuous integration option in triggers. This means whenever you push code all these steps will run and you have a new version of your nuget package.&lt;/p&gt;
&lt;p&gt;In Visual Studio you need to create a *.nuspec file, this contains all the meta data about your nuget package. Let look at an example.&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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;package&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;metadata&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;$id$&lt;span style="color:#f92672"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.2&lt;span style="color:#f92672"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Nuget&lt;span style="color:#f92672"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;authors&amp;gt;&lt;/span&gt;Simon Foster&lt;span style="color:#f92672"&gt;&amp;lt;/authors&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;owners&amp;gt;&lt;/span&gt;Simon Foster&lt;span style="color:#f92672"&gt;&amp;lt;/owners&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;requireLicenseAcceptance&amp;gt;&lt;/span&gt;false&lt;span style="color:#f92672"&gt;&amp;lt;/requireLicenseAcceptance&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;An example of a nuget package.&lt;span style="color:#f92672"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;releaseNotes&amp;gt;&lt;/span&gt;Release Notes&lt;span style="color:#f92672"&gt;&amp;lt;/releaseNotes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;copyright&amp;gt;&lt;/span&gt;Copyright 2017&lt;span style="color:#f92672"&gt;&amp;lt;/copyright&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;projectUrl&amp;gt;&lt;/span&gt;https://[yourVSaccount].visualstudio.com/nuget/&lt;span style="color:#f92672"&gt;&amp;lt;/projectUrl&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/metadata&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/package&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One last thing to mention is version numbers. You can either change the version number in your *.nuspec file everytime you push changes. This will create stable packages like 1.0, 1.1, 1.2 etc&lt;/p&gt;
&lt;p&gt;However you can use the automatic version number setting in the nuget pack build step. However I have found this only ever creates pre-release packages and I haven’t found a way to upgrade a package from pre-release to stable.&lt;/p&gt;
&lt;p&gt;This is a really neat way to reuse your code in multiple projects. I have only been looking at this for a few days and I have already extracted code to do with emails, creating excel downloads and database related methods. I suspect that doing this will also have a side benefit of forcing me to create code with fewer dependencies so more code can be turned into a nuget package.&lt;/p&gt;</description></item><item><title>Async and Await</title><link>https://blog-test.funkysi1701.com/posts/2017/async-and-await/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 24 Jul 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/async-and-await/</guid><category term="Async">Async</category><category term="Await">Await</category><category term="C-Sharp">C-Sharp</category><description>&lt;p&gt;For a while the Async and Await commands in c# have confused me.&lt;/p&gt;
&lt;p&gt;Like most things the best way to learn about something is to use it in a real world example. I am currently adding an email alert feature to a website. This is an ideal example of something that would benefit from Asynchronous programming. There is no need for the webpage to wait to send 1000s of emails, lets just send a call to get started and allow the browser to carry on as normal.&lt;/p&gt;
&lt;p&gt;This is my first try at using async and await so feel free to suggest best practises in the comments.&lt;/p&gt;
&lt;p&gt;Lets start with a Send method in my EmailController.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; ActionResult Send(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; id, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; pageId, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; userID)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (!Authorize.checkPageIsAuthorised(userID, (Authorize.PageIds)pageId))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Redirect(&lt;span style="color:#e6db74"&gt;&amp;#34;/login&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Task&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt; t = SendNotifications(id,userID);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Redirect(Request.UrlReferrer.ToString());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This simply checks to see if you have permission to the page. If not redirects to the login page otherwise it makes a method call and redirects back to the page it came from.&lt;/p&gt;
&lt;p&gt;Lets have a look at that method call in more detail.&lt;/p&gt;
&lt;p&gt;Task&lt;string&gt; t = SendNotification(id, userid);&lt;/p&gt;
&lt;p&gt;SendNotification doesn’t return a normal string it returns a Task&lt;string&gt;, so lets look at how we are creating 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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; Task&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&amp;gt; SendNotifications(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; id,&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; type,&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; userid)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//logic ommitted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; ef.SendEmail(model, emailHtmlBody);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The return type is set to Task but it has the aysnc keyword appended to it. It also makes a call with the await keyword.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; Task SendEmail(EmailModel model,&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; emailHtmlBody)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//logic removed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; smtp.SendMailAsync(message);
&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;So that is it. My first bit of code that uses Async and Await. My controller calls a method asynchronously which then calls another method asynchronously which sends emails asynchronously.&lt;/p&gt;
&lt;p&gt;Async – This enables the Await keyword to be used in the method&lt;/p&gt;
&lt;p&gt;Await – This is where things get asynchronous. The await keyword allows the code to wait asynchronously for the long running code to complete.&lt;/p&gt;</description></item><item><title>How good is your SSL?</title><link>https://blog-test.funkysi1701.com/posts/2017/how-good-is-your-ssl/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 17 Jul 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/how-good-is-your-ssl/</guid><category term="SSL">SSL</category><category term="Security">Security</category><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Troy Hunt SSL expert" src="https://blog-test.funkysi1701.com/images/2017/Troy-Hunt-Profile-Photo.jpg" loading="lazy"
width="800" height="800"
/&gt;
&lt;/p&gt;
&lt;p&gt;I recently watched Troy Hunt’s &lt;a href="https://www.pluralsight.com/courses/https-every-developer-must-know" target="_blank" rel="noopener noreferrer"&gt;What Every Developer Must Know about HTTPS&lt;/a&gt;
course on Pluralsight. Its very good and really make you think about SSL certificates and how to correctly implement them.&lt;/p&gt;
&lt;p&gt;One thing in particular Troy mentions is the website &lt;a href="https://www.ssllabs.com/ssltest/index.html" target="_blank" rel="noopener noreferrer"&gt;SSL Labs&lt;/a&gt;
. This website allows you to test a websites implementation of SSL. A grade of A to F is assigned with A being the best and F being the worst.&lt;/p&gt;
&lt;p&gt;Troy Hunt has a &lt;a href="https://www.troyhunt.com/do-you-really-want-bank-grade-security/" target="_blank" rel="noopener noreferrer"&gt;blog&lt;/a&gt;
post where he discusses how Australian Banks score. Lets look at a few UK banks.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Bank&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;SSL Certificate&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Grade&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Home Page Under SSL&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HSBC&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.hsbc.co.uk" target="_blank" rel="noopener noreferrer"&gt;www.hsbc.co.uk&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nationwide&lt;/td&gt;
&lt;td&gt;onlinebanking.nationwide.co.uk&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NatWest&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.nwolb.com" target="_blank" rel="noopener noreferrer"&gt;www.nwolb.com&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Barclaycard&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.barclaycard.co.uk" target="_blank" rel="noopener noreferrer"&gt;www.barclaycard.co.uk&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;A-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Barclays&lt;/td&gt;
&lt;td&gt;bank.barclays.co.uk&lt;/td&gt;
&lt;td&gt;A-&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lloyds Bank&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.lloydsbank.com" target="_blank" rel="noopener noreferrer"&gt;www.lloydsbank.com&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Royal Bank of Scotland&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.rbsdigital.com" target="_blank" rel="noopener noreferrer"&gt;www.rbsdigital.com&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard Chartered&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.sc.com" target="_blank" rel="noopener noreferrer"&gt;www.sc.com&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Virgin Money&lt;/td&gt;
&lt;td&gt;uk.virginmoney.com&lt;/td&gt;
&lt;td&gt;A+&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Santander&lt;/td&gt;
&lt;td&gt;retail.santander.co.uk&lt;/td&gt;
&lt;td&gt;A-&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On the whole the ratings are all quite good with all being in the range A-C. However I have also indicated if they have SSL on the home page. Only 4 out 10 website listed above have the home page load under SSL.&lt;/p&gt;
&lt;p&gt;Why does this matter as long as the login is under SSL? Any page that loads over http is potentially at risk from a man in the middle attack. A fake malicious home page could contain links to any page and trick users into entering personal information.&lt;/p&gt;
&lt;p&gt;If you want to test a bank or other website not listed here. Go to &lt;a href="https://www.ssllabs.com/ssltest/index.html" target="_blank" rel="noopener noreferrer"&gt;https://www.ssllabs.com/ssltest/index.html&lt;/a&gt;
and type the address that is on the SSL certificate in to the search. The good news is that this site scores a A.&lt;/p&gt;
&lt;p&gt;Troy mentions that there is rapid growth in the adoption of SSL, there is also rapid growth in improving ratings. One of these banks went from a C to an A during the course of writing this blog.&lt;/p&gt;</description></item><item><title>Writing your first test</title><link>https://blog-test.funkysi1701.com/posts/2017/writing-your-first-test/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 10 Jul 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/writing-your-first-test/</guid><category term="Act">Act</category><category term="Arrange">Arrange</category><category term="Assert">Assert</category><category term="Testing">Testing</category><description>&lt;p&gt;Whenever I write a new test I have to think how best to do it. Hopefully I can summarise a few tips here to help get started.&lt;/p&gt;
&lt;h2 id="arrange-act-assert"&gt;Arrange Act Assert&lt;a class="anchor ms-1" href="#arrange-act-assert" aria-label="Permalink: Arrange Act Assert"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first thing I think about when writing a test is Arrange, Act, Assert. Arrange, Act, Assert is a pattern for writing the tests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Arrange&lt;/strong&gt; – This gets things in order ready to execute the test.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Act&lt;/strong&gt; – This executes the method you want to test.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Assert&lt;/strong&gt; – This compares the value produced in the Act step with a known value typically with a method similar to the following&lt;/p&gt;
&lt;p&gt;Assert.AreEqual(expected value, actual value)&lt;/p&gt;
&lt;p&gt;Say for example you wanted to test a method called ReturnsTrue() which does nothing but returns a value of true. This method is in a class called ReturnsTrueClass&lt;/p&gt;
&lt;p&gt;The Arrange step in this example would be.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ReturnsTrueClass t = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ReturnsTrueClass();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Act step in this example would be.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; result = t.ReturnTrue();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Assert step in this example would be.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Assert.AreEqual(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, result);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a stupidly simple example but hopefully you get the idea of how you can build all your tests with these three steps.&lt;/p&gt;
&lt;p&gt;Recently I saw a tweet complaining that someone has mixed up expected and actual in the Assert statement.&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;There is a minor but special hell reserved for those who mix up the expected and actual parameters in Assert.Equals&lt;/p&gt;&amp;mdash; Keith Williams (@zogface) &lt;a href="https://twitter.com/zogface/status/882737770095149056?ref_src=twsrc%5Etfw"&gt;July 5, 2017&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;At first glance this probably isn’t the worst mistake to make as if your tests are all passing actual and expected are the same.&lt;/p&gt;
&lt;p&gt;However tests will fail, that is the whole point of them, you can then fix bits of code. If you have mixed up actual and expected it adds extra time to debugging and figuring out what values are produced from your code and what you are expecting it to produce. It may be your test uses a mocking framework and somewhere in there, there is an issue, with mixed up expected/actual you may assume a problem in your code rather than the test.&lt;/p&gt;
&lt;p&gt;Also, how do you make such an error? When I type Assert.AreEquals() in Visual Studio, Visual Studio tells me what each parameter does, it takes a matter of seconds to do this, just by hovering over the code.&lt;/p&gt;
&lt;p&gt;One last tip to say about tests. Write your tests to test the behaviour of your application.&lt;/p&gt;</description></item><item><title>Uploading Files to AWS</title><link>https://blog-test.funkysi1701.com/posts/2017/uploading-files-to-aws/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 03 Jul 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/uploading-files-to-aws/</guid><category term="AWS">AWS</category><category term="C-Sharp">C-Sharp</category><description>&lt;p&gt;I am a fan of Azure but today I have been looking at AWS. Specifically how to upload and download files.&lt;/p&gt;
&lt;p&gt;AWS S3 stores files in Buckets. I already had an AWS S3 account setup with a Bucket. I am going to assume you have got a bucket setup and concentrate on the code to get files in and out.&lt;/p&gt;
&lt;p&gt;First step is to use nuget to install the AWS packages. In nuget the packages you want are called AWSSDK.Core and AWSSDK.S3.&lt;/p&gt;
&lt;p&gt;The using statements you want to use are called Amazon.S3 and Amazon.S3.Transfer, not sure why this doesn’t match nuget, this difference caught me out a couple of times.&lt;/p&gt;
&lt;p&gt;Now to the code that uploads files&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-c#" data-lang="c#"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AmazonS3Client AWSclient = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; AmazonS3Client(accessKeyID, secretAccessKeyID, Amazon.RegionEndpoint.EUWest1);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TransferUtility fileTransferUtility = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; TransferUtility(AWSclient);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; (FileStream streamWriter = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; FileStream(path, FileMode.Open))
&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; TransferUtilityUploadRequest fileTransferUtilityRequest = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; TransferUtilityUploadRequest
&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; BucketName = &lt;span style="color:#e6db74"&gt;&amp;#34;flawlessimages&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; InputStream = streamWriter,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Key = fileName
&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; fileTransferUtility.Upload(fileTransferUtilityRequest);
&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;Lets break it down and look at what it does.&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-c#" data-lang="c#"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AmazonS3Client AWSclient = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; AmazonS3Client(accessKeyID, secretAccessKeyID, Amazon.RegionEndpoint.EUWest1);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates an instance of AmazonS3Client, we are passing the Access Key and Secret Access Key both of which can be found from your Amazon S3 account My Security Credentials section. Amazon.RegionEndpoint.EUWest1 specifies the amazon data centres that your bucket is located in.&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-c#" data-lang="c#"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TransferUtility fileTransferUtility = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; TransferUtility(AWSclient);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates an instance of TransfterUtility using the AmazonS3Client instance we created in the previous step.&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-c#" data-lang="c#"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; (FileStream streamWriter = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; FileStream(path, FileMode.Open))
&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;This opens up a filestream from a files path and specifies that the file should be opened.&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-c#" data-lang="c#"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TransferUtilityUploadRequest fileTransferUtilityRequest = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; TransferUtilityUploadRequest
&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; BucketName = &lt;span style="color:#e6db74"&gt;&amp;#34;flawlessimages&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; InputStream = streamWriter,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Key = fileName
&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;fileTransferUtility.Upload(fileTransferUtilityRequest);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This last step specifies which bucket to upload to, what input stream to upload and the Key to use. Key is just AWS way of referring to files, more commonly referred to as the filename.&lt;/p&gt;
&lt;p&gt;This is all you need to do to upload a file to your Bucket. The file will be located at &lt;a href="https://s3-eu-west-1.amazonaws.com/[bucketname]/[filename]" target="_blank" rel="noopener noreferrer"&gt;https://s3-eu-west-1.amazonaws.com/[bucketname]/[filename]&lt;/a&gt;
, however by default it will not be downloadable until you set Read permission to everyone, once you do that anyone who has the link will be able to download your file.&lt;/p&gt;
&lt;p&gt;This is the same permission level as any file you have on your webserver, however AWS has a better way.&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-c#" data-lang="c#"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; (s3Client = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; AmazonS3Client(accessKeyID, secretAccessKeyID, Amazon.RegionEndpoint.USEast1))
&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; GetPreSignedUrlRequest request1 = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; GetPreSignedUrlRequest
&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; BucketName = bucketName,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Key = filename,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Expires = DateTime.Now.AddMinutes(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; urlString = s3Client.GetPreSignedURL(request1);
&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;Here we are generating a url to download the file, but we are specifying that it is only valid for 5 minutes. This means that if you share the url it will only work for 5 minutes, after that AWS will give an access denied message.&lt;/p&gt;
&lt;p&gt;This is much better security than you have on a typical web server, and easy to implement, every time a user clicks on a download link you generate a new presigned url and send the download to the browser, as long as this process doesn’t take longer than 5 minutes the user will never know.&lt;/p&gt;</description></item><item><title>Using Azure WebJobs to automate</title><link>https://blog-test.funkysi1701.com/posts/2017/using-azure-webjobs-to-automate-stuff/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 26 Jun 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/using-azure-webjobs-to-automate-stuff/</guid><category term="Automate">Automate</category><category term="Azure">Azure</category><category term="Cron">Cron</category><description>&lt;p&gt;I keep hearing about Azure WebJobs but I have never used them. Time to change this.&lt;/p&gt;
&lt;p&gt;WebJobs are a feature of Azure App Service that can run a script at a specific time. In my case I would like to hit a specific url of my website at the same time every day.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="WebJobs" src="https://blog-test.funkysi1701.com/images/2017/addkeepalivewebjob.png" loading="lazy"
width="313" height="615"
/&gt;
To the right you can see an example of the WebJobs form on the Azure portal that you need to fill in.&lt;/p&gt;
&lt;p&gt;You need to supply a name for your webjob.&lt;/p&gt;
&lt;p&gt;You need to upload the script that will run in my case I used a powershell script. My script consisted of which basically just loads the url specified.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$progressPreference = &lt;span style="color:#e6db74"&gt;&amp;#34;silentlyContinue&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$result = Invoke-WebRequest -Uri (&lt;span style="color:#e6db74"&gt;&amp;#34;https://www.google.com&amp;#34;&lt;/span&gt;) -Method Get -UseBasicParsing;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Type refers to if your job will be triggered or run continuously, I want it to be triggered.&lt;/p&gt;
&lt;p&gt;Triggers refers to if you want it to be scheduled or manual, something that you can run on an ad hoc basis. I of course want scheduled.&lt;/p&gt;
&lt;p&gt;If you are familiar with the linux CRON then the next box will make sense to you for everyone else I will try and make sense of it. The box consists of 6 numbers which can either have a value or a *. The numbers correspond to the following {second} {minute} {hour} {day} {month} {day of the week}.&lt;/p&gt;
&lt;p&gt;A hourly job would be expressed as 0 0 * * * *, ie every day of week, every month, every day, every hour and only when minute and second equals zero. For more help with this check out the &lt;a href="https://docs.microsoft.com/en-us/azure/app-service-web/web-sites-create-web-jobs#CreateScheduledCRON" target="_blank" rel="noopener noreferrer"&gt;MSDN docs&lt;/a&gt;
about it. I want to use 0 30 21 * * * to run daily at 9.30pm.&lt;/p&gt;
&lt;p&gt;That’s it everything setup, now time to wait and see if it works.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Oh no!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It failed to run at the specified time.&lt;/p&gt;
&lt;p&gt;The reason for this is the scheduler requires the feature Always On to be turned on which is not available in the free App Service. Before you reach for your wallets, I found a solution on this &lt;a href="https://tomssl.com/2016/12/20/how-to-get-azure-webjobs-to-run-indefinitely-for-free/" target="_blank" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;
that allows them to run on the free tier.&lt;/p&gt;
&lt;p&gt;The thinking behind this solution is you need to keep the website alive throughout the day so Tom has created a script that does this. His script can be found on his blog or on his &lt;a href="https://github.com/TomChantler/Self-KeepAlive" target="_blank" rel="noopener noreferrer"&gt;github page&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Set this script up to run every 5 minutes (0 */5 * * * *) like the example above.&lt;/p&gt;
&lt;p&gt;The nextthing you need to do is create a Custom connection string in the Application Settings blade called SecretThing. Tom’s script references this to access the website and keep it alive. The password you need to put in SecretThing can be found in you publish profile (downloaded from the Overview blade in the Azure portal). For more details and a better explanation check out &lt;a href="https://tomssl.com/2016/12/20/how-to-get-azure-webjobs-to-run-indefinitely-for-free/" target="_blank" rel="noopener noreferrer"&gt;Tom’s blog&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;One last thing to mention about WebJobs is that you can see details about when they have run at https://[YourWebAppName].scm.azurewebsites.net/azurejobs/#/jobs and this can be a great place to help debug your scripts.&lt;/p&gt;</description></item><item><title>Fiddler and APIs</title><link>https://blog-test.funkysi1701.com/posts/2017/fiddler-and-apis/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 19 Jun 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/fiddler-and-apis/</guid><category term=""/><category term=""/><description>&lt;p&gt;A while ago I blogged about &lt;a href="https://www.funkysi1701.com/posts/2017/automation-promotion/" target="_blank" rel="noopener noreferrer"&gt;promoting&lt;/a&gt;
my blog with Buffer. At the time I made use of the nuget package &lt;a href="https://www.nuget.org/packages/BufferAPI/" target="_blank" rel="noopener noreferrer"&gt;BufferAPI&lt;/a&gt;
but lets look at some improvements I can make.&lt;/p&gt;
&lt;p&gt;The BufferAPI package worked great from my console app, but when I tried to use it from a Controller in an MVC app I never got it to work. Lets look at the API docs and see if I can rewrite it.&lt;/p&gt;
&lt;p&gt;There are two main types of API calls GET which gets data from the server and POST which posts data to the server. These come from the types of HTTP requests.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Alt Text" src="https://blog-test.funkysi1701.com/images/2017/6wozrfdoqvtjaoxs7j1v.jpg" loading="lazy"
width="638" height="359"
/&gt;
&lt;/p&gt;
&lt;p&gt;I quickly figured out how to use the GET API call to authenticate using &lt;a href="https://api.bufferapp.com/1/profiles.json?access_token=XXXX" target="_blank" rel="noopener noreferrer"&gt;https://api.bufferapp.com/1/profiles.json?access_token=XXXX&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;However POST was defeating me. That was until I remembered &lt;a href="https://www.telerik.com/fiddler" target="_blank" rel="noopener noreferrer"&gt;Fiddler&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;I had heard Troy Hunt (and others) talk of using Fiddler to examine what data is being passed among websites. Troy uses it to do a man in the middle test to see what information can be stolen.&lt;/p&gt;
&lt;p&gt;It is really easy to setup, install Fiddler, click yes to a few security warnings and you can see what information is being passed from your code to remote APIs.&lt;/p&gt;
&lt;p&gt;Once I had Fiddler installed I could compare what information is being passed between a successful API call using the BufferAPI nuget package and an unsuccessful API call using my code.&lt;/p&gt;
&lt;p&gt;Fiddler also showed that passing my authentication token in a POST request is much better. Despite both GET and POST being encrypted when using HTTPS, anything at either end that logs URLs will have a log of your username and password.&lt;/p&gt;
&lt;p&gt;If you have not tried Fiddler, give it a try especially if you are doing things with API calls.&lt;/p&gt;</description></item><item><title>Add Power BI data to a webpage</title><link>https://blog-test.funkysi1701.com/posts/2017/how-do-i-add-power-bi-data-to-a-webpage/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 12 Jun 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/how-do-i-add-power-bi-data-to-a-webpage/</guid><category term="PowerBI">PowerBI</category><category term=""/><description>&lt;p&gt;Last week I talked about &lt;a href="https://www.funkysi1701.com/posts/2017/businessintelligence/" target="_blank" rel="noopener noreferrer"&gt;Power BI&lt;/a&gt;
, what it is and some of the different services you can use with it. This week lets add some of that data to a simple web page.&lt;/p&gt;
&lt;p&gt;For this example I am going to add the google analytics data from this website to this page.&lt;/p&gt;
&lt;p&gt;First login to your Power BI &lt;a href="https://app.powerbi.com/" target="_blank" rel="noopener noreferrer"&gt;https://app.powerbi.com/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Click the get data link at the bottom left.&lt;/p&gt;
&lt;p&gt;Click My Organisation to bring up the app search box.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Alt Text" src="https://blog-test.funkysi1701.com/images/2017/46c1lyxy053xcq66fowf.jpg" loading="lazy"
width="768" height="406"
/&gt;
&lt;/p&gt;
&lt;p&gt;Click the Apps tab and search for “google” in the search box, you should then see Google Analytics, click into this and then click the get it now button.&lt;/p&gt;
&lt;p&gt;Log into your google account. If you have multiple google accounts I found it worked best to sign out of all of them or run this in an incognito window.&lt;/p&gt;
&lt;p&gt;Once you are signed in you should see a list of the different google analytics data you have, select the one you want to use and click import.&lt;/p&gt;
&lt;p&gt;Power BI will then go away and start loading the data.&lt;/p&gt;
&lt;p&gt;Once loaded go to Reports and select the Google Analytics that has been loaded. If you have more than one, it is a good idea to rename each one eg Corporate Site Google Analytics, Blog Google Analytics so you won’t get mixed up.&lt;/p&gt;
&lt;p&gt;In the file menu select Publish to web and agree that you are OK for this to be made public.&lt;/p&gt;
&lt;p&gt;You will then be given a piece of HTML code that starts with &amp;lt;iframe copy this onto your web page. Reload your webpage and you should see something similar to mine below.&lt;/p&gt;
&lt;p&gt;It should be noted that while you can but the webpage containing the iframe behind a login page, the data could still be accessed if you knew the url contained within the iframe, this is why the link can be emailed and continue to work.&lt;/p&gt;</description></item><item><title>What is Business Intelligence here?</title><link>https://blog-test.funkysi1701.com/posts/2017/businessintelligence/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 05 Jun 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/businessintelligence/</guid><category term="ApplicationInsights">ApplicationInsights</category><category term="BusinessIntelligence">BusinessIntelligence</category><category term="SQL">SQL</category><description>&lt;p&gt;The term &lt;strong&gt;Business Intelligence (BI)&lt;/strong&gt; refers to technologies, applications and practices for the collection, integration, analysis, and presentation of business information. The purpose of Business Intelligence is to support better business decision making. Essentially, Business Intelligence systems are data-driven Decision Support Systems (DSS). Business Intelligence is sometimes used interchangeably with briefing books, report and query tools and executive information systems.&lt;/p&gt;
&lt;h2 id="what-is-power-bi"&gt;What is Power BI?&lt;a class="anchor ms-1" href="#what-is-power-bi" aria-label="Permalink: What is Power BI?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Power BI&lt;/strong&gt; is a business analytics service provided by Microsoft. It provides interactive visualisations with self-service business intelligence capabilities, where end users can create reports and dashboards by themselves, without having to depend on any information technology staff or database administrator.&lt;/p&gt;
&lt;p&gt;Microsoft describe it as follows: &lt;strong&gt;Power BI&lt;/strong&gt; is a suite of business analytics tools that deliver insights throughout your organisation. Connect to hundreds of data sources, simplify data prep, and drive ad hoc analysis. Produce beautiful reports, then publish them for your organisation to consume on the web and across mobile devices. Everyone can create personalised dashboards with a unique, 360-degree view of their business. And scale across the enterprise, with governance and security built-in.&lt;/p&gt;
&lt;h2 id="what-can-you-do-with-it"&gt;What can you do with it?&lt;a class="anchor ms-1" href="#what-can-you-do-with-it" aria-label="Permalink: What can you do with it?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the first thing you can do with Power Bi is connect some of the apps that you use.&lt;/p&gt;
&lt;p&gt;To sign up to use Power BI go to the &lt;a href="https://www.microsoft.com/en-us/power-platform/products/power-bi/" target="_blank" rel="noopener noreferrer"&gt;Power BI website&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Once you are signed in click the get data link in the bottom left corner and browse through the apps you can use.&lt;/p&gt;
&lt;p&gt;If your website uses google analytics you can connect it up to Power BI and see some cool analytics. The below map was generated from some google analytics data, you can see that this website has had users across the globe, with UK and USA getting a lot of hits.
&lt;img class="img-fluid" alt="Business Intelligence from Google Analytics" src="https://blog-test.funkysi1701.com/images/2017/Capture.jpg" loading="lazy"
width="1189" height="627"
/&gt;
&lt;/p&gt;
&lt;p&gt;Another thing you can do is connect Azure Application Insights. This provides some similar data to google analytics about who is visiting your site.&lt;/p&gt;
&lt;p&gt;If your code is hosted in Visual Studio Team Services you can get some cool analytics from your commit history.
&lt;img class="img-fluid" alt="Business Intelligence from VSTS" src="https://blog-test.funkysi1701.com/images/2017/Capture-1.jpg" loading="lazy"
width="1299" height="348"
/&gt;
&lt;/p&gt;
&lt;p&gt;There is a huge long list of apps you can connect to power BI so you can start getting all sorts of analysis very easily. I am hopefully going to talk another time about getting custom data into Power BI.&lt;/p&gt;</description></item><item><title>Have I Been Pwned?</title><link>https://blog-test.funkysi1701.com/posts/2017/have-i-been-pwned/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 29 May 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/have-i-been-pwned/</guid><category term="Pwned">Pwned</category><category term="DataBreach">DataBreach</category><category term="Security">Security</category><category term="TroyHunt">TroyHunt</category><description>&lt;p&gt;Have you heard of the website &lt;a href="https://haveibeenpwned.com" target="_blank" rel="noopener noreferrer"&gt;https://haveibeenpwned.com&lt;/a&gt;
?&lt;/p&gt;
&lt;p&gt;Well you should have. Have I Been Pwned is a website created by security expert Troy Hunt that keeps track of data breaches and allows you to search and find ones that affect you. As I write this &lt;a href="https://www.troyhunt.com/" target="_blank" rel="noopener noreferrer"&gt;Troy Hunt&lt;/a&gt;
has tracked 3,752,984,562 pwned accounts from 216 pwned websites.&lt;/p&gt;
&lt;h2 id="what-does-pwned-mean"&gt;What does “pwned” mean?&lt;a class="anchor ms-1" href="#what-does-pwned-mean" aria-label="Permalink: What does “pwned” mean?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;pwn means to compromise or control, specifically another computer (server or PC), website, gateway device, or application. (as defined on wikipedia)&lt;/p&gt;
&lt;p&gt;Originally, pwn and its variants were pronounced /ˈoʊn/ in the same way as the verb own, the tail of the p being “silent”.&lt;/p&gt;
&lt;p&gt;In terms of this site Troy Hunt defines it as:&lt;/p&gt;
&lt;p&gt;&lt;quote&gt;A &amp;ldquo;breach&amp;rdquo; is an incident where a hacker illegally obtains data from a vulnerable system, usually by exploiting weaknesses in the software. All the data in the site comes from website breaches which have been made publicly available.&lt;/quote&gt;&lt;/p&gt;
&lt;h2 id="what-can-i-do"&gt;What can I do?&lt;a class="anchor ms-1" href="#what-can-i-do" aria-label="Permalink: What can I do?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As an individual you can search for your email address in Have I Been Pwned, I am in 7 data breaches.&lt;/p&gt;
&lt;p&gt;As a person responsible for an email domain you can search and find which of your users are in a data breach.&lt;/p&gt;
&lt;p&gt;You can also sign up to get notified of any future data breaches you might get caught up in.&lt;/p&gt;
&lt;p&gt;If you are in a data breach change your password. If you use the same password across multiple sites or services change them as well. Consider using a &lt;a href="https://www.troyhunt.com/only-secure-password-is-one-you-cant/" target="_blank" rel="noopener noreferrer"&gt;password manager&lt;/a&gt;
so you can have unique complex passwords for every services you use and not have to worry about forgetting them.&lt;/p&gt;
&lt;p&gt;If you look after a website or service then follow Troy Hunt. Think about security, is your site vulnerable to SQL injection, do you store passwords with reversible encryption?&lt;/p&gt;
&lt;h2 id="how-worried-should-i-be"&gt;How worried should I be?&lt;a class="anchor ms-1" href="#how-worried-should-i-be" aria-label="Permalink: How worried should I be?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Data breaches are happening more and more often. Its not showing any sign of slowing down, in fact I expect there to be lots more in the years to come. However there are things you can do to mitigate the damage of being in a breach.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use a password manager&lt;/li&gt;
&lt;li&gt;Don’t share passwords between sites&lt;/li&gt;
&lt;li&gt;Regularly change your passwords&lt;/li&gt;
&lt;li&gt;Think of passwords as pass phrases and include spaces between the different words&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consider what information a company has about you. How worried would you be if this became public knowledge? Consider if you want this online, weigh up the benefits etc&lt;/p&gt;</description></item><item><title>Star Trek Discovery trailer thoughts</title><link>https://blog-test.funkysi1701.com/posts/2017/star-trek-discovery/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 22 May 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/star-trek-discovery/</guid><category term="StarTrek">StarTrek</category><category term="Discovery">Discovery</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2017/DAD0hTKUAAAUkTP.jpg"/><description>&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/UoV3kc05Nwc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;I am really excited a new Star Trek Discovery trailer has just been released, if you haven’t seen it yet, watch it now.&lt;/p&gt;
&lt;p&gt;The rumour mill has been going crazy about Star Trek Discovery but now we have a trailer with actual footage to analyse. In my opinion all the concerns about changes in the production team have gone out the window, this looks to be a polished Star Trek show that can sit alongside our favourites.&lt;/p&gt;
&lt;h2 id="the-ship"&gt;The Ship&lt;a class="anchor ms-1" href="#the-ship" aria-label="Permalink: The Ship"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When images first surfaced of the ship I wasn’t keen, however all the shots of the ship look great. I assume this must be the USS Discovery, although it is hard to tell anything from a two minute advert.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="USS Discovery from the Star Trek Discovery trailer" src="https://blog-test.funkysi1701.com/images/2017/DAD0hTKUAAAUkTP.jpg" loading="lazy"
width="1199" height="663"
/&gt;
&lt;/p&gt;
&lt;h2 id="the-bridge"&gt;The Bridge&lt;a class="anchor ms-1" href="#the-bridge" aria-label="Permalink: The Bridge"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Bridge looks recognisable as a Star Trek bridge, but also looks fresh and new. I think it feels very JJ Verse. I like it.&lt;/p&gt;
&lt;h2 id="the-uniforms"&gt;The Uniforms&lt;a class="anchor ms-1" href="#the-uniforms" aria-label="Permalink: The Uniforms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The uniforms look like a mid step between what we saw on Enterprise and what we know as the Classic Trek look. I can’t see any Blue, Red, Gold to signify departments, but it looked like Gold and Silver could well signify something. Really hard to tell at this stage, but I like what I can see.&lt;/p&gt;
&lt;h2 id="characters"&gt;Characters&lt;a class="anchor ms-1" href="#characters" aria-label="Permalink: Characters"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The show feels like it is going to be gritty and real. With characters you can really get behind. I liked what I saw of the captain and lead character. The alien character intrigued me, hopefully his line about death will be explored. It feels like there is a strong link between Vulcans and Sarek with the shows lead (played by Sonequa Martin-Green) Not sure how I feel about this yet, depends on what they do with it. I don’t want them to just redo what they have done with Spock, but again lets wait and see.&lt;/p&gt;
&lt;h2 id="klingons"&gt;Klingons&lt;a class="anchor ms-1" href="#klingons" aria-label="Permalink: Klingons"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OK I am not sure I like the strong emphasis on the Klingons. I think we have spent a lot of time learning about Klingons, so when I heard the casting news about Klingons I was not excited. The Klingons also have a new look, which doesn’t bother me that much as the Klingons have changed their look before. But lets wait and see what happens.&lt;/p&gt;
&lt;h2 id="star-trek-is-back"&gt;Star Trek is back&lt;a class="anchor ms-1" href="#star-trek-is-back" aria-label="Permalink: Star Trek is back"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After over a decade with no Star Trek on TV, it is finally coming back. I am beyond excited about this. There are lots of things I want from this new show but this advert has definitely rekindled my excitement and hope that we are going to get something good.&lt;/p&gt;</description></item><item><title>Windows Update – don’t turn it off!</title><link>https://blog-test.funkysi1701.com/posts/2017/windows-update-dont-turn-off/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 15 May 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/windows-update-dont-turn-off/</guid><category term="Windows">Windows</category><category term="Update">Update</category><category term="ITAdmin">ITAdmin</category><description>&lt;p&gt;No blog post this week. However why not check out Troy Hunts blog article about &lt;a href="https://www.troyhunt.com/dont-tell-people-to-turn-off-windows-update-just-dont/" target="_blank" rel="noopener noreferrer"&gt;Windows Update&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Windows Update settings screen showing active updates" src="https://blog-test.funkysi1701.com/images/2017/ximage7.png.pagespeed.gpjpjwpjwsjsrjrprwricpmd.ic_.OmA4sQpZUA.png" loading="lazy"
width="464" height="288"
/&gt;
&lt;/p&gt;
&lt;p&gt;I am probably fairly unique in that I like installing updates whether it be on my phone, my PC or for one of my favourite programs. One of my tasks when I used to work in a sysadmin role was ensuring all windows updates got installed on all servers and client machines. It was a never ending task, as soon as you got almost all updates done, it would be update Tuesday and a new set of updates would be released.&lt;/p&gt;
&lt;p&gt;I can think of a couple of times an update got installed that caused a problem and needed to be rolled back. However I have no way of measuring how often it fixed a problem or improved the security of the OS or other software. If you compare the annoyance of waiting for updates to install against having a computer (or worse a server) be hacked or otherwise compromised I think it is fairly clear what you need to do.&lt;/p&gt;
&lt;p&gt;As someone who works in IT I feel it is my duty to share the importance of keeping your devices updated. Don’t turn automatic updates off or disable it. It is there to help you and keep your computer safe and secure.&lt;/p&gt;</description></item><item><title>HighCharts</title><link>https://blog-test.funkysi1701.com/posts/2017/highcharts/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 08 May 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/highcharts/</guid><category term="HighCharts">HighCharts</category><category term="Graphs">Graphs</category><category term="JavaScript">JavaScript</category><category term="SQL">SQL</category><description>&lt;p&gt;High Charts is a javascript library that allows graphs and charts to easily be added to web pages.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Highcharts line chart showing solar employment growth by sector" src="https://blog-test.funkysi1701.com/images/2017/chart.jpeg" loading="lazy"
width="1200" height="800"
/&gt;
&lt;/p&gt;
&lt;p&gt;A chart like this can easily be added with a few lines of html and javascript.&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-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://code.highcharts.com/highcharts.js&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://code.highcharts.com/modules/exporting.js&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This adds the highcharts library and a container for the chart to be displayed in.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Highcharts&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;chart&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;container&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Solar Employment Growth by Sector, 2010-2016&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;subtitle&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Source: thesolarfoundation.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;yAxis&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Number of Employees&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;legend&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;layout&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;vertical&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;align&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;right&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;verticalAlign&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;middle&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;plotOptions&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;series&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pointStart&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2010&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;series&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Installation&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;43934&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;52503&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;57177&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;69658&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;97031&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;119931&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;137133&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;154175&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Manufacturing&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;24916&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;24064&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;29742&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;29851&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;32490&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;30282&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;38121&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;40434&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Sales &amp;amp; Distribution&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;11744&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;17722&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;16005&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;19771&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20185&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;24377&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;32147&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;39387&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Project Development&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;7988&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12169&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;15112&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;22452&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;34400&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;34227&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Other&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;12908&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5948&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8105&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;11248&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8989&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;11816&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;18274&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;18111&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This adds the data and sets up various options for the charts. More details about the different charts and options you can set can be found at &lt;a href="https://www.highcharts.com" target="_blank" rel="noopener noreferrer"&gt;https://www.highcharts.com&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;I am quite a fan of the different gauges that you can put on your site, as you can add a bit of animation and make the needles bounce around. &lt;a href="https://www.highcharts.com/demo/gauge-solid" target="_blank" rel="noopener noreferrer"&gt;https://www.highcharts.com/demo/gauge-solid&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Highcharts solid gauge chart example" src="https://blog-test.funkysi1701.com/images/2017/chart-1.jpeg" loading="lazy"
width="1200" height="400"
/&gt;
&lt;/p&gt;
&lt;p&gt;As most of the data I deal with lives in a SQL Server database, I have been spending quite a bit of time writing Stored Procedures and functions to mould the data so I can easily pass data from the database to javascript.&lt;/p&gt;
&lt;p&gt;Highcharts are very flexible with lots of different options that allow you to display charts of almost any data you have, these charts are also exportable as PNG, JPEG, CSVs etc&lt;/p&gt;</description></item><item><title>Office Move</title><link>https://blog-test.funkysi1701.com/posts/2017/office-move/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 May 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/office-move/</guid><category term="ITAdmin">ITAdmin</category><category term="Routers">Routers</category><category term="Servers">Servers</category><category term="OfficeMove">OfficeMove</category><description>&lt;p&gt;
&lt;img class="img-fluid" alt="New Rack" src="https://blog-test.funkysi1701.com/images/2017/20170422_191127-e1493403982560-169x300.jpg" loading="lazy"
width="169" height="300"
/&gt;
For the past few weeks my software developing has been taking a back seat as I planned and coordinated the IT requirements of an office move.&lt;/p&gt;
&lt;p&gt;The company I work for has been working out of a converted barn, but as the company has grown we have outgrown the building and for quite a while it has been a real squeeze to get everyone in. We now have a shiny new offices with plenty of room for growth.&lt;/p&gt;
&lt;p&gt;It was at the start of the year when I first started getting involved with the new office. At that time building work was about to begin. The office had concrete floors so in order to get network and power points in the floor, channels would have to be cut into the concrete for the floor boxes and cable runs.&lt;/p&gt;
&lt;p&gt;At the old office our servers were in a cabinet in the corner of the room which meant they could be quite loud especially when the fans were going full pelt. Our American owners were supplying brand new IT equipment and we would have a dedicated server room.&lt;/p&gt;
&lt;p&gt;Soon a weekly conference call was setup so we could coordinate with the IT people in America and the various different contractors that would help deliver our new office.&lt;/p&gt;
&lt;p&gt;One thing I was particularly proud of was YDS. York Data Services (YDS) is an ISP I have worked with in the past at a previous job and I was able to continue my relationship with them and they were contacted and became our primary internet supplier.&lt;/p&gt;
&lt;p&gt;Unfortunately most ISPs have to deal with BTOpenreach who have a bit of a monopoly on getting phone lines or leased lines installed. The initial estimate we were given was two weeks after we were due to move in. It was looking like we would move in and two weeks later we would get an internet connection. We were in the process of getting quotes for a temporary internet connection when BT contacted us and could get us connected up.
&lt;img class="img-fluid" alt="New Office" src="https://blog-test.funkysi1701.com/images/2017/18121045_1302238519862436_8711390769620542649_o.jpg" loading="lazy"
width="2048" height="1536"
/&gt;
&lt;/p&gt;
&lt;p&gt;Soon afterwards a huge cabinet and two pallets full of equipment was delivered. Two days later a team was dispatched to rack everything up. On the rack we had the following equipment: 4 x UPS, 4 x Network Switches, 2 x Routers (for 2 x Leased Lines from different providers, the secondary connection has not been installed yet), 2 x Palo Alto Firewall devices, 2 x New Servers.&lt;/p&gt;
&lt;p&gt;Just prior to our move we had a rack full of equipment but no patch cables, nothing connected up and I was beginning to get concerned that we would not be ready in time.&lt;/p&gt;
&lt;p&gt;Thankfully a team was dispatched to help out over the weekend of the move, with the patch cables being delivered only hours beforehand. I worked closely with them and we worked late into the night. By the end of the Friday night our domain controller had been moved and its IP address updated. DHCP scopes had been setup for the new network. Once that was done we could get the WiFi points connected up (These had already been fitted to the ceiling).&lt;/p&gt;
&lt;p&gt;The following day we moved our existing servers and updated their IP addresses and got everything patched up. Furniture started arriving so desks could start being setup and phones connected up. Everything was slotting into place, and for the first time our new office was starting to look like an office.&lt;/p&gt;
&lt;p&gt;By the time it got to Monday the only problem was the phone number had not transferred as requested (something else to blame on BT) All staff could either connect via an Ethernet cable or connect to our brand new WiFi network and had access to all the IT services they had at the old office. Another minor issue was the NAS we used for backups had to be reset as it couldn’t communicate with the domain so no one could login, luckily this didn’t affect the data on it.&lt;/p&gt;
&lt;p&gt;From my perspective the move was a massive success considering how complex and how many different people had been involved.&lt;/p&gt;</description></item><item><title>GitHub history</title><link>https://blog-test.funkysi1701.com/posts/2017/github-history/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 24 Apr 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/github-history/</guid><category term="Git">Git</category><category term="GitHub">GitHub</category><category term="Code">Code</category><description>&lt;p&gt;I created my GitHub account in August 2010, lets look at what I have done with it.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="GitHub contribution graph for 2010" src="https://blog-test.funkysi1701.com/images/2017/git10.jpg" loading="lazy"
width="1471" height="331"
/&gt;
&lt;/p&gt;
&lt;p&gt;In 2010 I started by committing the code for an old php website I had created. Then in December I committed some other php sites.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="GitHub contribution graph showing daily commits between late 2010 and 2011" src="https://blog-test.funkysi1701.com/images/2017/git11.jpg" loading="lazy"
width="1484" height="331"
/&gt;
&lt;/p&gt;
&lt;p&gt;Between 12 December 2010 and 29 September 2011 I must have created some automated process which is why there is a commit every day. Looking at the diff it appears to be related to tracking visitors to a site. I assume back then I hadn’t heard of the .gitignore file!&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="GitHub contribution graph for 2014" src="https://blog-test.funkysi1701.com/images/2017/git14.jpg" loading="lazy"
width="1479" height="336"
/&gt;
&lt;/p&gt;
&lt;p&gt;Nothing for a few years until 2014, when I started compiling a code samples collection, this is bits of code that I want to show off, I have added to this since 2015 so I really should go back to this as my skills have developed a bit since then.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="GitHub contribution graph for 2015" src="https://blog-test.funkysi1701.com/images/2017/git15.jpg" loading="lazy"
width="1471" height="331"
/&gt;
&lt;/p&gt;
&lt;p&gt;In 2015 I really started to think of myself as a developer, I added repositories for Raspberry Pi, and a few C# ideas I had. I ended the year taking part in Advent of Code&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="GitHub contribution graph for 2016" src="https://blog-test.funkysi1701.com/images/2017/git16.jpg" loading="lazy"
width="1470" height="332"
/&gt;
&lt;/p&gt;
&lt;p&gt;What did I do last year? Well I started going to York Code Dojo and this meant lots of forks from their code examples and also my first pull request. I also did a fair bit of looking at other repositories trying to find a good open source project to contribute to, still not found one for me yet. Lastly I ended 2016 with a bit of Advent of Code.&lt;/p&gt;
&lt;p&gt;Not sure how enthralling a blog post this is, but fascinating to see the different commit histories.&lt;/p&gt;</description></item><item><title>Automating promotion of my blog</title><link>https://blog-test.funkysi1701.com/posts/2017/automation-promotion/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 17 Apr 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/automation-promotion/</guid><category term="Buffer">Buffer</category><category term="Blogging">Blogging</category><category term="XML">XML</category><category term="RSS">RSS</category><description>&lt;p&gt;I would like to automate the promotion of this blog. Currently to promote this blog on social media I use a few different services.
&lt;img class="img-fluid" alt="Buffer social media scheduling hub illustration" src="https://blog-test.funkysi1701.com/images/2017/img-buffer-illustration-hub-960@2x.png" loading="lazy"
width="1780" height="794"
/&gt;
&lt;/p&gt;
&lt;p&gt;Buffer (&lt;a href="https://buffer.com" target="_blank" rel="noopener noreferrer"&gt;buffer.com&lt;/a&gt;
) is a service that allows you to schedule updates to the main social media channels (Facebook, Twitter, LinkedIn and Google+)&lt;/p&gt;
&lt;p&gt;IFTTT or If This Then That (&lt;a href="https://ifttt.com" target="_blank" rel="noopener noreferrer"&gt;ifttt.com&lt;/a&gt;
) is a service that allows you to connect different online services. You can send an email when a specific event occurs in your calendar for example.&lt;/p&gt;
&lt;p&gt;I have been using a combination of these services to share to social media some of my past blog posts. I then add to my calendar details of my blog posts. Then I use IFTTT to add the event to Buffer, and then buffer tweets on a schedule.&lt;/p&gt;
&lt;p&gt;This works great however it is a manual process to add my posts to my calendar. I have been using a spreadsheet to help me generate an ics calendar file which I import into my google calendar. There must be a better way of doing this.&lt;/p&gt;
&lt;p&gt;I have written some code that reads the RSS feed of my blog and then shares that to Buffer using the Buffer API. The code I am creating is far from finished however I am trying to use the concepts of clean code to make it as flexible as possible.&lt;/p&gt;
&lt;p&gt;I have an interface called ISocial which my buffer code implements, but it would be easy to add a class that implements the same interface but uses the twitter or facebook APIs. My code reads from a specific WordPress RSS feed, but it should be easy enough to adapt to read from a SQL database or any other data source.&lt;/p&gt;
&lt;p&gt;I am currently unsure what kind of interface to use for this application. I could create a web page that controls the functionality, or maybe just a windows application, or maybe both of these are complicating things and all I need is just a console application that could be added as a scheduled task.&lt;/p&gt;</description></item><item><title>Blame</title><link>https://blog-test.funkysi1701.com/posts/2017/blame/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 10 Apr 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/blame/</guid><category term="Blame">Blame</category><category term="Culture">Culture</category><category term="DevOps">DevOps</category><category term="SoftSkills">SoftSkills</category><description>&lt;p&gt;I recently came home from a busy day of work to my wife blaming me for allowing our 18 month old son to reach some paint and get it all over the carpet. She was concentrating on the fact that he could reach the paint not on the fact that she had brilliantly got the paint out of the carpet.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Cartoon illustrating blame shifting between people" src="https://blog-test.funkysi1701.com/images/2017/blame-shifting.jpg" loading="lazy"
width="347" height="346"
/&gt;
&lt;/p&gt;
&lt;p&gt;My instinct on being blamed is to deny it, or start throwing blame back at her. It is possible I put the paint in his reach, it is also possible it was someone else.&lt;/p&gt;
&lt;p&gt;It is very easy to blame someone else. For example, looking through the git history to find out who changed a specific file is only a few clicks.&lt;/p&gt;
&lt;p&gt;But is it ever productive to blame someone? Is it not better to focus our energy on fixing the issue at hand?&lt;/p&gt;
&lt;p&gt;In the world of business it is easy to go from blaming other people until you have a blame culture. When you have a blame culture everyone starts looking out for themselves so it’s not them that gets the blame and productivity will suffer.&lt;/p&gt;
&lt;p&gt;I think it is more important to put in place​ processes to minimise issues happening again. If a deployment causes downtime, don’t ask who’s fault is it and sack them. Instead what can we do to reduce the chance of it happening again?&lt;/p&gt;
&lt;p&gt;As someone who has an interest in DevOps, I often break things and don’t want to get blamed for that, I do want to improve my processes so I am not always breaking the same things.&lt;/p&gt;
&lt;p&gt;What do you think about Blame? Is what can we do differently always better than who did this?&lt;/p&gt;</description></item><item><title>Interfaces</title><link>https://blog-test.funkysi1701.com/posts/2017/interfaces/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 27 Mar 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/interfaces/</guid><category term="C-Sharp">C-Sharp</category><category term="Interface">Interface</category><description>&lt;p&gt;I am trying to understand interfaces and when to use them in my code.&lt;/p&gt;
&lt;p&gt;An interface defines a contract and any class that implements that interface agrees to fulfil that contract.&lt;/p&gt;
&lt;p&gt;Lets look at an example as this tends to be how I learn best.&lt;/p&gt;
&lt;p&gt;Most applications require some sort of data to work from so lets start by defining IData which can load data.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;IData&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Blog LoadData(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; Connectionstring);
&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;My interface defines one method LoadData and outputs an object called Blog (I will explain why in a minute)&lt;/p&gt;
&lt;p&gt;A common data source is a SQL database so we could define a SQL class that implements IData.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SQL&lt;/span&gt; : IData
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Blog LoadData(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; Connectionstring)
&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; Blog blog = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Blog();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; (SqlConnection con = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; SqlConnection(Connectionstring))
&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; con.Open();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//etc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We could also get data from an RSS feed of a blog (hence why I called the object Blog earlier)&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;XML&lt;/span&gt; : IData
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Blog LoadData(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; Connectionstring)
&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; XmlDocument myXmlDocument = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; XmlDocument();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myXmlDocument.Load(Connectionstring);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Blog blog = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Blog();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (XmlNode RootNode &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; myXmlDocument.ChildNodes)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//etc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both classes implement IData and have a method called LoadData which has a string parameter and outputs a blog object. The string parameter is either a connection string to a SQL database or the URL of the rss feed. Not sure if there is a better way of doing this bit, maybe the name of the string needs making more generic.&lt;/p&gt;
&lt;p&gt;Now we have some classes that implement an interface what can we do with them. Lets write a class called GetData which gets data but doesn’t care if it comes form the rss feed or a SQL database.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GetData&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; IData _repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; GetData(IData repo)
&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; _repo = repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Blog LoadData(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; Connectionstring)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; original = _repo.LoadData(Connectionstring);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; original;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we call GetData we can either pass in XML or SQL as the class is not tied to either implementation. We could even write other classes that implement IData for testing purposes.&lt;/p&gt;
&lt;p&gt;My full code can be found on &lt;a href="https://github.com/funkysi1701/InterfaceExample" target="_blank" rel="noopener noreferrer"&gt;github&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;The advantages of writing code in this way include code that is easier to extend, easier to test and easier to maintain. This is only the start of my understanding and I am sure this is going to be a topic I come back to in the next few weeks.&lt;/p&gt;</description></item><item><title>SOLID and other programming terms</title><link>https://blog-test.funkysi1701.com/posts/2017/solid-programming-terms/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 20 Mar 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/solid-programming-terms/</guid><category term="DesignPatterns">DesignPatterns</category><category term="DRY">DRY</category><category term="MVC">MVC</category><category term="SOLID">SOLID</category><description>&lt;p&gt;This week I have been looking at improving my understanding of a few programming terms, like SOLID and I will try and define them so I can look back here when I get confused.&lt;/p&gt;
&lt;h2 id="mvc"&gt;MVC&lt;a class="anchor ms-1" href="#mvc" aria-label="Permalink: MVC"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have previously blogged about &lt;a href="https://www.funkysi1701.com/posts/2016/model-view-controller-mvc/" target="_blank" rel="noopener noreferrer"&gt;MVC&lt;/a&gt;
, but my understanding was not 100% correct so I will refine this here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Model&lt;/strong&gt; – Now this is where my understanding was not quite correct. I thought the model was the actual source data, eg an XML file, SQL database etc. The model is the business logic so this is a processed version of the source data. MVC does not care where data is stored it can be flat files, SQL, XML or anything really.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View&lt;/strong&gt; – This displays data to the user and typically is the HTML/CSS markup. Only display related logic would get included in the view.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controller&lt;/strong&gt; – This is another place I had got a bit confused. I had thought all the logic lived here. This is incorrect controllers are only concerned with getting data between Model and View.&lt;/p&gt;
&lt;h2 id="solid"&gt;SOLID&lt;a class="anchor ms-1" href="#solid" aria-label="Permalink: SOLID"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SOLID are five principles of object oriented programming and design.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;S&lt;/strong&gt; is for Single Responsibility Principle. A class or piece of code should be responsible for doing one thing.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Diagram illustrating the Single Responsibility Principle" src="https://blog-test.funkysi1701.com/images/2017/SingleResponsibilityPrinciple2_71060858.jpg" loading="lazy"
width="750" height="600"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O&lt;/strong&gt; is for Open/Closed Principle. Code should be open for extensions but closed for modifications. Often this refers to the way you can implement an interface and add extra functionality.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Diagram illustrating the Open/Closed Principle" src="https://blog-test.funkysi1701.com/images/2017/ocp.jpg" loading="lazy"
width="640" height="513"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;L&lt;/strong&gt; is for Liskov Substitution Principle. Objects in a program can be replaced with subtypes of that object with out changing functionality.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Diagram illustrating the Liskov Substitution Principle" src="https://blog-test.funkysi1701.com/images/2017/LiskovSubtitutionPrinciple_52BB5162.jpg" loading="lazy"
width="750" height="600"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I&lt;/strong&gt; is for Interface Segregation Principle. Large interfaces should be split down into small interfaces so that clients only know about methods that are of interest.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Diagram illustrating the Interface Segregation Principle" src="https://blog-test.funkysi1701.com/images/2017/isp.jpg" loading="lazy"
width="640" height="513"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D&lt;/strong&gt; is for Dependency Inversion Principle. High and Low level modules should depend on abstractions.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Diagram illustrating the Dependency Inversion Principle" src="https://blog-test.funkysi1701.com/images/2017/dip.jpg" loading="lazy"
width="640" height="513"
/&gt;
&lt;/p&gt;
&lt;p&gt;I need to look into SOLID some more but here are some &lt;a href="https://www.codeproject.com/Articles/703634/SOLID-architecture-principles-using-simple-Csharp" target="_blank" rel="noopener noreferrer"&gt;examples&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="dry"&gt;DRY&lt;a class="anchor ms-1" href="#dry" aria-label="Permalink: DRY"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DRY is simply Don’t Repeat Yourself. It is often easy to spot when a function call will help you not have to use the same bit of code in different places. I am often spotting places where I can put this into action.&lt;/p&gt;</description></item><item><title>Test Driven Development or TDD</title><link>https://blog-test.funkysi1701.com/posts/2017/test-driven-development-tdd/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 13 Mar 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/test-driven-development-tdd/</guid><category term="TestDrivenDevelopment">TestDrivenDevelopment</category><category term="Testing">Testing</category><category term="VisualStudio">VisualStudio</category><media:content medium="image" type="image/gif" url="https://blog-test.funkysi1701.com/images/2017/03/tdd_flow.gif"/><description>&lt;p&gt;A few weeks back I attended a talk at &lt;a href="https://www.agileyorkshire.org/event-announcements/tuesfebruary21st-drolivershawtestdrivendevelopmentthemostmisusedterminsoftwaredevelopmentandkeithwilliamsdependenciesinjectionandabstractionforfunandprofit" target="_blank" rel="noopener noreferrer"&gt;Agile Yorkshire&lt;/a&gt;
about Test Driven Development or TDD by Dr Oliver Shaw. I was impressed at how easy Oliver made it look, so as I have never tried it I thought I should give it a try.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Red, Green, Refactor cycle diagram for test driven development" src="https://blog-test.funkysi1701.com/images/2017/tdd_flow.gif" loading="lazy"
width="489" height="511"
/&gt;
&lt;/p&gt;
&lt;p&gt;Test Driven Development or TDD is a way of development which starts with writing a Unit Test. First you write a failing test, then you write the code to make it pass, then you refactor your code. This can be remembered by thinking of &lt;strong&gt;Red, Green, Refactor&lt;/strong&gt;. Red being the failing test, Green being getting the test to pass, and Refactor being the refactoring.&lt;/p&gt;
&lt;p&gt;During the demonstration Oliver used a language called scala and a system that automatically reran all the tests after every change. I code with Visual Studio in C# is there a way I can get my tests to run automatically as well?&lt;/p&gt;
&lt;p&gt;A bit of googling and configuring I can answer this as Yes.&lt;/p&gt;
&lt;p&gt;The nuget package called &lt;a href="https://github.com/codereflection/Giles" target="_blank" rel="noopener noreferrer"&gt;Giles&lt;/a&gt;
is a watcher which will rerun your tests similar to how Oliver did it with his scalar environment. Fans of Buffy the Vampire Slayer will get the joke of why a watcher is called Giles. I couldn’t get this to work with MSTest but works fine with NUnit. There is a powershell script giles.ps1 which you need to run and will update every so often with how many tests have passed or failed. However you may not see this if you are coding in Visual Studio but there is a way to get a notification.&lt;/p&gt;
&lt;p&gt;If you install the application Growl you can get notifications from Giles which pop up and then disappear. So whatever you have on screen you can find out almost instantly if you have broken tests.&lt;/p&gt;
&lt;p&gt;Another thing that I wanted to configure is a way of viewing code coverage and which methods are tested and which aren’t. If you are familiar with VSTS after a build it gives you a percentage score for test coverage. I don’t find this overly useful as it doesn’t tell you what is covered and what isn’t. Also what if you want to use Github, how do you calculate the code coverage then?&lt;/p&gt;
&lt;p&gt;The nuget packages &lt;a href="https://www.nuget.org/packages/OpenCover/" target="_blank" rel="noopener noreferrer"&gt;OpenCover&lt;/a&gt;
and &lt;a href="https://www.nuget.org/packages/ReportGenerator/" target="_blank" rel="noopener noreferrer"&gt;ReportGenerator&lt;/a&gt;
allow a html report of code coverage to be produced. I created a batch script that can be run whenever you require this information.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[path]\OpenCover.Console.exe -target:&amp;#34;[path]\nunit3-console.exe&amp;#34; -targetargs:&amp;#34;[path]\Test.dll&amp;#34; -output:&amp;#34;[path]\coverage.xml&amp;#34; -register:user
[path]\ReportGenerator.exe &amp;#34;-reports:[path]\coverage.xml&amp;#34; &amp;#34;-targetdir:[path]&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The commands are fairly straightforward, the only tricky bit is sorting out all the filepaths to the different programs.&lt;/p&gt;
&lt;p&gt;Now that I have all this plumbing setup time to give TDD a try and see what I can build.&lt;/p&gt;</description></item><item><title>GitHub, Bitbucket, or VSTS compared</title><link>https://blog-test.funkysi1701.com/posts/2017/github-vs-bitbucket-vs-vsts/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 06 Mar 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/github-vs-bitbucket-vs-vsts/</guid><category term="Git">Git</category><category term="Bitbucket">Bitbucket</category><category term="DevOps">DevOps</category><category term="AzureDevOps">AzureDevOps</category><category term="SourceControl">SourceControl</category><description>&lt;p&gt;As a developer using source control and git is bread and butter of what we do. Github is probably the most popular and widely known hosting service for source control but I have also used Bitbucket and Visual Studio Team Services. Lets have a look at each one and what they offer. Note while I have included prices I have only tried out the free versions.&lt;/p&gt;
&lt;h2 id="github"&gt;Github&lt;a class="anchor ms-1" href="#github" aria-label="Permalink: Github"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="GitHub Octocat mascot logo" src="https://blog-test.funkysi1701.com/images/2017/github-octocat.png" loading="lazy"
width="1200" height="630"
/&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;URL: &lt;a href="https://github.com/" target="_blank" rel="noopener noreferrer"&gt;https://github.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Private Repositories: Not Available for free&lt;/li&gt;
&lt;li&gt;Public Repositories: Unlimited&lt;/li&gt;
&lt;li&gt;Team Size: Unlimited&lt;/li&gt;
&lt;li&gt;Prices: $7 per month for unlimited private repositories, $25 per month for 5 users then $9 per month per user&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is probably the most widely used service for hosting code. Over 13 million repositories of code. This is an ideal solution if you want your code to be publicly viewable, but take care not to publish passwords, private keys or your companies trade secrets. Every developer should have a Github account for displaying bits of code they are proud of.&lt;/p&gt;
&lt;p&gt;There are a number of externally built APIs that link into Github for doing extra features, like building, code coverage etc&lt;/p&gt;
&lt;h2 id="bitbucket"&gt;Bitbucket&lt;a class="anchor ms-1" href="#bitbucket" aria-label="Permalink: Bitbucket"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Bitbucket logo" src="https://blog-test.funkysi1701.com/images/2017/d8TRzzL.png" loading="lazy"
width="277" height="277"
/&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;URL: &lt;a href="https://bitbucket.org/" target="_blank" rel="noopener noreferrer"&gt;https://bitbucket.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Private Repositories: Unlimited&lt;/li&gt;
&lt;li&gt;Public Repositories: Unlimited&lt;/li&gt;
&lt;li&gt;Team Size: Less than 5&lt;/li&gt;
&lt;li&gt;Prices: $10 per month for 10 Users, $100 per month for 100 Users, $200 per month for Unlimited Users&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At my last job we used Bitbucket extensively for all our projects. All the code was private so only the team could access it, however before I left we were approaching the 5 user limit (but looking at these prices cost seems very reasonable)&lt;/p&gt;
&lt;h2 id="visual-studio-team-services"&gt;Visual Studio Team Services&lt;a class="anchor ms-1" href="#visual-studio-team-services" aria-label="Permalink: Visual Studio Team Services"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Visual Studio Team Services logo" src="https://blog-test.funkysi1701.com/images/2017/Visual-Studio-Team-Services.png" loading="lazy"
width="960" height="434"
/&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;URL: &lt;a href="https://azure.microsoft.com/services/devops/" target="_blank" rel="noopener noreferrer"&gt;https://azure.microsoft.com/services/devops/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Private Repositories: Unlimited&lt;/li&gt;
&lt;li&gt;Public Repositories: Not Available&lt;/li&gt;
&lt;li&gt;Team Size: Less than 5&lt;/li&gt;
&lt;li&gt;Prices: $30 per month for 10 users, and other features paid for via Azure Invoices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Visual Studio Team Services or VSTS is Microsoft’s version control solution and I have only just started using it, however what I have seen I like. There are lots of options for building your code so VSTS is more than just hosting your code it is verging on a Continuous Integration/Delivery solution. Being a Microsoft product there are numerous links to Azure and it is easy to deploy stuff to that platform.&lt;/p&gt;
&lt;p&gt;All three have options for tracking issues but VSTS have options to add Stakeholder users which would allow none developers to add and keep track of issues and progress with them.&lt;/p&gt;
&lt;p&gt;If I want to run tests, look at code coverage VSTS is probably the solution I would go for, if I want something that is public I would go for Github. What do you think which of these is your favourite?&lt;/p&gt;</description></item><item><title>Learning R</title><link>https://blog-test.funkysi1701.com/posts/2017/learning-r/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 27 Feb 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/learning-r/</guid><category term="ExchangeRates">ExchangeRates</category><category term="R">R</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2017/Exchange-Rate-Calculator.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="R" src="https://blog-test.funkysi1701.com/images/2017/Exchange-Rate-Calculator.jpg" loading="lazy"
width="1024" height="689"
/&gt;
Today I spent some time learning the R language.&lt;/p&gt;
&lt;p&gt;The problem I was trying to solve was to convert local prices of some items into Euros. I had been using a fixed exchange rate for all data, but as exchange rates fluctuate so much this is incorrect.&lt;/p&gt;
&lt;p&gt;My first though was to find a free API that I could query to get the values I wanted. The first API I found didn’t cover all the currencies, the next one I found I burnt through the free allowance in one pass.&lt;/p&gt;
&lt;p&gt;A colleague of mine mentioned using R to solve this, he sent me some links and I set out to write my first piece of R code.&lt;/p&gt;
&lt;p&gt;My finished code can be found on &lt;a href="https://github.com/funkysi1701/ExchangeRate/blob/master/script.R" target="_blank" rel="noopener noreferrer"&gt;github&lt;/a&gt;
and I will attempt to explain some of it.&lt;/p&gt;
&lt;p&gt;R defines functions fairly simply&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-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nameoffunction &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(arg1, arg2)
&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; arg1 &lt;span style="color:#f92672"&gt;*&lt;/span&gt; arg2
&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 have created a function that takes 2 parameters date and currency. I know I have about 10 different currencies that I want to get currencies for and I want to loop through each day so I will need to pass in a date.&lt;/p&gt;
&lt;p&gt;The source of my exchange rate information is the &lt;a href="https://www.xe.com" target="_blank" rel="noopener noreferrer"&gt;www.xe.com&lt;/a&gt;
website, its historical exchange rate page passes currency and date into the query string so I should be able to build up a string containing all the different elements.&lt;/p&gt;
&lt;p&gt;All programming language can concatenate strings and R is no different. R uses paste()&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-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;var &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;paste&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;World&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However R has an annoying feature in this function. I would expect that var in the above example would contain &amp;ldquo;HelloWorld&amp;rdquo;, it doesn’t it contains &amp;ldquo;Hello World&amp;rdquo;. Why it automatically adds a space I don’t know?&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-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;var &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;paste&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;World&amp;#34;&lt;/span&gt;, sep&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I am not entirely sure what all of the code does but I can take a good guess.&lt;/p&gt;
&lt;p&gt;read_html() I would guess loads a html page, html_nodes() finds all the html tags of a certain type on the page, in my case &amp;lt;table&amp;gt;, html_table() reads the first table it finds.&lt;/p&gt;
&lt;p&gt;table1[2] selects the second column, and head() selects a specific number of rows. I want the first row and second column so I combine these two as head(table1[2],1)&lt;/p&gt;
&lt;p&gt;Now that I have found my exchange rate what do I do with it? R can read and write to SQL Server so why not store this info in a SQL lookup table. I can then use this data in a stored procedure when I process my data.&lt;/p&gt;
&lt;p&gt;To query sql you can use sqlQuery(), it has two parameters, a sql connection and a TSQL command (eg a SELECT, INSERT, UPDATE statement)&lt;/p&gt;
&lt;p&gt;I use a while loop to loop through every day between 1st October 2016 and today and look up the exchange rate for each currency.&lt;/p&gt;
&lt;p&gt;For now I am manually running this R script, however there are ways to run R directly from SQL Server which I may well investigate. I could then have a SQL job to run this on a schedule, maybe once a day to get the latest exchange rates. I also would like to do something a bit cleverer like only getting exchange rates for the days that I need them by querying existing database tables.&lt;/p&gt;</description></item><item><title>Side Project – Connect 4</title><link>https://blog-test.funkysi1701.com/posts/2017/side-project-connect-4/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 06 Feb 2017 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2017/side-project-connect-4/</guid><category term="Connect4">Connect4</category><category term="PWA">PWA</category><category term="Website">Website</category><description>&lt;p&gt;Hello?&lt;/p&gt;
&lt;p&gt;You have probably like me almost forgotten about this blog. Life has got in the way over the last few months, but lets see if I can restart my blogging habit.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Connect 4 board game" src="https://blog-test.funkysi1701.com/images/2017/Connect4.png" loading="lazy"
width="639" height="553"
/&gt;
&lt;/p&gt;
&lt;p&gt;In 2017 I want to start a side project for a few reasons. I want to improve my coding skills and look at things I wouldn’t normally during my day job.&lt;/p&gt;
&lt;p&gt;I have been trying to decide what to build. The actual project doesn’t matter too much, it is the techniques I use during build that matters the most. I would like something that I can start off as a windows app and then extend onto the web or mobile apps.&lt;/p&gt;
&lt;p&gt;I started off thinking about a Rubik’s cube app, however my initial coding has lead me to believe it is probably too complex for my first app.&lt;/p&gt;
&lt;p&gt;Last year I spent an evening looking at Connect 4 during a &lt;a href="https://yorkcodedojo.github.io/" target="_blank" rel="noopener noreferrer"&gt;York Code Dojo&lt;/a&gt;
session. I think this should be complex enough that I can code some logic to efficiently solve the game, however not too complex I get defeated before building too much.&lt;/p&gt;
&lt;p&gt;So far I have built a console app that displays via Console.Write() commands, a grid to represent the game, with 0 meaning empty, 1 red and 2 yellow etc. I am currently working on the logic to solve the game, once I have that in a good state I can extend into a winforms app, into a web (MVC most likely) app and finally a mobile app (I have no knowledge about how to do this yet, but something I would like to try one day).&lt;/p&gt;
&lt;p&gt;Over the last few days I listened to .NetRocks where they discussed &lt;a href="https://www.dotnetrocks.com/?show=1396" target="_blank" rel="noopener noreferrer"&gt;Progressive Web Apps&lt;/a&gt;
. This sounds like a great challenge for me to aim for. A progressive Web App is a website that automatically detects various properties to give you an app that runs well whatever the state of your internet connection and whatever browser you are in.&lt;/p&gt;
&lt;p&gt;I have lots to learn but I can split it down into small sections and I can build something that demonstrates some of my skills.&lt;/p&gt;</description></item><item><title>What should be in Source Control?</title><link>https://blog-test.funkysi1701.com/posts/2016/what-should-be-in-source-control/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 24 Nov 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/what-should-be-in-source-control/</guid><category term="Git">Git</category><category term="SourceCode">SourceCode</category><category term="SourceControl">SourceControl</category><category term="C-Sharp">C-Sharp</category><description>&lt;p&gt;I am currently working on source code that is over 5Gb in size. This is mostly due to a poorly thought out folder structure, there are code files, images and Excel files all jumbled together. I think a clear distinction should be made between source code and data.&lt;/p&gt;
&lt;h2 id="source-code"&gt;Source Code&lt;a class="anchor ms-1" href="#source-code" aria-label="Permalink: Source Code"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I will define source code as anything that is written in order to compile and run the project. If it is a webpage it will be all the HTML, CSS and Javascript or any file used to produce these. I would also include any configuration files and files used to build/deploy the website or project. Anything that is compiled from your source files can safely be ignored.&lt;/p&gt;
&lt;h2 id="data"&gt;Data&lt;a class="anchor ms-1" href="#data" aria-label="Permalink: Data"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I would define data as anything that is added to the project during its life. So if you have an upload option, anything that is uploaded I would describe as data. The site should still function without (or very little) data.&lt;/p&gt;
&lt;h2 id="images"&gt;Images&lt;a class="anchor ms-1" href="#images" aria-label="Permalink: Images"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Images can fit into both groups. Any icons or images attached to the functionality of the project I would class as source code. However anything that is uploaded should be classed as Data.&lt;/p&gt;
&lt;h2 id="databases"&gt;Databases&lt;a class="anchor ms-1" href="#databases" aria-label="Permalink: Databases"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The database should also be classed as both. The data, anything that is inside a database table should normally be classed as data. Stored Procedures, Functions and Views are all Source Code and would benefit from version control.&lt;/p&gt;
&lt;h2 id="source-control--backup"&gt;Source Control != Backup&lt;a class="anchor ms-1" href="#source-control--backup" aria-label="Permalink: Source Control != Backup"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Source control is not an excuse not to backup things. Don’t just commit files to source control so you know you can restore them if you need to. Files in general in source control are there so you can see how they changed over time as the code base changed. Files in you backup are a snapshot of what the application was at a point in time and will include ALL the data.&lt;/p&gt;
&lt;p&gt;One last point before I end. If you are hosting on a Cloud Computing platform like Azure it gives you an easy way to distinguish between Data and Code.&lt;/p&gt;
&lt;p&gt;Anything in your&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web App = Code&lt;/li&gt;
&lt;li&gt;Blob Storage = Data&lt;/li&gt;
&lt;li&gt;SQL = Data/Code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each project is unique and there will always be exceptions to these suggestions but I think this is a good goal to have. What do you think?&lt;/p&gt;</description></item><item><title>Getting control of a codebase</title><link>https://blog-test.funkysi1701.com/posts/2016/getting-control-of-a-codebase/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 17 Nov 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/getting-control-of-a-codebase/</guid><category term="JavaScript">JavaScript</category><category term="AzureDevOps">AzureDevOps</category><category term="SQL">SQL</category><category term="VisualStudio">VisualStudio</category><category term="C-Sharp">C-Sharp</category><description>&lt;p&gt;So recently I started working on a new codebase. I will be honest when I first saw it, it was a mess. Here are a few of the things I did to try and regain control.&lt;/p&gt;
&lt;p&gt;I was given access to the source code on Visual Studio Team Services. However this consisted of a single commit 3 months ago. When I looked at what was running on the production server it was clear that changes were being made live with no regard for source control.&lt;/p&gt;
&lt;p&gt;The first thing I did was commit everything that was running live into source control.&lt;/p&gt;
&lt;p&gt;Next I created a SQL Server Data Tools (SSDT) project to keep track of all the database objects. Previously there was a folder with some stored procedures in it, but these did not match with what was currently running.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="SQL Server 2012 Management Studio Splash Screen" src="https://blog-test.funkysi1701.com/images/2016/sql-server-2012-management-studio-splash-screen.png" loading="lazy"
width="529" height="360"
/&gt;
&lt;/p&gt;
&lt;p&gt;I now had in source control the current state of the website and the database, so I knew I could get things back to this state if I made some bad changes.&lt;/p&gt;
&lt;p&gt;Lets start by looking at the website code I had. There was no solution file, the only way to look at the website was to setup my local IIS to run what was in the website folder. I could then use Visual Studio to &amp;ldquo;open&amp;rdquo; my local IIS website and attach to process to debug it.&lt;/p&gt;
&lt;p&gt;Next I Looked at Default.aspx to see how the website worked. The majority of the website code was stored in the database stored procedures. After the tag there was a &amp;lt;% %&amp;gt; which contained a Response.Write(RunSP.RunStoredProcedure(Parameter1, Parameter2, &amp;hellip;) command, which executed a stored procedure and the results of the stored procedure was the html code including any javascript that the webpage needed to display. I will be honest I have never seen any code like it. My guess is that the developer was secretly a DBA and wanted to make any web page changes by just changing how the stored procedures work.&lt;/p&gt;
&lt;p&gt;This meant that the website is not going to do anything without a backup of the database running, and meant my SSDT project was going to be vital. However the database was in a bad state, it consisted of a fair few broken objects and SSDT would not build.&lt;/p&gt;
&lt;p&gt;Using find I went through each of the broken database objects to find where in the code they were being used. Luckily most were referenced in commented out code, so I just removed all the broken database objects. The database could now be built. However there was a dependency on the users table of another database. (This was the developers solution to sharing logins between websites) As I was using SSDT I added a database dependency, problem solved for now.&lt;/p&gt;
&lt;p&gt;Next I tried publishing my database. SQL CMD encountered a parsing error. The reason for this was my SPs contained javascript eg $(document), SQL CMD uses $(DatabaseName) as variables for different database so it was getting itself confused.&lt;/p&gt;
&lt;p&gt;My solution was to use Find and Replace to replace all the $ with &amp;rsquo; + CHAR(36) + '&lt;/p&gt;
&lt;p&gt;So I now have a SSDT project that builds and publishes but still no website project.&lt;/p&gt;
&lt;p&gt;To get the website running from Visual Studio I started off creating a .Net 4 website project and added Entity Framework 5 and MVC 3 via nuget. I then copied all the website code into the new project, and with a bit of work I got it to build. Most of the work was relating to namespaces and referencing the correct one and moving the EF model from AppCode to a custom named folder. A bit of trial and error later I had a version of the website that could be run from Visual Studio.&lt;/p&gt;
&lt;p&gt;I have not deployed my new version of the website as it needs further testing. No automated testing or even a smoke test checklist currently exist.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Visual Studio Team Services build pipeline for source code commits" src="https://blog-test.funkysi1701.com/images/2016/Visual-Studio-Team-Services.png" loading="lazy"
width="960" height="434"
/&gt;
&lt;/p&gt;
&lt;p&gt;As my source code is hosted on Visual Studio Team Services (VSTS), I can get VSTS to build each commit and check I haven’t broken the build. This is not that helpful at the moment, hopefully one day I will have automated tests that can be run here as well.&lt;/p&gt;
&lt;p&gt;Wow, I feel like I have done loads with this code so far but there is loads more still to do. I need to understand more about the business processes behind the code with a hope to understand why some architectural decisions have been made. I want to refactor the code as much as is possible, I would like to remove much of the html/javascript from the stored procedures as I can’t see that there is any advantage to running a website like this. Please correct my if I am wrong.&lt;/p&gt;</description></item><item><title>LINQ</title><link>https://blog-test.funkysi1701.com/posts/2016/linq/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 06 Oct 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/linq/</guid><category term="LINQ">LINQ</category><category term="SQL">SQL</category><category term="C-Sharp">C-Sharp</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/step30.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="LINQ Language Integrated Query overview diagram" src="https://blog-test.funkysi1701.com/images/2016/step30.jpg" loading="lazy"
width="515" height="355"
/&gt;
&lt;/p&gt;
&lt;h2 id="what-is-linq"&gt;What is LINQ?&lt;a class="anchor ms-1" href="#what-is-linq" aria-label="Permalink: What is LINQ?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;LINQ&lt;/strong&gt; is an acronym for Language Integrated Query, which describes where it’s used and what it does. The Language Integrated part means that LINQ is part of programming language syntax. In particular, both C# and VB are languages that ship with .NET and have LINQ capabilities.&lt;/p&gt;
&lt;h2 id="how-do-i-use-linq-in-my-c-code"&gt;How do I use LINQ in my C# code?&lt;a class="anchor ms-1" href="#how-do-i-use-linq-in-my-c-code" aria-label="Permalink: How do I use LINQ in my C# code?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To use LINQ the first thing you need to do is add the LINQ using statement.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.Linq;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In your code you need a datasource, for this example I am going to use a simple array, but it can be anything eg SQL, XML etc&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;[] data = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;] { &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next you need a LINQ query. (Note I know the Q in LINQ means query, so I have just written query query, if you are one of those people who hates seeing PIN number you might not like this blog post.) A LINQ query is very similar to a T-SQL query, so if like me you are good with databases this should make sense to you.&lt;/p&gt;
&lt;p&gt;In T-SQL you can have:&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; num
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; num &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In LINQ this becomes:&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; query =
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; num &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; num == &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; num;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally you need to do something with the query you have written. I am just going to print the results of my query to console.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; num &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; query)
&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; Console.Write(num);
&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;h2 id="what-other-sql-like-syntax-can-i-use"&gt;What other SQL like syntax can I use?&lt;a class="anchor ms-1" href="#what-other-sql-like-syntax-can-i-use" aria-label="Permalink: What other SQL like syntax can I use?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In T-SQL you can control ordering using ORDER BY, LINQ has a similar syntax orderby&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;orderby&lt;/span&gt; num &lt;span style="color:#66d9ef"&gt;descending&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In T-SQL you can use GROUP BY, to do something similar with LINQ&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;group&lt;/span&gt; num &lt;span style="color:#66d9ef"&gt;by&lt;/span&gt; num.Type &lt;span style="color:#66d9ef"&gt;into&lt;/span&gt; type
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; type
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; type &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; query)
&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; Console.Write(type.Key);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; num &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; type)
&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; Console.Write(num);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="joins"&gt;JOINS&lt;a class="anchor ms-1" href="#joins" aria-label="Permalink: JOINS"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So you thought joining tables was a SQL Server only thing. Think again you can do this in LINQ&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; joinquery =
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; cust &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; customers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; prod &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; products &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; prod.CustomerId &lt;span style="color:#66d9ef"&gt;equals&lt;/span&gt; cust.Id
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; { ProductName = prod.Name, CustomerName = cust.CompanyName };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="anchor ms-1" href="#conclusion" aria-label="Permalink: Conclusion"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are loads more LINQ functionality that you can use. While writing this blog I found &lt;a href="https://learn.microsoft.com/101-LINQ-Samples-3fb9811b" target="_blank" rel="noopener noreferrer"&gt;https://learn.microsoft.com/101-LINQ-Samples-3fb9811b&lt;/a&gt;
which has loads of examples of different queries that you can write with LINQ.&lt;/p&gt;
&lt;p&gt;This has inspired me to use LINQ more in my code and learn more about the different queries that could be written.&lt;/p&gt;</description></item><item><title>Looking back Ten years</title><link>https://blog-test.funkysi1701.com/posts/2016/looking-back-ten-years/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 29 Sep 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/looking-back-ten-years/</guid><category term="DevOps">DevOps</category><category term="ITAdmin">ITAdmin</category><category term="Servers">Servers</category><category term="Nagios">Nagios</category><category term="2016">2016</category><category term="2006">2006</category><category term="C-Sharp">C-Sharp</category><category term="Career">Career</category><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Animated graphic marking a ten-year career milestone" src="https://blog-test.funkysi1701.com/images/2016/10-year-term-life-insurance.gif" loading="lazy"
width="471" height="314"
/&gt;
&lt;/p&gt;
&lt;p&gt;Next month I will celebrate ten years working at my current job, two weeks after that I will start a new chapter of my life at a new company. Lets take this opportunity to look back ten years at some of the great stuff I have achieved.&lt;/p&gt;
&lt;h2 id="2006"&gt;2006&lt;a class="anchor ms-1" href="#2006" aria-label="Permalink: 2006"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2006 I had no IT experience. If you were to ask me where Event Logs could be found I wouldn’t know, and the letters DNS meant nothing to me. I was quiet and shy but hard working. The idea of making IT my career hadn’t occurred to me, this was just a job.&lt;/p&gt;
&lt;p&gt;I started off life doing first line support and compiling health and safety files onto CD-ROMs (known by the company as Eurofiles) with HTML. At the time the company had a mix of Windows 2000 and Windows XP, using MS Office 2003. Server wise I can’t remember exactly but I think two domain controllers, a database server and a backup server using a tape drive. At this point in time I don’t believe I did a lot with the servers but I think the servers were running Windows Server 2005.&lt;/p&gt;
&lt;p&gt;As time went on I learnt more and more about what the company did and how stuff worked.&lt;/p&gt;
&lt;h2 id="nagios"&gt;Nagios&lt;a class="anchor ms-1" href="#nagios" aria-label="Permalink: Nagios"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of my early achievements was setting up a nagios server. I have blogged about &lt;a href="https://www.funkysi1701.com/posts/2014/i-love-nagios/" target="_blank" rel="noopener noreferrer"&gt;Nagios&lt;/a&gt;
before, but it is a server monitoring system that runs on linux. I am extremely proud of what I have achieved here, no one else in the company had my knowledge of how nagios worked. Initially I even experimented with using a cheap mobile phone connected to the serial port (remember when PCs had these?) to send SMS messages to alert of down time. However this was abandoned when I burned through all the credit on this phone.&lt;/p&gt;
&lt;p&gt;Nagios is still used today, and my current team have been shown how to extend the system as the business changes. My philosophy has always been if we have a problem that Nagios didn’t warn us about we need an extra nagios test. These days the nagios web interface is publicly available on the internet so can be checked from anywhere (assuming the office internet is up!) and a mobile app replaces the SMS idea we originally had.&lt;/p&gt;
&lt;h2 id="2011"&gt;2011&lt;a class="anchor ms-1" href="#2011" aria-label="Permalink: 2011"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At the end of 2010 the IT Manager resigned, then the Developer resigned and finally the Lead Developer resigned. I was alone. I was IT Manager. I negotiated my first pay rise since joining the company. I was IT.&lt;/p&gt;
&lt;p&gt;Wow things were stressful back then. I had so much to learn but somehow I managed. I learnt how to Interview, yes I have employed some clangers along the way, but also some great staff. As well as internal staff I learnt to deal with contractors. We had contractors to help with our internal systems and also contractors to do development work. One thing I have learnt about contractors is that you will always have to chase them at some point to deliver what you are paying them for.&lt;/p&gt;
&lt;h2 id="server-migration"&gt;Server Migration&lt;a class="anchor ms-1" href="#server-migration" aria-label="Permalink: Server Migration"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Around the start of 2011 our email server started to show its age. Exchange 2003 had a hard limit on the size of its information store and we were rapidly approaching this. Along with an IT contractor I worked to migrate to Exchange 2010, this was a huge project and caused all sorts of issues which we just worked through. Since then I have done other migrations so Windows Server 2012 and also virtualized many servers in 2013.&lt;/p&gt;
&lt;h2 id="bandwidth"&gt;Bandwidth&lt;a class="anchor ms-1" href="#bandwidth" aria-label="Permalink: Bandwidth"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A major limit with our infrastructure has always been the internet connection coming in. For a while we tried to load balance three ADSL connections, but the upload speed was always a limiting factor. It was a major victory for the simplification of our network when we got a leased line installed into our head office, helped by a government grant we gave us free installation. Not content with this I did the same again for our second York office, including the free installation.&lt;/p&gt;
&lt;h2 id="learning-development"&gt;Learning Development&lt;a class="anchor ms-1" href="#learning-development" aria-label="Permalink: Learning Development"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since I started I have always been learning development stuff. But in the past few years I have learnt a massive amount helped largely by two main things. My boss passing lots of my responsibility onto others and dedicating lots of my time to development tasks, and also the opportunity to learn with our outsourced development team.&lt;/p&gt;
&lt;h2 id="finishing-off"&gt;Finishing off&lt;a class="anchor ms-1" href="#finishing-off" aria-label="Permalink: Finishing off"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a few things that have been ongoing that we have wanted to change since I started which I can’t really take the credit for as they are not complete yet, but I am proud as they may be finished in the next few months.&lt;/p&gt;
&lt;p&gt;The company stores calendar information in one giant excel spreadsheet, this is being replaced by outlook calendars.&lt;/p&gt;
&lt;p&gt;Our last Windows Server 2003 server and tape drive is being decommissioned. This is the only server that has been running for the entire time I have been here.&lt;/p&gt;
&lt;p&gt;The way the company keeps track of work coming in and who does what is being reviewed. Over the years many people have tried to adapt the old database that one of the directors created in Access many years ago. I did a major overhaul recently to delete unused columns and added extra invoicing functionality. What is needed is a fresh system, maybe a CRM can do everything they want. I wish them lots of luck in doing this as I know it won’t be easy but it has to be done.&lt;/p&gt;
&lt;h2 id="2016"&gt;2016&lt;a class="anchor ms-1" href="#2016" aria-label="Permalink: 2016"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are many other projects and pieces of work that I have done that I am proud of. In 2016 I will leave a stable IT department. All clients are on Windows 10 and using Office 2010. We have virtual servers running Server 2012 and are using some great services from Azure to run our SaaS websites. There are of course things I would have liked to achieve, and things I wish I had done differently but on the whole it feels like the right time to move on, especially now long running projects are starting to conclude.&lt;/p&gt;</description></item><item><title>10 Ways to Survive as an IT Manager</title><link>https://blog-test.funkysi1701.com/posts/2016/10-ways-to-survive-as-an-it-manager/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 22 Sep 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/10-ways-to-survive-as-an-it-manager/</guid><category term="ITAdmin">ITAdmin</category><category term="Backups">Backups</category><category term="DevOps">DevOps</category><category term="Technology">Technology</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/bhrzpww6aehdx1wvrrug.jpg"/><description>&lt;p&gt;So after five and a bit years of being an IT Manager here is some advice I have learned along the way in no particular order. On the whole I have enjoyed myself but it has been a real challenge at times.&lt;/p&gt;
&lt;h2 id="1-figure-out-what-plates-are-still-spinning"&gt;1. Figure out what plates are still spinning&lt;a class="anchor ms-1" href="#1-figure-out-what-plates-are-still-spinning" aria-label="Permalink: 1. Figure out what plates are still spinning"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Being an IT Manager is all about keeping everything running all of the time. A bit like spinning 5 or 6 plates. You have plates for your servers and network infrastructure, you have plates for bespoke databases that you maintain, you have plates for your staff (including any external contractors), you have plates for any websites or apps that you develop. That is a lot of plates to keep spinning and that before you start thinking about what your boss wants you to deliver. Make sure you know what is happening with all these plates, which ones are happy, which ones are on the way to the floor and which ones you need to get the glue out and repair.&lt;/p&gt;
&lt;h2 id="2-make-it-someone-elses-problem"&gt;2. Make it someone else’s problem&lt;a class="anchor ms-1" href="#2-make-it-someone-elses-problem" aria-label="Permalink: 2. Make it someone else’s problem"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you can blame someone else do so. If your internet goes down it is your ISPs fault. If your website dies its your hosting company’s fault. Take responsibility for problems but if when something goes wrong you can pick up the phone and ask for help, it will make your life easier.&lt;/p&gt;
&lt;h2 id="3-hire-good-staff"&gt;3. Hire good staff&lt;a class="anchor ms-1" href="#3-hire-good-staff" aria-label="Permalink: 3. Hire good staff"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hiring poor staff wastes time and money and makes you look bad by others. Demand the highest salary band for new staff that you can afford and don’t agree to hiring anyone that you have doubts about. It is easy to bow to the pressure to get someone quickly but this will always result in worse problems in the long run. Once you have a good team do your best to keep them, and warn upper management of the problems if staff leaves (basically make it their problem not yours!).&lt;/p&gt;
&lt;h2 id="4-learn-learn-learn"&gt;4. Learn, Learn, Learn&lt;a class="anchor ms-1" href="#4-learn-learn-learn" aria-label="Permalink: 4. Learn, Learn, Learn"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may or may not have the opportunity to go on training courses. Whatever your situation spend time learning new stuff that will benefit the company and yourself. You can learn a lot by reading online, you can petition for training from your managers, you can fund training yourself, you can ask for help from your different suppliers. The more you learn, the more you can do and the more useful you can be to the company, plus the more interesting you will find the job.&lt;/p&gt;
&lt;h2 id="5-say-no"&gt;5. Say No!&lt;a class="anchor ms-1" href="#5-say-no" aria-label="Permalink: 5. Say No!"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Don’t be afraid to say no. You will always be asked to do the impossible and if something is impossible say so at the start. It wastes everyone’s time if you spend a lot of time trying to do the impossible. Always give your reasons for saying no, and if you always say no people will think you are unhelpful. A better way to say no is to come up with a better solution. No I can’t do it your way but here is a better solution.&lt;/p&gt;
&lt;h2 id="6-dont-give-estimates"&gt;6. Don’t give estimates&lt;a class="anchor ms-1" href="#6-dont-give-estimates" aria-label="Permalink: 6. Don’t give estimates"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are asked how long something will take you don’t answer straight away or give an exaggerated estimate. Go away and spend some time thinking of everything that is involved before replying. There will always be something that you forgot to consider when first asked about it and looking at the different components will help plan out the work needed as well as provide an estimate.&lt;/p&gt;
&lt;h2 id="7-know-what-to-tell-your-boss-and-what-not-to"&gt;7. Know what to tell your boss, and what not to&lt;a class="anchor ms-1" href="#7-know-what-to-tell-your-boss-and-what-not-to" aria-label="Permalink: 7. Know what to tell your boss, and what not to"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a hard one to get the balance right for. You need to tell your boss enough so that they appreciate all that you do, but too much and they will stop listening and accuse you of talking in technobabble. I have never got the balance right with this one. I have always aired on the side of not telling my boss enough, and hence they don’t realize that I saved the day on Sunday night as everything is working again on Monday. Do repeat yourself. If your server is running low on resources start asking for replacement hardware early, and increase the frequency and the panic in line with the problems it is causing.&lt;/p&gt;
&lt;h2 id="8-understand-the-problems-of-the-business"&gt;8. Understand the problems of the business&lt;a class="anchor ms-1" href="#8-understand-the-problems-of-the-business" aria-label="Permalink: 8. Understand the problems of the business"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Illustration of understanding business needs and profitability as an IT manager" src="https://blog-test.funkysi1701.com/images/2016/bhrzpww6aehdx1wvrrug.jpg" loading="lazy"
width="800" height="450"
/&gt;
&lt;/p&gt;
&lt;p&gt;Businesses need to make money. If the one you work for isn’t making enough money you will soon be looking for another. If you work for IT you will quickly start to see the problems of the business, think about what simple changes IT could make to improve things that would benefit the whole company. Some of your suggestions won’t go anywhere, but some may have a massive impact. I can think of a few changes that IT have spearheaded that I am very proud of, upgrading our internet connection, simplifying or automating processes and delivering new versions of software.&lt;/p&gt;
&lt;h2 id="9-ask-for-help"&gt;9. Ask for help&lt;a class="anchor ms-1" href="#9-ask-for-help" aria-label="Permalink: 9. Ask for help"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Don’t be afraid of asking for help. There are lots of places to look for help. Other departments could take more on, you could recruit extra help, you could hire external contractors. You can ask questions on support forums like &lt;a href="https://serverfault.com/" target="_blank" rel="noopener noreferrer"&gt;ServerFault&lt;/a&gt;
or &lt;a href="https://stackoverflow.com/questions" target="_blank" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt;
, many software re-sellers or other suppliers are a good point of contact for questions about things they supply. Microsoft Support was also invaluable for a server issue.&lt;/p&gt;
&lt;h2 id="10-think-about-disasters"&gt;10. Think about disasters&lt;a class="anchor ms-1" href="#10-think-about-disasters" aria-label="Permalink: 10. Think about disasters"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Write a disaster recovery plan or backup policy. Yes there will always be something more important that needs doing, but just stop for a moment to think how you would feel if everything died on your watch. The one thing you can rely on with technology is that it will fail at some point. A back of the envelope plan of action is better than no plan at all, even better is a detailed plan of what to do when each and every service you rely on fails. Plan additional services with an idea of adding extra redundancy. Always have multiple Domain Controllers, think about what data you could run from the Cloud. VMs could be replicated to the Cloud, and servers could be run from there.&lt;/p&gt;</description></item><item><title>Imposter Syndrome</title><link>https://blog-test.funkysi1701.com/posts/2016/imposter-syndrome/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 15 Sep 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/imposter-syndrome/</guid><category term="Newjob">Newjob</category><category term="ImposterSyndrome">ImposterSyndrome</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/1429677066685.rendition-medium.jpg"/><description>&lt;p&gt;This week I handed in my notice at a job I have had for almost ten years. In a few weeks time I will start a brand new job as a web applications developer.&lt;/p&gt;
&lt;p&gt;This is a great achievement for me and a great chance to learn and expand my development skills.&lt;/p&gt;
&lt;p&gt;However moments after I handed my notice in, a huge wave of uncertainty enveloped me. I have read about this and I think I was suffering from an attack of &lt;strong&gt;Imposter Syndrome&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Despite external evidence of their competence, those with the syndrome remain convinced that they are frauds and do not deserve the success they have achieved. Proof of success is dismissed as luck, timing, or as a result of deceiving others into thinking they are more intelligent and competent than they believe themselves to be.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Person feeling overwhelmed and uncertain about starting a new job" src="https://blog-test.funkysi1701.com/images/2016/1429677066685.rendition-medium.jpg" loading="lazy"
width="598" height="309"
/&gt;
&lt;/p&gt;
&lt;p&gt;I started to convince myself I couldn’t do the job I had just accepted and that moments after I arrived on my first day I would be found out as a fraud and kicked out the door.&lt;/p&gt;
&lt;p&gt;My logical brain was no match for the Imposter Syndrome. Having been kicked out the door of this new job, I would become penniless in no time with no employer (even my previous boss wouldn’t want me back) or recruitment agency willing to speak with me.&lt;/p&gt;
&lt;p&gt;OK lets see if we can fight off the Imposter Syndrome and look at a possible worse case scenario. I start at my new job, it is very hard work and a month or so later I have to move on.&lt;/p&gt;
&lt;p&gt;No employer ever would sack me on my first day. My first day will be lots of learning how they do things, looking at procedures. I have lots of experience of learning new things, looking at procedures and if I put the work in I can make this new job a success. I have lots of good ideas and useful experience that no one at my new company has.&lt;/p&gt;
&lt;p&gt;I don’t know what the solution is to Imposter Syndrome other than to try and ignore it by thinking positively and the knowledge that I have done amazing things in the last ten years and I will do the same in the next ten.&lt;/p&gt;</description></item><item><title>DZone</title><link>https://blog-test.funkysi1701.com/posts/2016/dzone/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 25 Aug 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/dzone/</guid><category term="Blogging">Blogging</category><category term="DevOps">DevOps</category><category term="Social">Social</category><category term="DZone">DZone</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2016/dzone_02.png"/><description>&lt;p&gt;For a while now I have been sharing some of my blog posts on the &lt;a href="https://dzone.com/" target="_blank" rel="noopener noreferrer"&gt;Dzone&lt;/a&gt;
website.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="DZone developer community website homepage" src="https://blog-test.funkysi1701.com/images/2016/dzone_02.png" loading="lazy"
width="400" height="300"
/&gt;
&lt;/p&gt;
&lt;p&gt;The Dzone website allows users to submit links to content and I have been submitting the content I have created on this website. This is how Dzone describes themselves:&lt;/p&gt;
&lt;p&gt;With over 1 Million members, DZone.com is one of the web’s largest communities and publishers of technical content for software professionals. Developers from all over the world come to DZone for the latest and best content to hone their skills and advance their careers.&lt;/p&gt;
&lt;p&gt;Well this week I have been invited to join the &lt;a href="https://dzone.com/pages/contribute" target="_blank" rel="noopener noreferrer"&gt;MVB&lt;/a&gt;
(Most Valuable Blogger) programme. The hope is that more of my readers will find my content from the DZone website.&lt;/p&gt;
&lt;p&gt;The DZone team will soon start sharing my content on the DZone website and I hope this will result in even more people reading what I have to say.&lt;/p&gt;
&lt;p&gt;If nothing else this is clearly telling me that my blog is making a difference, people are taking note of me and what I have to say. I need to keep going and keep writing articles and be more consistent.&lt;/p&gt;</description></item><item><title>Amazon Web Services Pt 2</title><link>https://blog-test.funkysi1701.com/posts/2016/amazon-web-services-pt-2/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 04 Aug 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/amazon-web-services-pt-2/</guid><category term="AWS">AWS</category><category term="Azure">Azure</category><category term="Amazon">Amazon</category><category term="Cloud">Cloud</category><category term="DevOps">DevOps</category><description>&lt;p&gt;Last time I started looking at Amazon Web Services and how it differed from Azure. I am going to continue looking at what it can do.&lt;/p&gt;
&lt;h2 id="virtual-machines"&gt;Virtual Machines&lt;a class="anchor ms-1" href="#virtual-machines" aria-label="Permalink: Virtual Machines"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lets look at what you can do with Virtual Machines. I selected to create a new Virtual Machine (or as AWS calls them an EC2 Instance)&lt;/p&gt;
&lt;p&gt;First you choose a name for your VM and then the OS that runs on it. There are 5 main OSes to choose from Windows Server, Amazon Linux and a selection of the most common Linux flavours.&lt;/p&gt;
&lt;p&gt;You can then download a certificate to secure your VM.&lt;/p&gt;
&lt;p&gt;Like Azure, AWS takes a few moments to create your VM. While I wait I can see that AWS has configured a firewall so only my current IP can connect to it.&lt;/p&gt;
&lt;p&gt;Once the VM is ready you can download an RDP file. However to get the login details you need to decrypt the password using the certificate you downloaded when you created the VM.&lt;/p&gt;
&lt;p&gt;It is interesting to compare the difference in security between Azure and AWS. Azure allows the resetting of passwords of VMs directly from its console, however I suspect that in AWS if you loose your certificate (AWS states they don’t keep a copy of this) you would have to recreate your VM.&lt;/p&gt;
&lt;p&gt;Like with the Websites the default name of the VM is much less user-friendly than what you get from Azure. However I suspect there are other options I haven’t spotted that may customise these.&lt;/p&gt;
&lt;h2 id="azure-portal-vs-aws-console"&gt;Azure Portal vs AWS Console&lt;a class="anchor ms-1" href="#azure-portal-vs-aws-console" aria-label="Permalink: Azure Portal vs AWS Console"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I really like the Azure Portal. It feels like something that has been designed so you can easily access all the options for a specific Azure feature.&lt;/p&gt;
&lt;p&gt;The AWS Console probably has all the same options as with Azure however I don’t think it looks half as good, and will take me a while looking through menus to find the equivalent options. Part of this is due to my unfamiliarity with AWS, so will get easier with time.&lt;/p&gt;</description></item><item><title>Amazon Web Services</title><link>https://blog-test.funkysi1701.com/posts/2016/amazon-web-services/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 21 Jul 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/amazon-web-services/</guid><category term="AWS">AWS</category><category term="Azure">Azure</category><category term="Amazon">Amazon</category><category term="Cloud">Cloud</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2016/07/aws-300x169.png"/><description>&lt;p&gt;I am a big fan of Azure but I know zero about its biggest rival – Amazon Web Services or AWS.&lt;/p&gt;
&lt;p&gt;So lets sign up for a free trial and see what it can do.
&lt;img class="img-fluid" alt="Amazon Web Services" src="https://blog-test.funkysi1701.com/images/2016/07/aws-300x169.png" loading="lazy"
width="300" height="169"
/&gt;
&lt;/p&gt;
&lt;p&gt;The AWS free trial is available from &lt;a href="https://aws.amazon.com/free/" target="_blank" rel="noopener noreferrer"&gt;https://aws.amazon.com/free/&lt;/a&gt;
and lasts for 12 months. From memory I think the Azure free trial lasted only one month.&lt;/p&gt;
&lt;p&gt;To start you need to login with your amazon account and create an AWS account. This requires your name and address and your payment info (you will only get billed if use services not covered by your free trial).&lt;/p&gt;
&lt;p&gt;Interestingly AWS requires you to verify your identity via an automated phone call. (I don’t recall doing anything like this for Azure but please correct me if I am wrong.)&lt;/p&gt;
&lt;p&gt;Once you are logged in you get a series of links displaying all the different services that are available. First impression is this is a simpler view to Azure’s portal with a similar amount of services. At the top right is an option to select which region you want to use, in Azure I use North Europe and West Europe, AWS has Ireland and Frankfurt.&lt;/p&gt;
&lt;h2 id="create-a-web-app"&gt;Create a Web App&lt;a class="anchor ms-1" href="#create-a-web-app" aria-label="Permalink: Create a Web App"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First thing to try is setting up a website. I selected create a web app and I get a page asking me for its basic details (very similar to Azure, however AWS asked what language your code is written in, Azure handles all of these) AWS websites appear to support a host of different options similar to Azure.&lt;/p&gt;
&lt;p&gt;The actual creation of your website takes a few moments (like on Azure). However the default URL for websites is similar to &lt;code&gt;https://test.vjbbimyv7w.eu-central-1.elasticbeanstalk.com/&lt;/code&gt; which is not quite as nice as the Azure equivalent &lt;code&gt;https://test.azurewebsites.net&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Azure has a host of command lines available via powershell. AWS has a similar command line interface called AWS CLI, including the option to deploy from git to your website.&lt;/p&gt;
&lt;p&gt;AWS Toolkit for Visual Studio is an extension that allows for the publishing of websites to AWS. (Just like you can publish to Azure)&lt;/p&gt;
&lt;p&gt;As I learn more about AWS I will continue to blog about it. &lt;a href="https://www.funkysi1701.com/posts/2016/amazon-web-services-pt-2/" target="_blank" rel="noopener noreferrer"&gt;Amazon Web Services Pt 2&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Clever things with MS Access</title><link>https://blog-test.funkysi1701.com/posts/2016/clever-things-ms-access/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 07 Jul 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/clever-things-ms-access/</guid><category term="Database">Database</category><category term="Access">Access</category><category term="DevOps">DevOps</category><category term="SourceControl">SourceControl</category><description>&lt;p&gt;I hate MS Access and especially developing with it as you can’t do any thing clever with it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wrong, Wrong, Wrong!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are a few clever things I have been able to script to make developing with it passable. I still would rather use Visual Studio but this improves the experience a fair bit.&lt;/p&gt;
&lt;h2 id="source-control"&gt;Source Control&lt;a class="anchor ms-1" href="#source-control" aria-label="Permalink: Source Control"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Access files are binary (I use the ADP/ADE file format but I assume other Access file formats have the same problem) and so you can’t diff them to see what has changed. This is bad.&lt;/p&gt;
&lt;p&gt;However there is a solution to this. A tool called Access SVN and can be downloaded from &lt;a href="https://accesssvn.codeplex.com/" target="_blank" rel="noopener noreferrer"&gt;https://accesssvn.codeplex.com/&lt;/a&gt;
, this gives you a way to extract to text files all the forms and reports that are in Access. Before every commit I would manually run this tool on my ADP file and extract to text files, then I would commit these text files to source control and could easily see what had changed in each commit.&lt;/p&gt;
&lt;p&gt;Despite the name Access SVN, the tool is not tied to subversion, you can use any source control system, I use git.&lt;/p&gt;
&lt;p&gt;Also included in this tool is a way to do this with the command line, so you can make this a build step on your build server. I have not used this extensively yet, but the syntax is fairly simple&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;asvn.exe e &lt;span style="color:#e6db74"&gt;&amp;#34;path to Access file&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;path to txt files&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;*.*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The filter at the end &lt;em&gt;.&lt;/em&gt; allows you to specify what to extract so you could extract all forms/reports beginning with D with &amp;ldquo;&lt;em&gt;.D&lt;/em&gt;&amp;rdquo;. I had trouble using &lt;em&gt;.&lt;/em&gt; because the names of my forms/reports contain characters not allowed in a windows file name. I am sure there is a way round this but I haven’t had chance to look into it further yet.&lt;/p&gt;
&lt;h2 id="testing-ms-access"&gt;Testing MS Access&lt;a class="anchor ms-1" href="#testing-ms-access" aria-label="Permalink: Testing MS Access"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Surely testing is not possible with MS Access? I would have agreed with that statement the other day until I found a neat way of testing if a feature is enabled.&lt;/p&gt;
&lt;p&gt;Firstly a bit of background. I develop using MS Access 2003 because the design view is far easier to use, however because it is out of support all my users use MS Access 2010. MS Access 2010 has a feature called Tabbed Documents which allows all forms and reports to open in new tabs so you can easily switch between them. This feature can only be enabled in MS Access 2010 and has no effect if opening with MS Access 2003.&lt;/p&gt;
&lt;p&gt;If you use Access SVN on your Access file with tabbed documents turned on and off you will see UseMDIMode: 0 and UseMDIMode: 1 show up in the Database properties file. UseMDIMode: 0 means that tabbed documents is turned on.&lt;/p&gt;
&lt;p&gt;In powershell I can now write a test to see if UseMDIMode: 0 can be found in the database properties file&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Get-Content &lt;span style="color:#e6db74"&gt;&amp;#34;General\Database properties.dbp.txt&amp;#34;&lt;/span&gt; | Select-String &lt;span style="color:#e6db74"&gt;&amp;#34;UseMDIMode: 0&amp;#34;&lt;/span&gt; -quiet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the test passes True will be returned, if it fails null will be returned.&lt;/p&gt;
&lt;p&gt;On my build server I scripted the extraction of Database properties.dbp.txt from the ADP file with asvn.exe before running this test. While not strictly needed as Database properties.dbp.txt should be in source control, it is possible that someone could forget to extract the text files from the ADP, with this step you are always testing what is enabled in the binary file.&lt;/p&gt;
&lt;h2 id="ms-access-connection-strings"&gt;MS Access Connection Strings&lt;a class="anchor ms-1" href="#ms-access-connection-strings" aria-label="Permalink: MS Access Connection Strings"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While developing with MS Access I often swap the database connection to point to my local machine or a build server. I always try and remember to only ever commit with this set to the live database to avoid obvious problems.&lt;/p&gt;
&lt;p&gt;The other day I found on &lt;a href="https://stackoverflow.com/questions/16411430/change-access-server-connection-from-command-line" target="_blank" rel="noopener noreferrer"&gt;stackoverflow&lt;/a&gt;
a way to script this. I love this! I can include this step in my deployment process and it will overwrite what ever the connection string is in source control with what your production environment needs.&lt;/p&gt;
&lt;p&gt;All you need to run this step is, (note it is spaces between the parameters not commas)&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cscript connect.vbs Project.adp &lt;span style="color:#e6db74"&gt;&amp;#34;ServerName&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;DatabaseName&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The contents of connect.vbs can be found on the &lt;a href="https://stackoverflow.com/questions/16411430/change-access-server-connection-from-command-line" target="_blank" rel="noopener noreferrer"&gt;stackoverflow article&lt;/a&gt;
. It is also possible to pass username and password if your environment requires this.&lt;/p&gt;
&lt;h2 id="compiled-ade"&gt;Compiled ADE&lt;a class="anchor ms-1" href="#compiled-ade" aria-label="Permalink: Compiled ADE"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The last clever thing I do with MS Access is convert my ADP file into the compiled ADE version. To manually do this there is an option in the tools menu.&lt;/p&gt;
&lt;p&gt;To automate this I run&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cscript createADE.vbs &lt;span style="color:#e6db74"&gt;&amp;#34;path to ADP&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;path to ADE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The contents of createADE came from this &lt;a href="https://social.msdn.microsoft.com/Forums/office/en-US/01fd48a9-258e-4405-86f1-adfb2f1057ee/create-an-access-2007-ade-from-a-adp-via-commandline?forum=accessdev" target="_blank" rel="noopener noreferrer"&gt;forum post&lt;/a&gt;
, the only change I made was to comment out some of the echo statements so it would run silently as part of my build process. It should be noted that cscript and wscript are almost identical and either will run these scripts however in a command line environment cscript is preferable, and wscript should be used in a windows environment.&lt;/p&gt;
&lt;p&gt;I am quite surprised at how much I have managed to do in terms of scripting the build and deployment process for MS Access. I still don’t like developing with Access but this has definitely improved things.&lt;/p&gt;</description></item><item><title>Periodic Table of DevOps</title><link>https://blog-test.funkysi1701.com/posts/2016/periodic-table-devops/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 30 Jun 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/periodic-table-devops/</guid><category term="Chemistry">Chemistry</category><category term="DevOps">DevOps</category><category term="Tools">Tools</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2016/periodic-table-of-devops-v2.png"/><description>&lt;p&gt;The periodic table lists all the chemical elements and groups them together based on some key properties. Today I found an article about the &lt;a href="https://digital.ai/periodic-table-of-devops-tools/" target="_blank" rel="noopener noreferrer"&gt;periodic table of DevOps&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Periodic table of DevOps tools grouped by category" src="https://blog-test.funkysi1701.com/images/2016/periodic-table-of-devops-v2.png" loading="lazy"
width="4896" height="2734"
/&gt;
&lt;/p&gt;
&lt;p&gt;I am not going to discuss every element but I thought I might go through some that I have heard of or used.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Github – The repository of lots of open source software. My Github can be found at &lt;a href="https://github.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;https://github.com/funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Amazon Web Services – The second most popular cloud computing provider (not sure why this isn’t number 3?)&lt;/li&gt;
&lt;li&gt;Git – The distributed source control system that everyone uses these days.&lt;/li&gt;
&lt;li&gt;Azure – The number one cloud provider, I have used this a lot, mostly with websites but also with some of their other features like Traffic Manager.&lt;/li&gt;
&lt;li&gt;Bitbucket – like Github but allows private repositories. I have used this extensively for work based projects that I don’t want to be public.&lt;/li&gt;
&lt;li&gt;Google Cloud Platform – don’t know much about this one, but no surprise that google wants a piece of the cloud computing pie.&lt;/li&gt;
&lt;li&gt;Selenium – This is a product I want to play about with as allows front end testing with a browser.&lt;/li&gt;
&lt;li&gt;Rackspace – Before we made the jump to Azure we made use of some Rackspace servers.&lt;/li&gt;
&lt;li&gt;Subversion – The first source control system that I used, but been using git so long now not sure I can remember how it worked.&lt;/li&gt;
&lt;li&gt;Visual Studio – The IDE from Microsoft that I use to write code. I am a big fan as it does everything I could want.&lt;/li&gt;
&lt;li&gt;TeamCity – The continuous integration software that I have been using to automate my deployments.&lt;/li&gt;
&lt;li&gt;MSBuild – This is used by Visual Studio to build your software and can also be used by your deployment scripts.&lt;/li&gt;
&lt;li&gt;Trello – A website that allows you to create a board of ideas or things to do.&lt;/li&gt;
&lt;li&gt;Slack – Brings all your communication together in one place. It’s real-time messaging, archiving and search for modern teams.&lt;/li&gt;
&lt;li&gt;New Relic – A software analytics tool suite used by developers, ops, and software companies to understand how your applications are performing. Useful but find myself favouring Application Insights (part of Azure) more now.&lt;/li&gt;
&lt;li&gt;Nagios – Yay nagios is on the list! My favourite server monitoring system.&lt;/li&gt;
&lt;li&gt;Splunk – This application can be used to search, monitor and analyse all your log files to find out what is happening. Don’t currently use it but I have tried it out in the past.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What is your favourite DevOps tool? Why not leave a comment below?&lt;/p&gt;</description></item><item><title>Automatic Git Tagging</title><link>https://blog-test.funkysi1701.com/posts/2016/automatic-git-tagging/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 16 Jun 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/automatic-git-tagging/</guid><category term="DevOps">DevOps</category><category term="SourceControl">SourceControl</category><category term="Git">Git</category><category term="TeamCity">TeamCity</category><description>&lt;p&gt;One of the features of git is the ability to tag a point in my change history with a tag. For a while now I have been manually tagging my code whenever I do a release, so I can easily work out what has changed by doing a diff between two tags.&lt;/p&gt;
&lt;p&gt;Now that I am automating my release process with TeamCity I am thinking about how to manage my tags better.&lt;/p&gt;
&lt;p&gt;TeamCity has a setting called VCS Labeling which comes in very handy.
&lt;img class="img-fluid" alt="TeamCity VCS labelling configuration settings" src="https://blog-test.funkysi1701.com/images/2016/Untitled.jpg" loading="lazy"
width="1595" height="580"
/&gt;
&lt;/p&gt;
&lt;p&gt;Configuring it is fairly simple as it only has three settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VCS root to label&lt;/strong&gt;: This is obviously the url to your git repository
&lt;strong&gt;Labeling pattern&lt;/strong&gt;: This is the text of the label to be added.
&lt;strong&gt;Label successful builds only&lt;/strong&gt;: Do you really want to add a tag if the build failed?&lt;/p&gt;
&lt;p&gt;A tag needs to have a unique name, so adding a tag just called &lt;strong&gt;deployed&lt;/strong&gt; won’t work. When I used to add tags manually I used the naming convention of &lt;strong&gt;deployedyyyymmdd&lt;/strong&gt;. While this naming convention is possible with TeamCity I use something a bit more complex to provide more information about what has been deployed.&lt;/p&gt;
&lt;p&gt;TeamCity provides lots of parameters that can be used in your build steps and also in the Labeling pattern box. I started off using &lt;strong&gt;deployed-build-%system.build.number%&lt;/strong&gt; as my tag which just marks git with the TeamCity build number.&lt;/p&gt;
&lt;p&gt;When I run a TeamCity deployment I don’t always use the same configuration options, I deploy locally, to a test server or to production and sometimes I just deploy the frontend or the backend. How cool would it be to include this information in the tag text?&lt;/p&gt;
&lt;p&gt;Well the next step was to change my Labeling pattern to &lt;strong&gt;deployed-build-%system.build.number%-%ServerName%-%DatabaseName%-%FrontEndPath%&lt;/strong&gt;, this adds the backend database config settings and the path the frontend was deployed to. Now when looking at git you can see commits marked with multiple tags, one for each deployment that succeeded and the tag will indicate the settings used during that deployment.&lt;/p&gt;
&lt;p&gt;Now I will never forget to add the tag after a release as the adding of a tag is part of the deployment process, if the deployment fails the tag won’t be added. I can test my deployment to test and git will show if this has been successful, and when I deploy live this will also show up.&lt;/p&gt;
&lt;p&gt;How do you use tags? Do you mark successful builds with a tag? Why not let me know or leave a comment below.&lt;/p&gt;</description></item><item><title>I’m 100 blog posts old</title><link>https://blog-test.funkysi1701.com/posts/2016/i-m-100-blog-posts-old/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 02 Jun 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/i-m-100-blog-posts-old/</guid><category term="100">100</category><category term="Blogging">Blogging</category><description>&lt;p&gt;That’s right this is the one hundredth post that I have written on this blog.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="100-posts-old-L-fwCF_f" src="https://blog-test.funkysi1701.com/images/2016/100-posts-old-L-fwCF_f-300x247.jpeg" loading="lazy"
width="300" height="247"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So what have I learned in the past 100 posts?&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It is easier to write a blog before you become a parent. More recently I am increasingly finding it difficult to find the time to blog. It used to be that I could write on an evening, but now James is around I often prefer to play with him, or more often stop him crawling where he shouldn’t.&lt;/li&gt;
&lt;li&gt;I like my job. The inspiration for most of this site is my day job and as you can read, I do a wide variety of different things, but I have a lot more to learn as well.&lt;/li&gt;
&lt;li&gt;Finding your niche is hard. 100 posts in and I am still not sure what my niche is. I started out with the broad niche of IT and what I do, I then considered something about IT and fatherhood but I don’t think that topic is really me. My current thinking is maybe DevOps especially as my role these days fits squarely between Development and Operations.&lt;/li&gt;
&lt;li&gt;Its time for a refresh. I have been meaning to change the theme of this site for some time and I feel after 100 posts now is as good as time as any. I want to emphasise my skills and what I am learning and increase the emphasis on DevOps, which I think will be my niche.&lt;/li&gt;
&lt;li&gt;Watching visitor numbers is addictive. Every day I look at how many people have looked at my blog, but I have yet to see a pattern between what I write and how many reads I get. Is my writing getting better? I don’t know. Are more people reading? Probably not. Will I keep going? Yes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;So what is next?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hopefully a refreshed look in the next few months. Hopefully regular posts. If there is something you want to see on here drop me a message via any of the social media links or put a comment below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is my favourite post?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Maybe &lt;a href="https://www.funkysi1701.com/posts/2015/user-groups-and-f/" target="_blank" rel="noopener noreferrer"&gt;User Groups and F#&lt;/a&gt;
which proved very popular and got me to start going to user groups something I still enjoy today. I also like &lt;a href="https://www.funkysi1701.com/posts/2016/coding-myself-into-a-corner/" target="_blank" rel="noopener noreferrer"&gt;Coding Myself Into A Corner&lt;/a&gt;
which got me to start thinking more if I was giving myself future problems. But there are many others I like such as &lt;a href="https://www.funkysi1701.com/posts/2015/baby-magic-and-becoming-a-father/" target="_blank" rel="noopener noreferrer"&gt;James and Becoming a father&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>TNG Brothers S4 E3: Battle Bridge</title><link>https://blog-test.funkysi1701.com/posts/2016/brothers-tng-s4-e3-review-battle-bridge/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 26 May 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/brothers-tng-s4-e3-review-battle-bridge/</guid><category term="StarTrek">StarTrek</category><category term="Trekmate">Trekmate</category><category term="Podcast">Podcast</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/Noonian_Soong_2367.jpg"/><description>&lt;p&gt;My latest podcast can be found at &lt;a href="https://www.trekmate.org.uk/brothers-tng-s4-e3-review-the-battle-bridge/" target="_blank" rel="noopener noreferrer"&gt;https://www.trekmate.org.uk/brothers-tng-s4-e3-review-the-battle-bridge/&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Data jeopardizes an emergency mission to save an ill child when he gets a signal from his creator.&lt;/p&gt;
&lt;p&gt;Today James and Lou discuss (Brothers) and what we think of it, with tonight’s guest host Simon Foster, Funky Si.&lt;/p&gt;
&lt;p&gt;Credit: Main Title Theme (TV Edit) was arranged by &lt;a href="https://memory-alpha.fandom.com/wiki/Dennis_McCarthy" target="_blank" rel="noopener noreferrer"&gt;Dennis McCarthy&lt;/a&gt;
and composed by &lt;a href="https://memory-alpha.fandom.com/wiki/Jerry_Goldsmith" target="_blank" rel="noopener noreferrer"&gt;Jerry Goldsmith&lt;/a&gt;
and &lt;a href="https://memory-alpha.fandom.com/wiki/Alexander_Courage" target="_blank" rel="noopener noreferrer"&gt;Alexander Courage&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Running Windows on Raspberry Pi</title><link>https://blog-test.funkysi1701.com/posts/2016/windows-10-raspberry-pi-3/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 05 May 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/windows-10-raspberry-pi-3/</guid><category term="C-Sharp">C-Sharp</category><category term="RaspberryPi">RaspberryPi</category><category term="VisualStudio">VisualStudio</category><description>&lt;p&gt;Last year you may remember me talking about playing with a Raspberry Pi. Well since then my Raspberry Pi has been sat on a desk collecting dust.&lt;/p&gt;
&lt;p&gt;This week I attended Leeds Sharp and the topic was &lt;strong&gt;Running Windows on Raspberry Pi&lt;/strong&gt; and this has inspired me again to do something with a Pi.&lt;/p&gt;
&lt;p&gt;But first what did I learn.&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Here are a couple more of pics of last nights &lt;a href="https://twitter.com/LeedsSharp?ref_src=twsrc%5Etfw"&gt;@LeedsSharp&lt;/a&gt; &lt;a href="https://t.co/QvlsYjNFvB"&gt;https://t.co/QvlsYjNFvB&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/RaspberryPi?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#RaspberryPi&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/MSIoT?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#MSIoT&lt;/a&gt; &lt;a href="https://t.co/60o4wiiPSv"&gt;pic.twitter.com/60o4wiiPSv&lt;/a&gt;&lt;/p&gt;&amp;mdash; Richard Tasker 🇬🇧 (@ritasker) &lt;a href="https://twitter.com/ritasker/status/725970415189909504?ref_src=twsrc%5Etfw"&gt;April 29, 2016&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;I had heard that a cut down version of Windows 10 could be installed on the newer Raspberry Pi’s, but I hadn’t really understood how cut down the version of windows is. Having now seen it demonstrated the OS consists of a single page with a few menu options.&lt;/p&gt;
&lt;p&gt;The real power of Windows 10 IoT is when you connect remotely to it. There are a couple of ways to do this, PowerShell (check out &lt;a href="https://github.com/MicrosoftDocs/windows-iotcore-docs/blob/main/windows-iotcore/manage-your-device/CommandLineUtils.md" target="_blank" rel="noopener noreferrer"&gt;https://github.com/MicrosoftDocs/windows-iotcore-docs/blob/main/windows-iotcore/manage-your-device/CommandLineUtils.md&lt;/a&gt;
for a few commands), and of course connecting Visual Studio to your Pi.&lt;/p&gt;
&lt;p&gt;When I had previously played with a Pi, it had been with bash scripts and linux commands. The beauty of installing Windows IoT is that you can write c# code, something I do in my day job so theoretically I should find it easier.&lt;/p&gt;
&lt;p&gt;The demonstration at Leeds Sharp was pretty impressive. If you are a fan of the Big Bang Theory you may recall Sheldon playing a Theremin. Well it is actually possible to construct a Theremin from a couple of sensors and a Raspberry Pi. The code for which is on &lt;a href="https://github.com/ritasker/IoTDemos" target="_blank" rel="noopener noreferrer"&gt;github&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Now that I have been inspired what shall I do?&lt;/p&gt;
&lt;p&gt;My Raspberry Pi won’t support Windows 10 IoT, so I need to buy the latest version. I am thinking of buying a kit so I can play about with a breadboard, LEDs and resistors. Maybe not build a robot straight away but certainly try doing something that connects to the GPIO pins.&lt;/p&gt;
&lt;p&gt;If you have any suggestions leave a comment below.&lt;/p&gt;</description></item><item><title>Exchange Web Services</title><link>https://blog-test.funkysi1701.com/posts/2016/exchange-web-services/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 21 Apr 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/exchange-web-services/</guid><category term="EWS">EWS</category><category term="MVC">MVC</category><category term="Exchange">Exchange</category><description>&lt;p&gt;Where I work we use a really old fashioned way of recording where in the country employees are: Excel!&lt;/p&gt;
&lt;p&gt;For years I have been trying to persuade staff to use calendars in Exchange. Outlook is great for looking at one or two people’s calendars at once but quickly gets unmanageable for looking at ten or more peoples availability.&lt;/p&gt;
&lt;p&gt;Recently I have started looking into how easy it is to query this information to give a custom view.&lt;/p&gt;
&lt;p&gt;Microsoft provide an API to query exchange information called Exchange Web Services or EWS. I have only used EWS with my Exchange 2010 setup, but the documentation mentions working with Exchange 2007 and older or Exchange online.&lt;/p&gt;
&lt;p&gt;Here are the basics of what I have tried. Fire up Visual Studio and from nuget install EWS.&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-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Install-Package Microsoft.Exchange.WebServices
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I started off with a simple Console App to see how it all worked, and then extended it to a MVC website. I found querying exchange directly was slow, but it is easy enough to cache information in a database.&lt;/p&gt;
&lt;p&gt;To start you need to create an Exchange Service object, by specifying the version of Exchange you are using.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExchangeService service = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ExchangeService(ExchangeVersion.Exchange2010);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next you need to pass the URL you are using to access Exchange.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;service.Url = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Uri(&lt;span style="color:#e6db74"&gt;&amp;#34;mail.example.com&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To access information from exchange you need to pass some Exchange credentials, ideally a username and password that has access to view all the calendars you want to look at.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;service.Credentials = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; WebCredentials(&lt;span style="color:#e6db74"&gt;&amp;#34;username&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;password&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next pass the email address of the user who owns the calendar you want to look at.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;service.ImpersonatedUserId = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ImpersonatedUserId(ConnectingIdType.SmtpAddress, &lt;span style="color:#e6db74"&gt;&amp;#34;me@example.com&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My particular exchange server has a self signed SSL certificate which is not going to be trusted by remote clients. The following line ignores this validation check and makes my program connect.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;System.Net.ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =&amp;gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have connected to exchange we just need a few lines to look for events in the calendars.&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Initialize the calendar folder object with only the folder ID.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CalendarFolder calendar = CalendarFolder.Bind(service, WellKnownFolderName.Calendar, &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; PropertySet());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Set the start and end time and number of appointments to retrieve.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CalendarView cView = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; CalendarView(startDate, endDate);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Limit the properties returned to the appointment&amp;#39;s subject, start time, and end time.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cView.PropertySet = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Retrieve a collection of appointments by using the calendar view.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FindItemsResults&amp;lt;Appointment&amp;gt; appointments = calendar.FindAppointments(cView);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that you have an appointments object you can loop through each element with a foreach loop. In my case I assign each elements Subject to a variable, which I can then do what I like with (display in a console window, save to a database, display in an MVC website.)&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (Appointment a &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; appointments)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (a.Subject != &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; subject += a.Subject.ToString();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My website queries a SQL database which I can easily populate with a console app that runs at regular intervals throughout the day.&lt;/p&gt;
&lt;p&gt;There is a lot more I want to do with this project as this is only the basics of what you can do with Exchange Web Services. So expect more blog posts on this subject as I expand its functionality and learn new ways of doing things.&lt;/p&gt;</description></item><item><title>Revisiting Team City</title><link>https://blog-test.funkysi1701.com/posts/2016/revisiting-teamcity/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 24 Mar 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/revisiting-teamcity/</guid><category term="CI">CI</category><category term="DevOps">DevOps</category><category term="SourceControl">SourceControl</category><description>&lt;p&gt;Last year I blogged about &lt;a href="https://www.funkysi1701.com/posts/2015/teamcity/" target="_blank" rel="noopener noreferrer"&gt;Team City&lt;/a&gt;
, well I have been looking at it again recently. In that time they have even changed their logo!&lt;/p&gt;
&lt;p&gt;Lets start with thinking about what I want my Continuous Integration server to do.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check out my code from source control (usually master but all feature branches would be even better)&lt;/li&gt;
&lt;li&gt;Configure specific setting for build&lt;/li&gt;
&lt;li&gt;Build my code&lt;/li&gt;
&lt;li&gt;Build my databases&lt;/li&gt;
&lt;li&gt;Run any unit tests&lt;/li&gt;
&lt;li&gt;(Optional) Run deployment to Azure Test/Live site&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are probably other things I want to achieve but I will start with these six.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Checking out code from source control is something Team City does out of the box, so I can safely say I have done this now. It even monitors a branch for changes and initiates a new check out.&lt;/li&gt;
&lt;li&gt;Team City allows you to create specific build steps so in theory you can have multiple builds for every variation of settings that you want for your code. I have not tried this yet apart from building with the default config, but I don’t expect it will be too difficult.&lt;/li&gt;
&lt;li&gt;I have managed to get my code to build with Team City, it took a bit of tweaking the different build steps but wasn’t too difficult. Team City has a visual studio build agent which takes you solution file and does what it needs to. The one problem I have found with this step is that I get errors with my tests if I select a Debug config instead of Release.&lt;/li&gt;
&lt;li&gt;Databases are always the problem part of the deployment. So far I have manually deployed my databases but I intend on revisit this step. A &lt;a href="https://stackoverflow.com/questions/21555038/how-can-i-execute-sql-scripts-using-teamcity" target="_blank" rel="noopener noreferrer"&gt;stackoverflow&lt;/a&gt;
post suggests that I can run SQL code via Team City in the following way by creating a command line executable:&lt;/li&gt;
&lt;/ol&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Command executable: c:&lt;span style="color:#ae81ff"&gt;\P&lt;/span&gt;rogram Files&lt;span style="color:#ae81ff"&gt;\M&lt;/span&gt;icrosoft SQL Server&lt;span style="color:#ae81ff"&gt;\1&lt;/span&gt;00&lt;span style="color:#ae81ff"&gt;\T&lt;/span&gt;ools&lt;span style="color:#ae81ff"&gt;\B&lt;/span&gt;inn&lt;span style="color:#ae81ff"&gt;\s&lt;/span&gt;qlcmd.exe
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Command parameters: -S &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ServerName&lt;span style="color:#f92672"&gt;]&lt;/span&gt; -i &lt;span style="color:#f92672"&gt;[&lt;/span&gt;PathToSQLScript&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have yet to try this but I am hopefully that it will just work. Dropping a database and restoring a back and then running different SQL scripts is all possible from TSQL, so I should be OK. Watch this space for more details.&lt;/p&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Running the unit tests got me stuck for a while. I tried setting it up using VSTest or MSTest neither worked mainly because a config file wasn’t being copied with the test binaries. When I tried using NUnit it just worked. The tests that failed gave me a few config settings to change.&lt;/li&gt;
&lt;li&gt;I have powershell scripts that deploy to Azure websites, I think that these could form the basis of a deployment to Azure. Again the difficult step here may end up being deploying all the different databases to Azure. This is also the riskiest step as I need to connect to live servers which is why I will leave this to last, at the very least I could generate scripts that do a full deployment.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s it for now. Once I have this all working I will revisit again with details of the database steps as I am expecting a few challenges to overcome. What have you used a CI Server for? Are there other things I want to achieve from a project like this? Why not contact me or leave a comment below&lt;/p&gt;</description></item><item><title>Model View Controller (MVC)</title><link>https://blog-test.funkysi1701.com/posts/2016/model-view-controller-mvc/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 17 Mar 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/model-view-controller-mvc/</guid><category term="MVC">MVC</category><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Model View Controller software architecture diagram" src="https://blog-test.funkysi1701.com/images/2016/27.jpg" loading="lazy"
width="327" height="314"
/&gt;
&lt;/p&gt;
&lt;p&gt;Model View Controller or MVC is a software architectural pattern for implementing user interfaces on computers. It divides a given software application into three interconnected parts, so as to separate internal representations of information from the ways that information is presented to or accepted from the user.&lt;/p&gt;
&lt;p&gt;I have been trying to get my head around the concept of MVC for a while, hopefully writing this article will help solidify my understanding of it.&lt;/p&gt;
&lt;p&gt;One of the core concepts of MVC is the ability to separate concerns so you can concentrate your energies on one aspect of the application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Model&lt;/strong&gt; This is the data. If your application uses a database the model often mirrors what you have in the database and concerns itself retrieving information from the database.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View&lt;/strong&gt; This concerns itself with displaying the data to the user. Typically this is the html pages of your application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controller&lt;/strong&gt; This concerns itself with actually doing things and deals with user interaction. Typically it will get data from the view and send data to the model.&lt;/p&gt;
&lt;p&gt;The three concerns can be developed in isolation as they do not depend on each other, for larger development teams you can even divide up development much easier that a traditional app.&lt;/p&gt;
&lt;p&gt;The basic concept of MVC I get and understand, however I find myself getting bogged down in the details.&lt;/p&gt;
&lt;p&gt;The database doesn’t matter. I need to remember this and not get sidetracked in writing custom methods to connect to the database which end up unmanageable. I know SQL, so can easily write SQL commands to copy data into the format I need for my app. The app I am currently working on involves a large amount of existing data, and I need to concentrate on the MVC parts and worry about the database later.&lt;/p&gt;
&lt;p&gt;In previous attempts I have tried to build my model against many tables, but instead I can write a query against many tables and insert that into one table which the Model can then use.&lt;/p&gt;
&lt;p&gt;Changing the model often results in an error informing you that the context has changed since the database was created. The easy solution to this in my case is to drop the database and allow entity framework to recreate the database each time. As long as my database contains no new data, I won’t loose anything.&lt;/p&gt;
&lt;p&gt;One of the core advantages of MVC is the ability to test it or even use test driven development (TDD). I haven’t really dabbled with testing yet as I am still trying to get my head around the fundamentals, but once I have made some progress with my app I want to test, so next time I get asked to add a new feature I have no fear about breaking stuff.&lt;/p&gt;
&lt;p&gt;For the first time I have got an app with a working Authentication system from the start. And it is remarkably easy to implement with one keyword. Adding &lt;strong&gt;[Authorize]&lt;/strong&gt; to the top of your controller is all that is needed. Building the actual Authentication system is relatively easy from Visual Studio, as it has templates for Azure AD, Forms Based, Open Auth like google/twitter etc.&lt;/p&gt;
&lt;p&gt;It is still very early days for my MVC app and my understanding of it, but I feel I have turned the corner and can actually build something with it now, rather than be stuck in a downward spiral of confusion.&lt;/p&gt;
&lt;p&gt;What do you think about MVC why not leave a comment below? For more info about MVC I have been looking at &lt;a href="https://dotnet.microsoft.com/en-us/apps/aspnet" target="_blank" rel="noopener noreferrer"&gt;https://dotnet.microsoft.com/en-us/apps/aspnet&lt;/a&gt;
which has more information and tutorials.&lt;/p&gt;</description></item><item><title>Surface Book Review</title><link>https://blog-test.funkysi1701.com/posts/2016/surface-book-review/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 10 Mar 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/surface-book-review/</guid><category term="Laptop">Laptop</category><category term="Hardware">Hardware</category><category term="Technology">Technology</category><category term="Microsoft">Microsoft</category><category term="Windows">Windows</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/en-INTL-PDP0-Surface-Book-CR9-00001-P2.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Microsoft Surface Book laptop with detachable keyboard" src="https://blog-test.funkysi1701.com/images/2016/en-INTL-PDP0-Surface-Book-CR9-00001-P2.jpg" loading="lazy"
width="780" height="400"
/&gt;
I have just bought myself a new laptop, but it is not just any laptop it is a &lt;a href="https://www.microsoft.com/en-gb/store/d/product/8TXJ08Q9LXDT" target="_blank" rel="noopener noreferrer"&gt;Microsoft Surface Book&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;I think this is probably the first time I have bought myself a top of the range laptop and after a few days of use I am loving it.&lt;/p&gt;
&lt;p&gt;The Surface Book is the latest in Microsoft’s Surface line of tablets but the first to feature a keyboard and be more like a traditional laptop. The keyboard is detachable from the keyboard so you can use the Surface Book like a tablet.&lt;/p&gt;
&lt;p&gt;As it is a top of the range laptop, it was not cheap, so if price is a significant factor in your laptop choice this is not the machine for you. Microsoft are trying to compete with Apple’s Macbook range.&lt;/p&gt;
&lt;p&gt;So what did I get for my money:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 10 Pro&lt;/li&gt;
&lt;li&gt;16Gb RAM&lt;/li&gt;
&lt;li&gt;512Gb SSD (Formatted Size nearer 474Gb)&lt;/li&gt;
&lt;li&gt;6th Generation Intel Core i7 Processor&lt;/li&gt;
&lt;li&gt;Surface Pen&lt;/li&gt;
&lt;li&gt;13.5-inch touch screen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have only had the device for a few days but these are my thoughts so far. My primary reason for buying this is for doing development work with Visual Studio and SQL Server.&lt;/p&gt;
&lt;p&gt;I really like the Surface Pen. This is a feature that I didn’t think I would use much. The Pen connects via bluetooth and allows interaction with the touch screen. The pressure sensitive screen allows all sort of touch actions to be performed.&lt;/p&gt;
&lt;p&gt;I especially like the choice of keyboards that are offered when the physical keyboard is detached. You can have either a on screen keyboard which you can type with pen or fingers, an on screen keyboard that splits in half or you can write with the pen. This is an amazing feature. My handwriting is not good but most of the time it understands my scrawl. With this option you can hand write a tweet or fill in a form on a webpage. For speed I would not recommend this form of input for large amounts of text, but for browsing the web of when you are just clicking on links it is great.&lt;/p&gt;
&lt;p&gt;Windows Hello – I can unlock windows just by looking at my screen. How cool is that! It was really easy to setup, it just takes a photo of your face and next time you login all you need to do it look at the screen. Note if you are working in tablet mode, make sure the tablet is the correct way up.&lt;/p&gt;
&lt;p&gt;It’s not all brilliant though. Detaching the screen is fiddly and sometimes takes a few moments to do. A few times I have felt I needed another hand but I am sure the more I do this the easier I will find it to do.&lt;/p&gt;
&lt;p&gt;Battery life isn’t great especially when running off the tablet only. This is due to the machine having two batteries, one in the base and one in the screen so with keyboard attached you have much longer use times. Actually I am finding the battery is lasting longer now that I have used it for a few days.&lt;/p&gt;
&lt;p&gt;The screen has a very high resolution 3000 x 2000 but using clever zooming technology everything is still readable and not tiny. However I use Remote Desktop a lot and this caused me a problem. When RDPing the remote session used the host screen resolution which made everything tiny on my servers. The solution to this can be found on &lt;a href="https://superuser.com/questions/891413/remote-connection-desktop-manager-2-7-does-not-support-dpi-scaling-anymore" target="_blank" rel="noopener noreferrer"&gt;SuperUser&lt;/a&gt;
and involved using Microsoft’s Remote Desktop Connection Manager, a cool bit of software for managing multiple RDP sessions. This is actually an improvement on the way I usually work, but until I found the answer this was annoying.&lt;/p&gt;
&lt;p&gt;Another minor annoyance with the keyboard is that you can’t press Ctrl-Alt-Del with one hand. Normally this isn’t a requirement but if the screen locks while I have my son on my lap I am stuck, but I won’t blame the surface book for this.&lt;/p&gt;
&lt;p&gt;When I got my Surface Book I was also given a Microsoft Wireless Display Adapter. I am not a fan of this bit of tech as I can’t get it to work. I briefly got my old laptop to connect but my Surface Book keeps telling me NO!&lt;/p&gt;
&lt;p&gt;Overall I like the Surface Book. It is certainly the nicest laptop I have ever used. Now that I have the docking station I can connect two monitors, have a wired internet connection and it becomes a proper work horse. What does everyone else think? Better than Apple’s range of laptops?&lt;/p&gt;</description></item><item><title>Trying Out Azure Active Directory</title><link>https://blog-test.funkysi1701.com/posts/2016/trying-out-azure-active-directory/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 03 Mar 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/trying-out-azure-active-directory/</guid><category term="ActiveDirectory">ActiveDirectory</category><category term="Azure">Azure</category><category term="Authentication">Authentication</category><category term="AzureActiveDirectory">AzureActiveDirectory</category><category term="DevOps">DevOps</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2016/arch.png"/><description>&lt;p&gt;One of my plans is to create new MVC Webapps for my companies databases. Once I publish these I will need to secure them so only staff have access.&lt;/p&gt;
&lt;p&gt;The traditional way to do this would be insert membership tables into my database. The user then has to remember another username and password and I have to secure the storage of these credentials. Lots of work for everyone.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Diagram comparing traditional membership tables with Azure Active Directory authentication" src="https://blog-test.funkysi1701.com/images/2016/arch.png" loading="lazy"
width="600" height="430"
/&gt;
&lt;/p&gt;
&lt;p&gt;There is a better way by using Azure Active Directory. You have probably heard of Active Directory, if you are a SysAdmin you probably use it all the time to manage your corporate users and computers. Azure Active Directory is an extension of this into the Cloud.&lt;/p&gt;
&lt;p&gt;I have blogged in the past about using Azure but this is the first time I have tried connecting my internal domain to Azure. There is a &lt;a href="https://vlabs.holsystems.com/vlabs/technet?eng=VLabs&amp;amp;auth=external&amp;amp;src=vlabs&amp;amp;altadd=true&amp;amp;labid=13535" target="_blank" rel="noopener noreferrer"&gt;Virtual Lab&lt;/a&gt;
which helped me try out some of these ideas.&lt;/p&gt;
&lt;p&gt;The first thing I did was to create a new Directory in Azure. I did this via the old portal (&lt;a href="https://manage.windowsazure.com/" target="_blank" rel="noopener noreferrer"&gt;manage.windowsazure.com&lt;/a&gt;
) it might be possible via the new portal but I don’t know how yet.&lt;/p&gt;
&lt;p&gt;Click New, select App Services &amp;gt; Active Directory &amp;gt; Directory and select Custom Create. Select Create new directory, give it a name and a domain name and select a region from the drop down. Then add a Global Admin for this directory.&lt;/p&gt;
&lt;p&gt;There is a tool called &lt;a href="https://www.microsoft.com/en-us/download/details.aspx?id=47594" target="_blank" rel="noopener noreferrer"&gt;Azure Active Directory Connect&lt;/a&gt;
. Download and Install this with express settings on one of your domain controllers. You need to specify a domain admin account to access your domain and the Azure Global Admin account you just created.&lt;/p&gt;
&lt;p&gt;At this point I went to bed so I am not sure how long it tool to sync all the domain information but by morning it was all showing in the users list on Azure.&lt;/p&gt;
&lt;p&gt;All my user accounts are showing with a @contoso.onmicrosoft.com, it is possible to use custom domains but I haven’t figured out that step yet. I made a change in my Active Directory and a while later that change was showing in Azure AD.&lt;/p&gt;
&lt;p&gt;So now what? Open up Visual Studio and see if I can use Azure to Authenticate.&lt;/p&gt;
&lt;p&gt;I selected to create a new MVC web project and clicked the change authenticate option. One of the options was Work and School Accounts, I then selected Cloud Single Organization and entered contoso.onmicrosoft.com. I then ran this app and it authenticated using Azure using my domain password. Really impressed at how easy that was.&lt;/p&gt;
&lt;p&gt;The app then shows up on Azure in the old portal. In Applications you can see a list of which users have access to your app and configure few other app related settings.&lt;/p&gt;
&lt;p&gt;This is a long way off being useful in my actual app, but it shows that the basics of what I am trying to do does work. Anyone done anything similar with Azure AD? How did you get on?&lt;/p&gt;</description></item><item><title>Coding myself into a corner</title><link>https://blog-test.funkysi1701.com/posts/2016/coding-myself-into-a-corner/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 25 Feb 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/coding-myself-into-a-corner/</guid><category term="Databse">Databse</category><category term="Access">Access</category><description>&lt;p&gt;I spend an awful lot of my working life adding new features and improvements to a legacy database system.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;legacy&lt;/strong&gt; system is an old method, technology, computer system, or application program, “of, relating to, or being a previous or outdated computer system.” Often a pejorative term, referencing a system as &amp;ldquo;&lt;strong&gt;legacy&lt;/strong&gt;&amp;rdquo; often implies that the system is out of date or in need of replacement.&lt;/p&gt;
&lt;p&gt;My particular legacy system is Microsoft Access. We use Microsoft Access to provide the front end for all our internal databases. The particular technology we use is ADP files which are only supported in Access 2000, 2003 or 2010.&lt;/p&gt;
&lt;p&gt;Microsoft has already dropped support for Access 2000 and 2003, and support for 2010 is due to be dropped in 2020.&lt;/p&gt;
&lt;p&gt;So why am I coding myself into a corner? Its simple for every feature or improvement I create in Access, I increase the amount of features I need to create or port to a new front end.&lt;/p&gt;
&lt;p&gt;This is a very depressing thought, everything I create will need creating again. I am not saving myself work but increasing the amount of work I need to do again.&lt;/p&gt;
&lt;p&gt;The bad news is that my employers like almost all businesses demand results and like a good employee I have been delivering them. I have been promised the mythical “when we are quiet” you can work on rebuilding the database front end. I know this will likely never happen so what are my options.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do nothing&lt;/strong&gt; I have warned my managers that this work needs doing and it is up to them to give me the resources I need. This is not an acceptable option. Firstly I am not future proofing the business, 2020 will be here before we know it. Also I am not developing myself as a developer, as the only experience I am getting is with Legacy technology that has expired or will do very soon. No one wants to employ someone who only has legacy experience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do something&lt;/strong&gt; I need to keep delivering results and doing what is asked of me. Like any good engineer I should be multiplying my estimates by four, meaning that I have some time that can be used for looking at the bigger picture. This is a win-win option really. Employer gets a solution that is future proof, Employee gets valuable experience in up to date technology.&lt;/p&gt;
&lt;p&gt;What do you think? Have you been tied to legacy technology? Why not leave a comment below.&lt;/p&gt;</description></item><item><title>Trek review: Best of Both Worlds</title><link>https://blog-test.funkysi1701.com/posts/2016/star-trek-episode-review-the-best-of-both-worlds/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 18 Feb 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/star-trek-episode-review-the-best-of-both-worlds/</guid><category term="StarTrek">StarTrek</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/Picard_kidnapped_by_the_Borg.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Captain Picard assimilated by the Borg as Locutus of Borg" src="https://blog-test.funkysi1701.com/images/2016/Picard_kidnapped_by_the_Borg.jpg" loading="lazy"
width="1000" height="865"
/&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Episode Title: &lt;strong&gt;The Best of Both Worlds&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Star Trek Type: TNG&lt;/li&gt;
&lt;li&gt;Original Air Date: 18 June 1990 &amp;amp; 24 September 1990&lt;/li&gt;
&lt;li&gt;Written By: Michael Piller&lt;/li&gt;
&lt;li&gt;Directed By: Cliff Bole&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Borg threaten the Federation, when they kidnap Captain Picard and destroy a fleet of 39 Starships. Luckily some original thinking from Commander Riker and Lieutenant Commander Shelby saves the Federation from assimilation.&lt;/p&gt;
&lt;p&gt;Thoughts: I love this episode! It is probably my favourite episode in the whole of trek. I can’t think of a single scene which I don’t like.&lt;/p&gt;
&lt;p&gt;It is a two parter that actually works best as a two parter. The moment that Riker orders the Enterprise to fire on the Borg is great. At the time some thought that Patrick Stewart might leave the show and be replaced by Riker/Shelby. I am very glad that didn’t happen but it is interesting to ponder what that might be like.&lt;/p&gt;
&lt;p&gt;The Borg soundtrack in this episode is great. Ron Jones really captures the spooky threat that the Borg are. I was always disappointed that some of that didn’t continue in First Contact and when the Borg return in Voyager.&lt;/p&gt;
&lt;p&gt;The episode has a cracking pace. From the moment the Borg first attack the Enterprise to the moment the Borg ship explodes the show doesn’t slow down.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;I am Locutus… of Borg. Resistance… is futile.
Your life, as it has been… is over. From this time forward… you will service… us.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Commander Shelby is a great character that enhances the episode and introduces conflict between characters, particularly Riker.&lt;/p&gt;
&lt;p&gt;I have heard that Riker’s thoughts about his career was a mirror to writer Michael Piller’s thoughts about leaving the show. Luckily for us he stayed.&lt;/p&gt;
&lt;p&gt;In a future episode of DS9 Worf comments that he felt there was nothing that they couldn’t do during this time. I have to agree the tag team of him and Data is a great one. If I want rescuing it would be Data and Worf that I would want.&lt;/p&gt;
&lt;p&gt;My good friends at &lt;a href="https://www.trekmate.org.uk/the-best-of-both-worlds-tng-s3-e26-review-the-battle-bridge/" target="_blank" rel="noopener noreferrer"&gt;Trekmate&lt;/a&gt;
have just reviewed part one, why not have a listen?&lt;/p&gt;
&lt;p&gt;The Best of Both Worlds along with all 900+ Star Trek episodes is now available in &lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>My git repository is too large!</title><link>https://blog-test.funkysi1701.com/posts/2016/my-git-repository-is-too-large/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 11 Feb 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/my-git-repository-is-too-large/</guid><category term="Git">Git</category><category term="SourceControl">SourceControl</category><description>&lt;p&gt;Today I did a clone of one of my git repositories and it took ages to download. Looking into what got downloaded it was easy to see why. The .git folder was over 500Mb in size.&lt;/p&gt;
&lt;p&gt;I know how this has happened. This repository was created in 2013 and has been used by me as a dumping ground for lots of things related to the code which never should have been committed.&lt;/p&gt;
&lt;p&gt;Since 2013 I have learnt a lot more about coding and git so the current version of the files in git isn’t too bad. But git keeps the history of changes for every file so bad practices like this are kept.&lt;/p&gt;
&lt;p&gt;What can I do about this? Well what does google suggest? I found this &lt;code&gt;https://stevelorek.com/how-to-shrink-a-git-repository.html&lt;/code&gt; (link no longer exists).&lt;/p&gt;
&lt;p&gt;It suggests ways of listing all the large files that are stored in git and a way to remove them. As I am the only person that regularly commits to this repository I see no problem with giving it a go.&lt;/p&gt;
&lt;p&gt;I will summarise the steps here.&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone url
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you need all the remote branches so there is a bash script to run&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; branch in &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;git branch -a | grep remotes | grep -v HEAD | grep -v master&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git branch –track &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;branch##*/&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; $branch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another bash script then lists the top 10 large files&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#set -x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Shows you the largest objects in your repo’s pack file.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Written for osx.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @see https://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @author Antony Stubbs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# set the internal field spereator to line break, so that we can iterate easily over the verify-pack output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IFS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$’&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;’;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# list all objects including their size, sort by size, take top 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;objects&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo “All sizes are in kB. The pack column is the size of the object, compressed, inside the pack file.”
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output&lt;span style="color:#f92672"&gt;=&lt;/span&gt;“size,pack,SHA,location”
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; y in $objects &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# extract the size in bytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$((&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;echo $y | cut -f &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; -d ‘ ‘&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# extract the compressed size in bytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;compressedSize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$((&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;echo $y | cut -f &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; -d ‘ ‘&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# extract the SHA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sha&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;echo $y | cut -f &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; -d ‘ ‘&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# find the objects location in the repository tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;other&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;git rev-list –all –objects | grep $sha&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#lineBreak=`echo -e “\n”`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output&lt;span style="color:#f92672"&gt;=&lt;/span&gt;“&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;size&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;compressedSize&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;other&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;”
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo -e $output
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After running the script you will see details of your largest files. I had *.msi and *.exe files in the mix. To remove them run the following, where filename is the path to the file that needs removing.&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git filter-branch –tag-name-filter cat –index-filter ‘git rm -r –cached –ignore-unmatch filename’ –prune-empty -f — –all
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To reclaim the disk space run the following commands&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rm -rf .git/refs/original/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git reflog expire –expire=now –all
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git gc –prune=now
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git gc –aggressive –prune=now
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now push your changes back to the remote server.&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-txt" data-lang="txt"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push origin –force –all
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push origin –force –tags
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if you do a clone it will be much smaller than before and you can get back to coding much quicker, without having to wait.&lt;/p&gt;</description></item><item><title>SQL Transaction Log Backups</title><link>https://blog-test.funkysi1701.com/posts/2016/transaction-log-backups/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 04 Feb 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/transaction-log-backups/</guid><category term="Database">Database</category><category term="SQL">SQL</category><category term="Backups">Backups</category><description>&lt;p&gt;Like many DBAs I spend a lot of time maintaining my SQL Server backups.&lt;/p&gt;
&lt;p&gt;From SQL Server I maintain both full backups and transaction log backups. I have often restored my full backups but until recently I have never restored a transaction log backup. All backup strategy’s are only as good as the last time you tested the restore process.&lt;/p&gt;
&lt;h2 id="so-what-is-a-transaction-log-backup"&gt;So what is a transaction log backup?&lt;a class="anchor ms-1" href="#so-what-is-a-transaction-log-backup" aria-label="Permalink: So what is a transaction log backup?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A transaction log backup contains all the transaction log records generated since the last full backup and is used to allow the database to be recovered to a specific point in time (usually the time right before a disaster strikes). Since these are incremental, if you want to restore the database to a particular point in time, you need to have all the transaction log records necessary to replay database changes up to that point in time.&lt;/p&gt;
&lt;h2 id="how-to-do-the-restore"&gt;How to do the restore.&lt;a class="anchor ms-1" href="#how-to-do-the-restore" aria-label="Permalink: How to do the restore."&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First right click on Databases in SQL Management Studio and select restore database. You should then get a screen similar to this.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="SQL Server Management Studio restore database dialog" src="https://blog-test.funkysi1701.com/images/2016/restore1.jpg" loading="lazy"
width="878" height="732"
/&gt;
&lt;/p&gt;
&lt;p&gt;In source click the &amp;hellip; to allow you to select your backup files.&lt;/p&gt;
&lt;p&gt;Now normally I have only ever selected one file here, the *.bak file. Instead select the *.bak and all the *.trn files as well. After SQL Server has chugged for a few minutes (time will depend on number of transaction files and server/disk speed etc) the restore plan section should fill up with files.&lt;/p&gt;
&lt;p&gt;In the destination database box, type in the name of the database you want to restore. I recommend using a different name to avoid overwriting the original database, appending Test or a datetime to the name is what I usually do.&lt;/p&gt;
&lt;p&gt;On my test server I need to untick the take tail-log backups option off the options screen before I can execute the restore.&lt;/p&gt;
&lt;p&gt;Now you can either check the tick boxes in the restore plan section or (more fun) click the timeline button to select at what point in time you want to restore to.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="SQL Server point-in-time restore timeline selector" src="https://blog-test.funkysi1701.com/images/2016/restore2.jpg" loading="lazy"
width="797" height="474"
/&gt;
&lt;/p&gt;
&lt;p&gt;You can either select the point in time with your mouse or specify the exact point in the time textbox. Alternatively you can just select the most recent point, probably the most likely option when disaster strikes.&lt;/p&gt;
&lt;p&gt;Now that I have tried doing this on my test server I feel much more confident that when disaster does strike I can get things restored quickly and painlessly.&lt;/p&gt;
&lt;h2 id="how-often-should-you-run-transaction-backups"&gt;How often should you run transaction backups?&lt;a class="anchor ms-1" href="#how-often-should-you-run-transaction-backups" aria-label="Permalink: How often should you run transaction backups?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The answer to this question depends on how critical your data is. Until very recently I ran mine ever 15 minutes, I have increased this to every 5 minutes, but I have seen recommendations of running it &lt;a href="https://www.brentozar.com/archive/2014/02/back-transaction-logs-every-minute-yes-really/" target="_blank" rel="noopener noreferrer"&gt;every minute&lt;/a&gt;
. The more critical your data the more often you should run them.&lt;/p&gt;</description></item><item><title>Development Annoyance</title><link>https://blog-test.funkysi1701.com/posts/2016/development-annoyance/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 29 Jan 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/development-annoyance/</guid><category term="Agile">Agile</category><category term="SQL">SQL</category><category term="Project">Project</category><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Illustration about stopping development annoyance and frustration quickly" src="https://blog-test.funkysi1701.com/images/2016/How-you-can-stop-annoyance-or-frustrations-quickly.jpg" loading="lazy"
width="425" height="282"
/&gt;
&lt;/p&gt;
&lt;p&gt;I spend a lot of my time creating new features that simplify my companies business processes.&lt;/p&gt;
&lt;p&gt;A good example of this is an invoicing system I created. Instead of users working off different spreadsheets and copying and pasting data between various different programs the user can click a couple of buttons and everything is done and they can move on to the next task.&lt;/p&gt;
&lt;p&gt;I am currently expanding this system so more of the companies work can be invoiced quickly and simply.&lt;/p&gt;
&lt;h2 id="i-like-working-on-this-kind-of-problem"&gt;I like working on this kind of problem&lt;a class="anchor ms-1" href="#i-like-working-on-this-kind-of-problem" aria-label="Permalink: I like working on this kind of problem"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I get to discuss with the different departments involved, finding out how they work and what could make their lives better.&lt;/p&gt;
&lt;p&gt;I then get to look at what structures already exist in the database and get to rip out anything that makes no sense (Today I had a Customer table which has a primary key called ClientId – its now a Client table with PK ClientId) and add new structures to store new information.&lt;/p&gt;
&lt;p&gt;I then can build a user interface so the users can interact with the data.&lt;/p&gt;
&lt;p&gt;But the most important part of the process comes next. This is when I show the users what I have built and how it will make their lives better, they can then feed back to me questions and comments. How do I do x?, what about y?, have you thought about z?&lt;/p&gt;
&lt;p&gt;After this very valuable feedback I can go back and tweak what I have done making it better and better until the users think it is suitable for what they need.&lt;/p&gt;
&lt;h2 id="now-why-did-i-call-this-post-development-annoyance"&gt;Now why did I call this post development annoyance?&lt;a class="anchor ms-1" href="#now-why-did-i-call-this-post-development-annoyance" aria-label="Permalink: Now why did I call this post development annoyance?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I find it intensely annoying that after spending weeks of my time working on creating something to be used. Users either make do with my solution and never tell me the one thing that really annoys them or worse they go back to the time consuming process and never feedback the one or two changes I need to make to complete the project.&lt;/p&gt;
&lt;p&gt;Now I am not perfect, like many IT people my people skills are somewhat lacking but apart from asking people what can you do to get the feedback you need to complete the project?&lt;/p&gt;
&lt;p&gt;I do not have the knowledge that other departments have so I consider development a team effort that requires everyone to contribute otherwise it will not finish.&lt;/p&gt;
&lt;p&gt;The second outcome where users return to their old ways is the most annoying. It could well be months or even years before I find out that what I created is not being used any more. By that time my memory of what I did and more importantly why I did what I did has been lost and forgotten.&lt;/p&gt;
&lt;p&gt;So users please, please tell me what works and what doesn’t and what things I can do to improve things. I want my solutions to constantly improve and get better and I can only do that with your help.&lt;/p&gt;</description></item><item><title>Star Trek Episode Review Arena</title><link>https://blog-test.funkysi1701.com/posts/2016/star-trek-episode-review-arena/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 21 Jan 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/star-trek-episode-review-arena/</guid><category term="StarTrek">StarTrek</category><category term="Gorn">Gorn</category><category term="Arena">Arena</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/Gorn.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="The Gorn captain from Star Trek TOS episode Arena" src="https://blog-test.funkysi1701.com/images/2016/Gorn.jpg" loading="lazy"
width="662" height="977"
/&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Episode Title: &lt;strong&gt;Arena&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Star Trek Type: TOS&lt;/li&gt;
&lt;li&gt;Original Air Date: 19 January 1967&lt;/li&gt;
&lt;li&gt;Teleplay: Gene L Coon&lt;/li&gt;
&lt;li&gt;Story By: Frederic Brown&lt;/li&gt;
&lt;li&gt;Directed By: Joseph Pevney&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The episode begins with the Enterprise in orbit of Cestus III. Commodore Travers requests a tactical team join the away team. When the away team beam down Cestus III has been destroyed.&lt;/p&gt;
&lt;p&gt;Spock detects non-human life signs, obviously the aliens that destroyed the outpost. They attack the Enterprise, stranding the away team who are under heavy fire. Sulu is instructed to do whatever he can to protect the Enterprise and leaves orbit.&lt;/p&gt;
&lt;p&gt;Kirk finds the armoury and a grenade launcher, after firing the enemy withdraws.&lt;/p&gt;
&lt;p&gt;After beaming back aboard the Enterprise they pursue the unknown enemy into uncharted space. One of the survivors of Cestus III explains that the enemy attacked without warning.&lt;/p&gt;
&lt;p&gt;Kirk is determined to destroy the enemy ship before it reaches home and the Enterprise prepares for battle.&lt;/p&gt;
&lt;p&gt;An unknown solar system scans the Enterprise as they continue their pursuit of the enemy ship. The enemy ship comes to a complete stop. The Enterprise prepares to attack but before they can they also come to a complete stop. The Metrons have stopped both ships because both ships were on a mission of violence. The captains of both ships will be placed on a planet where the winner can destroy the other.&lt;/p&gt;
&lt;p&gt;Captain Kirk and the enemy captain appear on a desert planet. The enemy is a reptilian like species called the Gorn. The Gorn has superior strength to humans but Kirk manages to escape his first encounter.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;#34;This is Captain James Kirk of the Starship Enterprise.
Whoever finds this, please get it to Starfleet Command.
I’m engaged in personal combat with a creature apparently
called a Gorn. He’s immensely strong. Already,
he has withstood attacks from me that would have
killed a Human being. Fortunately, though strong,
he is not agile. The agility and I hope the cleverness, is mine.&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Metrons said that the planet contained materials to allow the building of a weapon, however at first glance Kirk sees nothing that could help him defeat the much strong Gorn captain. He does find some diamonds, too small to be used as a weapon.&lt;/p&gt;
&lt;p&gt;Kirk pushes a huge boulder over a cliff onto the Gorn captain, which appears to knock him out, however he survives and Kirk barely escapes. Kirk then finds Sulphur, which triggers a memory.&lt;/p&gt;
&lt;p&gt;The Metrons allow the Enterprise to watch the last stages of Kirks struggle. They see Kirk discover Potassium Nitrate. The Gorn accuses the Federation of trespassing into their space.&lt;/p&gt;
&lt;p&gt;Kirk starts constructing a weapon using the diamonds, sulphur and potassium nitrate to make a gunpowder explosion to fire the diamonds at the Gorn captain. Just in time he applies a spark to his weapon and his opponent lies defeated.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Captain Kirk firing his improvised diamond cannon at the Gorn captain" src="https://blog-test.funkysi1701.com/images/2016/Gorn_Kirk_cannon.jpg" loading="lazy"
width="600" height="450"
/&gt;
&lt;/p&gt;
&lt;p&gt;Kirk refused to kill the Gorn captain as they may have been just defending themselves. The Metron announces that Kirk has displayed the advanced trait of mercy and there may be hope for humanity after all.&lt;/p&gt;
&lt;p&gt;Thoughts: I like this episode very much. It has some classic Star Trek ideas in it.&lt;/p&gt;
&lt;p&gt;We have a super powerful alien race (the Metrons) that think there is hope for humanity.&lt;/p&gt;
&lt;p&gt;We have Kirk using raw materials to construct a weapon using simple chemistry.&lt;/p&gt;
&lt;p&gt;We have an enemy race that appears destructive but may have just been defending themselves.&lt;/p&gt;
&lt;p&gt;We have the classic location of Vasquez Rocks, somewhere that if I ever visit the US I have to visit.&lt;/p&gt;
&lt;p&gt;We have the very cheesy Gorn mask, yes its not realistic but the story is strong enough that it doesn’t really matter. Enterprise brought back the Gorn but as a CGI character and I think I may prefer the rubber mask.&lt;/p&gt;
&lt;p&gt;Interestingly the weapon Kirk builds would likely not work. The US show MythBusters proved that the bamboo wasn’t strong enough to hold the explosion and the weapon would likely wound Kirk as much as it would wound the Gorn.&lt;/p&gt;
&lt;p&gt;Score: 10/10
Redshirt Count: Cestus III Outpost, 1 Red Shirt and 1 yellow shirt from away team.&lt;/p&gt;
&lt;p&gt;Arena along with all 900+ Star Trek episodes is now available in &lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Disaster Planning</title><link>https://blog-test.funkysi1701.com/posts/2016/disaster-planning/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 14 Jan 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/disaster-planning/</guid><category term="DisasterRecovery">DisasterRecovery</category><category term="BT">BT</category><category term="Outage">Outage</category><category term="Flood">Flood</category><category term="Phone">Phone</category><category term="Internet">Internet</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/flood.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Flooded streets in York during the 2015 Christmas floods" src="https://blog-test.funkysi1701.com/images/2016/flood.jpg" loading="lazy"
width="2325" height="2325"
/&gt;
&lt;/p&gt;
&lt;p&gt;Over the Christmas break the city of York experienced the worst flooding disaster it has seen in recent years. If you want to help donations are being taken at &lt;a href="https://mydonate.bt.com/events/yorkfloodappeal/272657" target="_blank" rel="noopener noreferrer"&gt;York Flood Appeal&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Luckily I wasn’t affected but it was really sad seeing many of my favourite streets full of water. Thousands of people had to be evacuated from their homes when the water was at its highest.&lt;/p&gt;
&lt;p&gt;York has its phone exchange located in the centre of the city and as the flood waters rose, this building flooded. BT who run the exchange worked flat out trying to restore phone and broadband services to York and the surrounding area, but this lead to at least 24 hours or more of downtime for users.&lt;/p&gt;
&lt;p&gt;During this time most of the city wasn’t able to take card payments from customers (due to an internet connection being required), cash machines were not working for the same reasons and the most worrying thing access to emergency services was not available.&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p lang="en" dir="ltr"&gt;Anyone would think the city phones were down &lt;a href="https://twitter.com/hashtag/yorkfloods?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#yorkfloods&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/bthardatwork?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#bthardatwork&lt;/a&gt; &lt;a href="https://t.co/ZavLMsG2Js"&gt;pic.twitter.com/ZavLMsG2Js&lt;/a&gt;&lt;/p&gt;&amp;mdash; Simon Foster (@funkysi1701) &lt;a href="https://twitter.com/funkysi1701/status/681439632886738944?ref_src=twsrc%5Etfw"&gt;December 28, 2015&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;I am in no way critical of the hard working engineers that worked on the BT exchange to restore services to the city. However I have to ask what was contained in the BT disaster recovery plan.&lt;/p&gt;
&lt;p&gt;As an IT Manager myself backups and disaster planning is something I need to think about and plan for. Recent investment in our internet connection meant that we are now on a leased line so BTs downtime would not have affected us in terms of network connectivity, I am uncertain about phone but I believe as a business we could have continued running during this time if we needed to.&lt;/p&gt;
&lt;p&gt;Planning for a disaster is not something I ever make enough time, however I definitely want to spend more time on it and I do have the basics of a plan in my head which is probably more than BT has.&lt;/p&gt;
&lt;p&gt;BT is a huge company they run almost the entire country’s phone lines and according to &lt;a href="https://en.wikipedia.org/wiki/BT_Group" target="_blank" rel="noopener noreferrer"&gt;wikipedia&lt;/a&gt;
have operations in 170 countries. I think that they can afford to have someone plan for disaster recovery.&lt;/p&gt;
&lt;p&gt;The York Exchange is located next to a river that often floods. What could the company have done to avoid this problem?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Relocate some or all of its services to a location away from the river.&lt;/li&gt;
&lt;li&gt;Add the ability to reroute services through an alternative exchange.&lt;/li&gt;
&lt;li&gt;Many towns and villages surrounding York use the BT exchange surely some of these could have been configured to use other exchanges.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In these days of terror alerts and bomb scares. Imagine if York was London and all it took to take down communication ability of the capital was one Exchange to be offline?&lt;/p&gt;
&lt;p&gt;I am sure BT are looking at what they did right and what they did wrong and if you are reading this have a look at your own disaster recovery policy. Don’t get caught out like BT did.&lt;/p&gt;</description></item><item><title>Top 50 Star Trek episodes</title><link>https://blog-test.funkysi1701.com/posts/2016/top-50-star-trek-episodes/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 07 Jan 2016 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2016/top-50-star-trek-episodes/</guid><category term="StarTrek">StarTrek</category><category term="Voyager">Voyager</category><category term="DeepSpaceNine">DeepSpaceNine</category><category term="Spock">Spock</category><category term="Kirk">Kirk</category><category term="Enterprise">Enterprise</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2016/07df3N8m.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Star Trek franchise promotional image celebrating fifty years of the series" src="https://blog-test.funkysi1701.com/images/2016/07df3N8m.jpg" loading="lazy"
width="512" height="512"
/&gt;
&lt;/p&gt;
&lt;p&gt;In 1966 a TV show called &lt;a href="https://www.startrek.com/" target="_blank" rel="noopener noreferrer"&gt;Star Trek&lt;/a&gt;
first aired in the USA. Since then 726 episodes have been made and 12 films have been released. 2016 marks the 50th anniversary and Star Trek is as alive as ever with a new film due out this summer and a brand new TV series in the works for broadcast in 2017.&lt;/p&gt;
&lt;p&gt;But what can I do to celebrate? With that many episodes I don’t have enough time to re-watch every episode so how about a re-watch of the top 50 episodes.&lt;/p&gt;
&lt;p&gt;Star Trek has five live action TV series so all I need to do is pick my top 10 from each.&lt;/p&gt;
&lt;h2 id="star-trek"&gt;Star Trek&lt;a class="anchor ms-1" href="#star-trek" aria-label="Permalink: Star Trek"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Landing party beaming up from the Guardian planet in Star Trek TOS" src="https://blog-test.funkysi1701.com/images/2016/Landing_party_beams_up_from_Guardian_planet.jpg" loading="lazy"
width="1440" height="1080"
/&gt;
&lt;/p&gt;
&lt;p&gt;The original Star Trek series first aired on September 8th 1966. It lasted only three years and 79 episodes. This series featured the iconic characters Kirk, Spock and Bones on a five-year mission to explore space.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The City on the Edge of Forever&lt;/li&gt;
&lt;li&gt;The Devil in the Dark&lt;/li&gt;
&lt;li&gt;Balance of Terror&lt;/li&gt;
&lt;li&gt;The Trouble with Tribbles&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.funkysi1701.com/posts/2016/star-trek-episode-review-arena/" target="_blank" rel="noopener noreferrer"&gt;Arena&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;This Side of Paradise&lt;/li&gt;
&lt;li&gt;Amok Time&lt;/li&gt;
&lt;li&gt;Space Seed&lt;/li&gt;
&lt;li&gt;Mirror Mirror&lt;/li&gt;
&lt;li&gt;The Deadly Years&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="star-trek-the-next-generation"&gt;Star Trek: The Next Generation&lt;a class="anchor ms-1" href="#star-trek-the-next-generation" aria-label="Permalink: Star Trek: The Next Generation"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Senior staff poker game aboard the Enterprise in Star Trek TNG" src="https://blog-test.funkysi1701.com/images/2016/Senior_staff_poker_game.jpg" loading="lazy"
width="1436" height="1080"
/&gt;
&lt;/p&gt;
&lt;p&gt;The first spin-off series set 100 years after Kirk featured a new Enterprise continuing to explore space. This series aired between 1987 and 1994 for 178 episodes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.funkysi1701.com/posts/2016/star-trek-episode-review-the-best-of-both-worlds/" target="_blank" rel="noopener noreferrer"&gt;Best of Both Worlds&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Yesterdays Enterprise&lt;/li&gt;
&lt;li&gt;The Offspring&lt;/li&gt;
&lt;li&gt;The Measure of a Man&lt;/li&gt;
&lt;li&gt;Disaster&lt;/li&gt;
&lt;li&gt;All Good Things…&lt;/li&gt;
&lt;li&gt;Tapestry&lt;/li&gt;
&lt;li&gt;The Inner Light&lt;/li&gt;
&lt;li&gt;Cause and Effect&lt;/li&gt;
&lt;li&gt;Unification&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="star-trek-deep-space-nine"&gt;Star Trek: Deep Space Nine&lt;a class="anchor ms-1" href="#star-trek-deep-space-nine" aria-label="Permalink: Star Trek: Deep Space Nine"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Federation fleet preparing to engage the Dominion fleet in Deep Space Nine" src="https://blog-test.funkysi1701.com/images/2016/Federation_fleet_prepares_to_engage_Dominion_fleet.jpg" loading="lazy"
width="694" height="530"
/&gt;
&lt;/p&gt;
&lt;p&gt;The second spin-off series which ran at the same time as TNG was set on a space station so instead of exploring adventures arrived via a stable wormhole. This series aired between 1993 and 1999 for 176 episodes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Emissary&lt;/li&gt;
&lt;li&gt;Duet&lt;/li&gt;
&lt;li&gt;The Way of the Warrior&lt;/li&gt;
&lt;li&gt;The Visitor&lt;/li&gt;
&lt;li&gt;Sacrifice of Angels&lt;/li&gt;
&lt;li&gt;Waltz&lt;/li&gt;
&lt;li&gt;Trials and Tribble-ations&lt;/li&gt;
&lt;li&gt;In the Pale Moonlight&lt;/li&gt;
&lt;li&gt;Far Beyond the Stars&lt;/li&gt;
&lt;li&gt;Siege of AR 558&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="star-trek-voyager"&gt;Star Trek: Voyager&lt;a class="anchor ms-1" href="#star-trek-voyager" aria-label="Permalink: Star Trek: Voyager"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Voyager away team on an alien planet in Star Trek Voyager" src="https://blog-test.funkysi1701.com/images/2016/Voyager_away_team.jpg" loading="lazy"
width="609" height="499"
/&gt;
&lt;/p&gt;
&lt;p&gt;The third spin-off series ran after TNG and featured a female captain and a starship stranded in a remote part of the galaxy journeying home. This series aired between 1995 and 2001 for 172 episodes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Scorpions&lt;/li&gt;
&lt;li&gt;Year of Hell&lt;/li&gt;
&lt;li&gt;Caretaker&lt;/li&gt;
&lt;li&gt;Message in a Bottle&lt;/li&gt;
&lt;li&gt;Eye of the Needle&lt;/li&gt;
&lt;li&gt;Heroes and Demons&lt;/li&gt;
&lt;li&gt;Jetrel&lt;/li&gt;
&lt;li&gt;Timeless&lt;/li&gt;
&lt;li&gt;Pathfinder&lt;/li&gt;
&lt;li&gt;Riddles&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="star-trek-enterprise"&gt;Star Trek: Enterprise&lt;a class="anchor ms-1" href="#star-trek-enterprise" aria-label="Permalink: Star Trek: Enterprise"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Andorians at the P&amp;rsquo;Jem monastery in Star Trek Enterprise" src="https://blog-test.funkysi1701.com/images/2016/Andorians_pjem.jpg" loading="lazy"
width="669" height="461"
/&gt;
&lt;/p&gt;
&lt;p&gt;The most recent spin-off ran after Voyager and was set 100 years before Kirk. This series aired between 2001 and 2005 for 98 episodes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Broken Bow&lt;/li&gt;
&lt;li&gt;The Andorian Incident&lt;/li&gt;
&lt;li&gt;Shuttlepod One&lt;/li&gt;
&lt;li&gt;In a Mirror Darkly&lt;/li&gt;
&lt;li&gt;Twilight&lt;/li&gt;
&lt;li&gt;Damage&lt;/li&gt;
&lt;li&gt;Azati Prime&lt;/li&gt;
&lt;li&gt;Regeneration&lt;/li&gt;
&lt;li&gt;Impulse&lt;/li&gt;
&lt;li&gt;Zero Hour&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I am not going to review each episode here, I will save that for future blogs. With 50 episodes that is one a week to get them all reviewed during Star Trek’s birthday year. We will see if I manage to keep to that schedule.&lt;/p&gt;
&lt;p&gt;Track all these episodes and more in &lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>A look back at 2015</title><link>https://blog-test.funkysi1701.com/posts/2015/look-back-2015/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 31 Dec 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/look-back-2015/</guid><category term="Blogging">Blogging</category><category term="James">James</category><category term="Goals">Goals</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/151218181153-2015-year-in-review-biggest-stories-wrap-up-orig-00025316-large-169.jpg"/><description>&lt;p&gt;Wow! What an amazing year 2015 has been and with 2015 about to end I thought it would be good to look back at what happened in this amazing year.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="2015 Year in Review" src="https://blog-test.funkysi1701.com/images/151218181153-2015-year-in-review-biggest-stories-wrap-up-orig-00025316-large-169.jpg" loading="lazy"
width="460" height="259"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;January&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I started the year with a declaration that 2015 would be my year of code. Well I have had a few breaks from programming but I have learnt loads this year. I have flitted a bit concentrating on different areas of programming but I think that has broadened my knowledge. I consider myself to be a &lt;a href="https://www.funkysi1701.com/posts/2015/im-a-developer-now/" target="_blank" rel="noopener noreferrer"&gt;programmer now&lt;/a&gt;
, which I didn’t at the start of 2015.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;February&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A first for 2015 was appearing on a &lt;a href="https://www.funkysi1701.com/posts/2015/podcasts/" target="_blank" rel="noopener noreferrer"&gt;podcast&lt;/a&gt;
. The Trekmate podcast &lt;a href="https://www.funkysi1701.com/posts/2015/ten-forward-episode-135-anti-firbob-is-back-or-simons-desert-island-trek/" target="_blank" rel="noopener noreferrer"&gt;Ten Forward&lt;/a&gt;
were the lucky ones that got to experience my first attempt at talking to the world. This continued throughout the year with appearances on &lt;a href="https://www.funkysi1701.com/posts/2015/upper-pylon-2-1-x-09-the-passenger/" target="_blank" rel="noopener noreferrer"&gt;Upper Pylon 2&lt;/a&gt;
, &lt;a href="https://www.funkysi1701.com/posts/2015/the-hunted-tng-s3-e11-the-battle-bridge/" target="_blank" rel="noopener noreferrer"&gt;The Battle Bridge&lt;/a&gt;
and even the &lt;a href="https://www.funkysi1701.com/posts/2015/star-trek-is-back-in-2017/" target="_blank" rel="noopener noreferrer"&gt;Sci-Fi Waffle&lt;/a&gt;
podcast.&lt;/p&gt;
&lt;p&gt;It was a sad time for Trekkies at the end of February when &lt;a href="https://www.funkysi1701.com/posts/2015/hes-really-not-dead-as-long-as-we-remember-him/" target="_blank" rel="noopener noreferrer"&gt;Leonard Nimoy&lt;/a&gt;
passed away.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;March&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In March I talked about my recent efforts with &lt;a href="https://www.funkysi1701.com/posts/2015/azure-traffic-manager/" target="_blank" rel="noopener noreferrer"&gt;Azure Traffic Manager&lt;/a&gt;
to help prevent downtime. I also spent a lot of time improving &lt;a href="https://www.funkysi1701.com/posts/2015/database-deployment/" target="_blank" rel="noopener noreferrer"&gt;databases&lt;/a&gt;
which led me to consider ways to deploy it better.&lt;/p&gt;
&lt;p&gt;Also in March I attended an IT networking event called &lt;a href="https://www.funkysi1701.com/posts/2015/networking-event/" target="_blank" rel="noopener noreferrer"&gt;ITBoss&lt;/a&gt;
. Free food and drinks and a discussion with fellow IT Managers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;April&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;April was a bit of a mixed bag. I celebrated my second wedding anniversary but I also said goodbye to my car due to financial reasons.&lt;/p&gt;
&lt;p&gt;I played about with a &lt;a href="https://www.funkysi1701.com/posts/2015/the-raspberry-pi-adventure-starts/" target="_blank" rel="noopener noreferrer"&gt;Raspberry Pi&lt;/a&gt;
, mostly with the &lt;a href="https://www.funkysi1701.com/posts/2015/security-camera-with-raspberry-pi-camera/" target="_blank" rel="noopener noreferrer"&gt;camera&lt;/a&gt;
. I really must make some time to play with it more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;May&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In May I went to a C# User Group called Leeds Sharp, was great fun and I really need to make more time and go back in 2016. It did result in one of my &lt;a href="https://www.funkysi1701.com/posts/2015/user-groups-and-f/" target="_blank" rel="noopener noreferrer"&gt;most popular blog posts&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Usually developers don’t enjoy finding bugs in their software but I had great fun when I realised I had a &lt;a href="https://www.funkysi1701.com/posts/2015/overflow/" target="_blank" rel="noopener noreferrer"&gt;Stack Overflow&lt;/a&gt;
in one of my databases, it was easy to fix once I worked out what was going on.&lt;/p&gt;
&lt;p&gt;In May the UK went to the polls as we had another General Election.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;June&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In June I celebrated my &lt;a href="https://www.funkysi1701.com/posts/2015/50th-blog-post/" target="_blank" rel="noopener noreferrer"&gt;50th Blog Post&lt;/a&gt;
. Amazing to think I had already written 50 Blog posts, even more now!&lt;/p&gt;
&lt;p&gt;Leeds Sharp had a coding challenge, to solve &lt;a href="https://www.funkysi1701.com/posts/2015/sudoku-challenge/" target="_blank" rel="noopener noreferrer"&gt;Sodoku&lt;/a&gt;
puzzle programatically. Didn’t get it finished but made a good stab at it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;July&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In July it was SysAdmin Day and I celebrated with my staff the amazing work we do keeping everything working.&lt;/p&gt;
&lt;p&gt;Microsoft launched &lt;a href="https://www.funkysi1701.com/posts/2015/how-to-upgrade-to-windows-10/" target="_blank" rel="noopener noreferrer"&gt;Windows 10&lt;/a&gt;
in July, the latest operating system is being offered for free for a year.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;August&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In August everything changed as my son &lt;a href="https://www.funkysi1701.com/posts/2015/baby-magic-and-becoming-a-father/" target="_blank" rel="noopener noreferrer"&gt;James&lt;/a&gt;
was born. I took time out from blogging and work during this time to spend with James.&lt;/p&gt;
&lt;p&gt;Before James was born I stepped down from my involvement with the &lt;a href="https://www.funkysi1701.com/posts/2015/volunteering-for-a-technical-team/" target="_blank" rel="noopener noreferrer"&gt;technical team&lt;/a&gt;
at St Michael le Belfrey.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;September&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In september it was back to work, where I started planning how to add &lt;a href="https://www.funkysi1701.com/posts/2015/adding-internet-connection-resiliency/" target="_blank" rel="noopener noreferrer"&gt;internet connections&lt;/a&gt;
to reduce the chance of outages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;October&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In October I took James to a &lt;a href="https://www.funkysi1701.com/posts/2015/james-goes-on-an-adventure-with-daddy/" target="_blank" rel="noopener noreferrer"&gt;dads group&lt;/a&gt;
. This was the first time Dad spent time with James without Mummy and it was awesome.&lt;/p&gt;
&lt;p&gt;I also celebrated my first birthday after becoming a father, was great to have a card from James. James also got the chance to spend time with my family in Nottingham.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;November&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In November the countdown to Christmas began with James appearing in his first Nativity as Jesus and dressed up as an Elf at a Christingle service.&lt;/p&gt;
&lt;p&gt;Exciting Star Trek news was announced this month, a new &lt;a href="https://www.funkysi1701.com/posts/2015/star-trek-is-back-in-2017/" target="_blank" rel="noopener noreferrer"&gt;TV series&lt;/a&gt;
is to be aired in January 2017. No other details yet but very exciting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;December&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;December is all about &lt;a href="https://www.funkysi1701.com/posts/2015/christmas-2015-fosters/" target="_blank" rel="noopener noreferrer"&gt;Christmas&lt;/a&gt;
and we had a great Christmas time as a family.&lt;/p&gt;
&lt;p&gt;Sadly York was hit by Floods just after Christmas, luckily my family was not affected but many others have been. Hopefully by the time you read this the cleanup will be well underway.&lt;/p&gt;
&lt;p&gt;Before Christmas I spent my time counting down the days with the &lt;a href="https://www.funkysi1701.com/posts/2015/christmas-count-code/" target="_blank" rel="noopener noreferrer"&gt;Advent of Code&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What will 2016 bring?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I don’t know. There will be lots more time with James as he continues to learn and develop. I will continue to learn and develop my coding skills. Watch this space as I keep blogging about it.&lt;/p&gt;</description></item><item><title>Christmas 2015 with the Fosters</title><link>https://blog-test.funkysi1701.com/posts/2015/christmas-2015-fosters/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 24 Dec 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/christmas-2015-fosters/</guid><category term="James">James</category><category term="Elf">Elf</category><category term="Christmas">Christmas</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/20151206_105450.jpg"/><description>&lt;p&gt;Four months ago James David Martin Foster was born. And he is even more awesome now than when he was born.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="James in a Christmas outfit" src="https://blog-test.funkysi1701.com/images/2015/20151206_105450.jpg" loading="lazy"
width="747" height="1328"
/&gt;
&lt;/p&gt;
&lt;p&gt;As I write this James only has a few sleeps (as James sleeps multiple times in a day I can’t put an exact number) until his first Christmas. James is pretty much unaware of what is going on as he is still too young but that doesn’t stop his parents enjoying the season.&lt;/p&gt;
&lt;p&gt;He has lots of Christmas themed clothes which we have been enjoying taking pictures of him wearing. He makes a great looking elf I think.&lt;/p&gt;
&lt;p&gt;We took James to his first Christingle service at &lt;a href="https://www.belfrey.org/" target="_blank" rel="noopener noreferrer"&gt;St Michael le Belfrey&lt;/a&gt;
at the start of December. A Christingle service is where you stick a candle and cocktail sticks into an orange. James loved it, he already loves looking at lights so loved looking into the light from the candle.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="James at Christingle service" src="https://blog-test.funkysi1701.com/images/2015/12333053_10153912153609155_79017677_o.jpg" loading="lazy"
width="1144" height="2048"
/&gt;
&lt;/p&gt;
&lt;p&gt;Another Christmas activity we did this year as a family was to appear in a nativity. St Michael le Belfrey every Christmas hold a cafe to tell people the good news about Christmas and they have a nativity outside which includes donkeys. Don’t we make a great holy family. (Excuse the coffee cups but it was cold.)&lt;/p&gt;
&lt;p&gt;Me and James’s mummy have gone a bit crazy with buying him presents, we have both got him lots of things to open on Christmas morning (or more likely mummy/daddy will do the opening)&lt;/p&gt;
&lt;p&gt;James also has three Christmas days to look forward to, with different sides of the family each no doubt with him as the centre of attention.&lt;/p&gt;
&lt;p&gt;Exciting times. Happy Christmas everyone, make yours as special as ours.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Family in nativity scene" src="https://blog-test.funkysi1701.com/images/2015/12309579_10153809916077792_2703731936729335666_o.jpg" loading="lazy"
width="810" height="1080"
/&gt;
&lt;/p&gt;</description></item><item><title>The Christmas count down with code</title><link>https://blog-test.funkysi1701.com/posts/2015/christmas-count-code/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 17 Dec 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/christmas-count-code/</guid><category term="Code">Code</category><category term="Challenge">Challenge</category><category term="Santa">Santa</category><category term="HappyChristmas">HappyChristmas</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/adventofcode.jpg"/><description>&lt;p&gt;In December we count down the days to Christmas. People often have advent calendars filled with chocolates or even Lego.&lt;/p&gt;
&lt;p&gt;But what about if you are a programmer, how can you count down the days till Christmas? What about if you had a daily Christmas themed coding challenge? Well &lt;a href="https://adventofcode.com/" target="_blank" rel="noopener noreferrer"&gt;adventofcode.com&lt;/a&gt;
is the answer.
&lt;img class="img-fluid" alt="Advent of Code Christmas coding challenge website" src="https://blog-test.funkysi1701.com/images/adventofcode.jpg" loading="lazy"
width="691" height="767"
/&gt;
&lt;/p&gt;
&lt;p&gt;Each day a new challenge is available. So far the challenges are related to Christmas and Santa delivering his presents. The challenge is split into two closely linked parts. You are given a randomly generated input and your need to give an answer using a short string or number.&lt;/p&gt;
&lt;p&gt;The challenges are getting harder, with some completely defeating me, (not surprising with my limited programming knowledge). The challenges are language independent so you could try them in javascript or c#. I have been using Visual Studio and C# and my code is viewable on &lt;a href="https://github.com/funkysi1701/AdventSolution" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;So far I have completed Challenges 1 to 6 and also 10. Partly because I found challenge 7 very difficult but I am hoping to have another go at it.&lt;/p&gt;
&lt;p&gt;While coding through these challenges I have done a fair amount of refactoring. I started off with a simple console app with most of my code in one method. As the number of challenges increased I started moving the code for each challenge into its own class, with methods and properties that were unique to the challenge. I also added a main menu so you can choose which challenge to run. Some of my code to answer the challenges takes some time to run so this was quite a time saver over running each challenge in order.&lt;/p&gt;
&lt;p&gt;These challenges are very good at teaching me things about coding. I have got to think about data structures, what is the best way to store this information, classes and methods and return types, how to output data to the screen, how to input/import data.&lt;/p&gt;
&lt;p&gt;Before I try and work on the next challenge lets have a look at the first challenge:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Santa is trying to deliver presents in a large apartment building,
but he can’t find the right floor –
the directions he got are a little confusing.
He starts on the ground floor (floor 0)
and then follows the instructions one character at a time.
An opening parenthesis, (, means he should go up one floor, and a closing parenthesis, ),
means he should go down one floor.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a simple loop through a long string of ( and ) and keep track of the floor number you are on to calculate what floor Santa finishes on. The second part of the challenge asks at what point in your input string does santa reach the basement (floor -1)&lt;/p&gt;</description></item><item><title>Roddenberry comic</title><link>https://blog-test.funkysi1701.com/posts/2015/roddenberry-comic/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 10 Dec 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/roddenberry-comic/</guid><category term="Help">Help</category><category term="GeneRoddenberry">GeneRoddenberry</category><category term="Plane">Plane</category><category term="StarTrek">StarTrek</category><media:content medium="image" type="image/webp" url="https://blog-test.funkysi1701.com/images/1-523x400.webp"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="The Oatmeal comic panel about Gene Roddenberry and a plane crash" src="https://blog-test.funkysi1701.com/images/1-523x400.webp" loading="lazy"
width="523" height="400"
/&gt;
&lt;/p&gt;
&lt;p&gt;The Oatmeal created a comic which you really should check out. It can be found &lt;a href="https://theoatmeal.com/comics/plane" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;The comic tells the story of a plane crash, in which the 25 year old co-pilot goes back into the burning plane to rescue passengers and lead a group of survivors through the desert to find help.&lt;/p&gt;
&lt;p&gt;The co-pilot was named Gene Roddenberry, and after these events he stopped being a pilot and became a writer and eventually created Star Trek.&lt;/p&gt;
&lt;p&gt;In these uncertain times when you are stranded in the desert, get out and help someone, it may change the world.&lt;/p&gt;</description></item><item><title>SQL Server Management Studio</title><link>https://blog-test.funkysi1701.com/posts/2015/sql-server-management-studio/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 03 Dec 2015 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/sql-server-management-studio/</guid><category term="Database">Database</category><category term="SQL">SQL</category><description>&lt;p&gt;I use SQL Server Management Studio all the time for writing queries, getting data and general SQL development.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="SQL Server Management Studio" src="https://blog-test.funkysi1701.com/images/2015/sql-server-2012-management-studio-splash-screen.png" loading="lazy"
width="529" height="360"
/&gt;
&lt;/p&gt;
&lt;p&gt;I have enjoyed seeing the improvements that each new version of SQL Server Management Studio (SSMS) introduced. One great improvement was intellisense.&lt;/p&gt;
&lt;p&gt;This feature saves typing and reduces errors by automatically suggesting tables, column names or other database objects.&lt;/p&gt;
&lt;p&gt;A common query that I get asked to write is provide a spreadsheet that gives the information that satisfies certain criteria. This is easy to do in SSMS, you can write the query, click execute and the rows that satisfy the criteria are displayed. These rows can then be easily copy/pasted into Excel or other spreadsheets.&lt;/p&gt;
&lt;p&gt;A common data item that gets stored in databases is addresses and addresses often contain line breaks to make the data display better. In the earlier versions of SSMS, when you copied and pasted these line breaks were ignored and the data displayed the same in SSMS as it did in Excel. However in the more recent version, theses line breaks got copied across breaking your spreadsheet and making it hard to see what data corresponded with what.&lt;/p&gt;
&lt;p&gt;Now I don’t know if this should be described as introducing a bug or fixing one. I can easily argue both sides. If your data contains a line break and you copy this data it should include the line break in the destination, but if it does that it displays badly in Excel.&lt;/p&gt;
&lt;p&gt;The fix I have been using until recently is to use the following TSQL command in my queries.&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;REPLACE&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;REPLACE&lt;/span&gt;(&lt;span style="color:#f92672"&gt;@&lt;/span&gt;str, CHAR(&lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;), &lt;span style="color:#e6db74"&gt;&amp;#34;), CHAR(10), &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command replaces any line breaks with an empty string. Both Char(10) and Char(13) are needed because you can have different types of line breaks. This is great if you are writing the script from scratch but isn’t great if your are running a stored procedure or your query has a lot of columns.&lt;/p&gt;
&lt;p&gt;The answer to this is to use Visual Studio to run your SQL query. In Visual Studio you can write and run queries via Server Explorer and the results produced don’t contain line breaks. I have only just discovered this solution, but so far it has worked and is very easy to do, plus as I do most of my development in Visual Studio anyway it saves me having to open SSMS to test my queries.&lt;/p&gt;</description></item><item><title>Black Friday Deals</title><link>https://blog-test.funkysi1701.com/posts/2015/black-friday-deals/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 27 Nov 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/black-friday-deals/</guid><category term="Deals">Deals</category><category term="Blogging">Blogging</category><category term="Blackfriday">Blackfriday</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/86910937_t053ll31.jpg"/><description>&lt;h2 id="over-50-off-this-black-friday"&gt;Over 50% Off this Black Friday!&lt;a class="anchor ms-1" href="#over-50-off-this-black-friday" aria-label="Permalink: Over 50% Off this Black Friday!"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Black Friday Deals" src="https://blog-test.funkysi1701.com/images/86910937_t053ll31.jpg" loading="lazy"
width="660" height="371"
/&gt;
&lt;/p&gt;
&lt;p&gt;Yes you heard it correctly even &lt;a href="https://www.funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;www.funkysi1701.com&lt;/a&gt;
has amazing offers.&lt;/p&gt;
&lt;p&gt;It is like the whole world has gone “Black Friday” mad, with every company in the world offering amazing and unmissable deals.&lt;/p&gt;
&lt;p&gt;So in an attempt to cash in on all the Black Friday fuss I will write a quick blog post about it.&lt;/p&gt;
&lt;p&gt;I mentioned 50% off well this month I have blogged 50% less than usual. There is one main reason for this, my new born son James is taking a lot of my time and energy and I think it will take a few months of sporadic blog posts before I get the balance right.&lt;/p&gt;
&lt;p&gt;I am not a big fan of spending just for the sake of it. Encouraging people to spend money they don’t have, on things they don’t need shouldn’t be encouraged. However times are hard so companies need to do what they need to, to try and make money.&lt;/p&gt;</description></item><item><title>Star Trek is back (in 2017)</title><link>https://blog-test.funkysi1701.com/posts/2015/star-trek-is-back-in-2017/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 12 Nov 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/star-trek-is-back-in-2017/</guid><category term="StarTrek">StarTrek</category><category term="Podcast">Podcast</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/11/3f448330857e4ca7ba40ab5465a3c2cb62cdb98c.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="3f448330857e4ca7ba40ab5465a3c2cb62cdb98c" src="https://blog-test.funkysi1701.com/images/2015/11/3f448330857e4ca7ba40ab5465a3c2cb62cdb98c.png" loading="lazy"
width="620" height="260"
/&gt;
&lt;/p&gt;
&lt;p&gt;As you have probably heard Star Trek is coming back to TV. I recently joined with the Sci Fi Waffle podcast to discuss.&lt;/p&gt;
&lt;p&gt;Sci Fi Waffle: Episode 12 – STAR TREK IS BACK!!&lt;/p&gt;
&lt;p&gt;In this episode we discuss the great news that Star Trek IS BACK!!.&lt;/p&gt;
&lt;p&gt;Shawn and I are joined again by James Roberts and TrekMates News feed Editor Simon Foster to speculate about the announcement of a new Star Trek TV series due to debut in January 2017.&lt;/p&gt;
&lt;p&gt;James can be found on our sister podcast &lt;a href="https://www.trekmate.org.uk/category/the-battle-bridge/" target="_blank" rel="noopener noreferrer"&gt;The Battle Bridge&lt;/a&gt;
and Simon can be found on Twitter &lt;a href="https://twitter.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;To listen go &lt;a href="https://www.trekmate.org.uk/sci-fi-waffle-episode-11-star-trek-is-back/" target="_blank" rel="noopener noreferrer"&gt;https://www.trekmate.org.uk/sci-fi-waffle-episode-11-star-trek-is-back/&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>How to speak to the whole world</title><link>https://blog-test.funkysi1701.com/posts/2015/how-to-speak-to-the-whole-world/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 05 Nov 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/how-to-speak-to-the-whole-world/</guid><category term="Global">Global</category><category term="Blogging">Blogging</category><category term="World">World</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/10/world.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="World map showing global website reach" src="https://blog-test.funkysi1701.com/images/2015/10/world.png" loading="lazy"
width="648" height="423"
/&gt;
&lt;/p&gt;
&lt;p&gt;Having a website is an easy way to reach people across the globe. This website has reached people in almost every continent.&lt;/p&gt;
&lt;p&gt;I have had visitors in each of the following countries.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;United States&lt;/li&gt;
&lt;li&gt;United Kingdom&lt;/li&gt;
&lt;li&gt;Canada&lt;/li&gt;
&lt;li&gt;Germany&lt;/li&gt;
&lt;li&gt;Australia&lt;/li&gt;
&lt;li&gt;India&lt;/li&gt;
&lt;li&gt;France&lt;/li&gt;
&lt;li&gt;Vietnam&lt;/li&gt;
&lt;li&gt;Netherlands&lt;/li&gt;
&lt;li&gt;Poland&lt;/li&gt;
&lt;li&gt;China&lt;/li&gt;
&lt;li&gt;Russia&lt;/li&gt;
&lt;li&gt;Sweden&lt;/li&gt;
&lt;li&gt;European Union&lt;/li&gt;
&lt;li&gt;New Zealand&lt;/li&gt;
&lt;li&gt;Hungary&lt;/li&gt;
&lt;li&gt;Norway&lt;/li&gt;
&lt;li&gt;Spain&lt;/li&gt;
&lt;li&gt;Brazil&lt;/li&gt;
&lt;li&gt;Hong Kong SAR China&lt;/li&gt;
&lt;li&gt;Belgium&lt;/li&gt;
&lt;li&gt;Denmark&lt;/li&gt;
&lt;li&gt;Italy&lt;/li&gt;
&lt;li&gt;Switzerland&lt;/li&gt;
&lt;li&gt;Finland&lt;/li&gt;
&lt;li&gt;Turkey&lt;/li&gt;
&lt;li&gt;Romania&lt;/li&gt;
&lt;li&gt;Singapore&lt;/li&gt;
&lt;li&gt;Israel&lt;/li&gt;
&lt;li&gt;Indonesia&lt;/li&gt;
&lt;li&gt;Serbia&lt;/li&gt;
&lt;li&gt;South Africa&lt;/li&gt;
&lt;li&gt;Lithuania&lt;/li&gt;
&lt;li&gt;Mexico&lt;/li&gt;
&lt;li&gt;Ireland&lt;/li&gt;
&lt;li&gt;South Korea&lt;/li&gt;
&lt;li&gt;Taiwan&lt;/li&gt;
&lt;li&gt;Greece&lt;/li&gt;
&lt;li&gt;Bulgaria&lt;/li&gt;
&lt;li&gt;Ukraine&lt;/li&gt;
&lt;li&gt;Japan&lt;/li&gt;
&lt;li&gt;Austria&lt;/li&gt;
&lt;li&gt;Kenya&lt;/li&gt;
&lt;li&gt;Portugal&lt;/li&gt;
&lt;li&gt;Czech Republic&lt;/li&gt;
&lt;li&gt;Colombia&lt;/li&gt;
&lt;li&gt;Philippines&lt;/li&gt;
&lt;li&gt;United Arab Emirates&lt;/li&gt;
&lt;li&gt;Moldova&lt;/li&gt;
&lt;li&gt;Slovenia&lt;/li&gt;
&lt;li&gt;Malaysia&lt;/li&gt;
&lt;li&gt;Ghana&lt;/li&gt;
&lt;li&gt;Argentina&lt;/li&gt;
&lt;li&gt;Venezuela&lt;/li&gt;
&lt;li&gt;Bangladesh&lt;/li&gt;
&lt;li&gt;Iceland&lt;/li&gt;
&lt;li&gt;Croatia&lt;/li&gt;
&lt;li&gt;Panama&lt;/li&gt;
&lt;li&gt;Belarus&lt;/li&gt;
&lt;li&gt;Slovakia&lt;/li&gt;
&lt;li&gt;Albania&lt;/li&gt;
&lt;li&gt;Kazakhstan&lt;/li&gt;
&lt;li&gt;Algeria&lt;/li&gt;
&lt;li&gt;Puerto Rico&lt;/li&gt;
&lt;li&gt;Thailand&lt;/li&gt;
&lt;li&gt;Estonia&lt;/li&gt;
&lt;li&gt;U.S. Virgin Islands&lt;/li&gt;
&lt;li&gt;Pakistan&lt;/li&gt;
&lt;li&gt;Latvia&lt;/li&gt;
&lt;li&gt;Chile&lt;/li&gt;
&lt;li&gt;Sri Lanka&lt;/li&gt;
&lt;li&gt;Malta&lt;/li&gt;
&lt;li&gt;Costa Rica&lt;/li&gt;
&lt;li&gt;Morocco&lt;/li&gt;
&lt;li&gt;Ethiopia&lt;/li&gt;
&lt;li&gt;Réunion&lt;/li&gt;
&lt;li&gt;Uruguay&lt;/li&gt;
&lt;li&gt;Honduras&lt;/li&gt;
&lt;li&gt;Cyprus&lt;/li&gt;
&lt;li&gt;Tunisia&lt;/li&gt;
&lt;li&gt;Nepal&lt;/li&gt;
&lt;li&gt;Cameroon&lt;/li&gt;
&lt;li&gt;Paraguay&lt;/li&gt;
&lt;li&gt;Gambia&lt;/li&gt;
&lt;li&gt;Peru&lt;/li&gt;
&lt;li&gt;Mauritius&lt;/li&gt;
&lt;li&gt;Bermuda&lt;/li&gt;
&lt;li&gt;Cambodia&lt;/li&gt;
&lt;li&gt;Jersey&lt;/li&gt;
&lt;li&gt;Egypt&lt;/li&gt;
&lt;li&gt;Macedonia&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How cool is that! If you know anyone from any country not mentioned above, send them a link to this page and lets see if we can get this blog seen in even more countries.&lt;/p&gt;
&lt;p&gt;Only a few years ago it would have been incredibly difficult to communicate your ideas to the whole world, now it is available to everyone at a touch of a button.&lt;/p&gt;
&lt;p&gt;The internet has a lot to answer for. On the one hand it is blamed for a decrease of communication between people as they stare at their devices all the time, but on the other hand it has greatly improved communication over larger distances like the use of Skype or the ability to broadcast your ideas on websites and social media.&lt;/p&gt;</description></item><item><title>Top 10 Warp 11 Songs</title><link>https://blog-test.funkysi1701.com/posts/2015/top-10-warp-11-songs/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 29 Oct 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/top-10-warp-11-songs/</guid><category term="StarTrek">StarTrek</category><category term="Music">Music</category><category term="Warp11">Warp11</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/10/redAlertCover_02.jpg"/><description>&lt;h2 id="i-dont-want-to-go-to-work-just-want-to-hang-with-captain-kirk"&gt;I don’t want to go to work Just want to hang with Captain Kirk&lt;a class="anchor ms-1" href="#i-dont-want-to-go-to-work-just-want-to-hang-with-captain-kirk" aria-label="Permalink: I don’t want to go to work Just want to hang with Captain Kirk"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I am a big Warp 11 fan. Warp 11 are a Star Trek rock band from Sacramento, California. Their songs often feature bad language, sex and drinking but always feature references to Star Trek characters and episodes and a good dose of humour.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Warp 11 Red Alert album cover" src="https://blog-test.funkysi1701.com/images/2015/10/redAlertCover_02.jpg" loading="lazy"
width="250" height="250"
/&gt;
&lt;/p&gt;
&lt;p&gt;I first listened to Warp 11 in about 2004 and have listened to every album they have released since. The second album Red Alert is probably my favourite but all their albums have a few tracks which I love. They have just released their seventh album and to celebrate this I will list my favourite tracks.&lt;/p&gt;
&lt;p&gt;All lyrics are by Warp 11 and no infringement is intended, if you like what you see go to their website (&lt;a href="https://www.warp11.com" target="_blank" rel="noopener noreferrer"&gt;www.warp11.com&lt;/a&gt;
), or buy their music. Also Warp 11 if you are reading this, come to the UK, I would love to hear you perform live.&lt;/p&gt;
&lt;ol start="10"&gt;
&lt;li&gt;&lt;strong&gt;It’s Dead Jim&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the fourth album &lt;strong&gt;It’s Dead Jim&lt;/strong&gt;. This song came out after Enterprise was cancelled and is all about the fact there was no more new trek being made. It was a bleak time to be a trekkie and I shared Warp 11’s sadness in this song.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;First they took my TOS
Then they took my TNG
Said “bon voyage” to Voyager
Now there’s nothing left for me
Decommissioned DS9
Now there’s no more Enterprise
Erased the animated show
Yeah, she met a quick demise
The final frontier has been finalized
There ain’t no coming back
It’s getting no reprise
It boldly came and went
Got no Trek to represent
I never thought the day
Would come that I had to say
It’s dead Jim
Space is cold and so am I
Just like Kirk my show has died
Everything has gone awry
I guess it’s time to say goodbye
‘Cause Scotty’s gone and so is Bones
They took their final voyage home
And I guess I’ve always known
That some day I’d be alone
Tore down the sets today
Gave the plastic ears away
Sold the props on eBay
Left my life in disarray
It’s dead Jim
Until they bring it back again
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="9"&gt;
&lt;li&gt;&lt;strong&gt;7 of Mine&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the second album &lt;strong&gt;Red Alert&lt;/strong&gt;. 7 of 9 is one sexy character so it is no surprise that Warp 11 chose to sing about that in a few songs and I think this is probably the best example.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Flesh and bone and silicone
You’re all by yourself, but you’re never alone
You’re pretty smooth, for a chick full of wires
So cold to the touch
But you set me on fire
Assimilate me
Dominate me
Short circuit my mind
Energize me
Your thighs always rise me
Let’s go out and make your gears grind
Seven of mine
One minute you’re cruel
And then you’re kind
You gave me a virus, but baby I don’t mind
‘Cause I self destruct when I see your behind
I’ll show you the difference between seven and nine
Chorus
Well, life and love are so absurd
And assimilation is the final word
Resistance is futile can’t you see
So, come on now baby and assimilate me
I’ll give you an identity
Locutus ain’t got nothing on me, oh yeah
Let’s grab a shuttle and go to your cube
You bring the oil and honey I’ll bring the lube
It’s not monogamy
‘Cause in the end
When I’m f****** you, I’m f****** all of your friends
Chorus
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="8"&gt;
&lt;li&gt;&lt;strong&gt;Old Country Dr.(The Ballad Of Bones)&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the second album &lt;strong&gt;Red Alert&lt;/strong&gt;. A song dedicated to Bones so of course it is great. The use of harmonica makes you think of the country doctor which is a nice touch. This song gets a sequel as well on one of the later albums.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Well, they call me Bones and I’m third in command
Second in line is a man I just can’t stand
He’s a green blooded, pointy-eared, seven year itch
And when he pon farrs
He’ll try to make me his bitch
Well, I may or may not have divorced my wife
But I damn sure pulled the plug on my daddy’s life
And two months later, well, they found a cure
I’m just an old country doctor on a damned five year tour
The damned teleporter
Yeah, it gives me the creeps
The first time I used it
I couldn’t get it up for weeks
Now my tricorder’s busted
And sick bay just stinks
I guess I’ll just go replicate me a drink
Chorus
Well, Jim is the captain of this here ship
We call her the Enterprise, and the crew’s pretty hip
Yeah, the girls all wear go-go boots and miniskirts
And I spend my days patching all the red shirts
Well, I have been asked to do many a thing
Outside the area of my expertise
Damn it Jim, I know I’ve told you before
Damn it Jim, I know I’ve told you before
Damn it Jim, damn it Jim, I told you before
I’m just an old country doctor on a damned five year tour
Just an old country doctor on a damned five year tour
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="7"&gt;
&lt;li&gt;&lt;strong&gt;Space Happy&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the second album &lt;strong&gt;Red Alert&lt;/strong&gt;. This song is just solid good fun, with a catchy chorus that I can’t help singing along to.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Gonna take a five year tour
Boldly go where no man’s gone before
Gonna travel to the end
And make new friends
Move ahead warp factor ten
Put a miniskirt on my yeoman
Represent the human race
And we’ll make space
A happy place
To boldly go where no man’s gone before
I think I sang that line once before
(But I’m not too sure)
We’ll be so happy – can’t you see?
A zero-g community
Gonna travel to new worlds
Beam on down and meet some green girls
Gonna see what we can see
A fancy-free galaxy
Chorus
Come and take a tour with me
They’ll be no Kahns or Kobiashi
Gonna travel to the end
And make new friends
With aliens
Chorus
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="6"&gt;
&lt;li&gt;&lt;strong&gt;And Thats Why I’m In A Star Trek Band&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the second album &lt;strong&gt;Red Alert&lt;/strong&gt;. Not only does the start of this song make me think of the postman pat theme but it is good fun.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;I love gettin’ hummers from chicks dressed as Klingons
Bumpy heads bobbin’ up and down
Like their necks have a spring on
And I know their teeth hurt
But I still get my thing on
And that’s why
And that’s why
I’m in a Star Trek band
I wanna tag team a stripper with Mr. William Shatner
He’ll take the front and hell, I’ll take the back-ner
And when we blow
We’re gonna reach warp factor
And that’s why
And that’s why
I’m in a Star Trek band
Well, people ask me
Where do I find my joy?
Do I like hot girls, green aliens or young boys?
Well, I got two words for you my friend – Leonard Nimoy
And that’s why
And that’s why
I’m in a Star Trek band
And that’s why
And that’s why
We’re in a Star Trek band
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;Everything I Do (I Do With William Shatner)&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the second album &lt;strong&gt;Red Alert&lt;/strong&gt;. This was probably the first Warp 11 song I heard and it made me want to listen to the rest. Warp 11 don’t just mention trek, they are actual fans as you can tell from the references that litter their songs.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Everything I do, I do with William Shatner
Loosing all my hair while my belly’s growing fat-ner
And when I drink too much
He holds my hair in his hands
And while I’m blowing chunks
He treats me like the captain
Oh, when we get together we boldly go
Talk about our favorite episodes
I don’t want to go to work
Just want to hang with Captain Kirk
And if I had my way I’d make it so
Everything I do, I do with William Shatner
We drink a couple of brews
Go to the Laundromat-ner
When our clothes are dry
We fold them up together
‘Cause everything I do, I do with William Shatner
Chorus
Hey, spend more time with him than George Takei
Say full speed ahead and we’re on our way
He is so mysterious
His middle name’s Tiberius
And he’ll make me his cabin boy someday
Hey Bill – Let’s go get a tan
Hey Bill – And a green woman
Hey Bill – We’ll kill some Romulans
Hey Bill – I’m your number one fan
‘Cause everything I do, I do with William Shatner
We go to the rodeo and put on our cowboy hat-ners
When we paint the town
We buy each other dinner
We’re fully functional
Just like Brent Spiner
Everything I do, I do with William Shatner
And don’t you wish that you could do it too
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;What would William Shatner do?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the fifth album &lt;strong&gt;I Don’t Want to Go to Heaven as Long as They Have Vulcans in Hell&lt;/strong&gt;. Everyone’s been in situations where they would like to keep there fandom a secret. And what would William Shatner do?&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;I’ve got a girl, the coolest girl in the world
But she ain’t fly for the guys in sci-fi
And I’m a guy with a model Enterprise
Imagine her surprise if she ever finds out
I’ve got a queen, but she only wears blue jeans
And I am a guy in Kirk t-shirt
Black boots and a red miniskirt
I’ll be in world of hurt if she ever finds out
I’ve got to think about it
I’ve got to work it through
If she learns my dark secret
What would William Shatner do?
I’ve got a chick, in bed a lunatic
Won’t be my whore if she knows I love Star Wars
And I know only one thing for sure
I’ll never score If she ever finds out
I’ve got to make a choice now
Deceive her or tell her true
I know Vulcans never lie but
What would William Shatner do?
I love War of the Worlds, got a b**** for green girls
Alien nations, deep space stations
I love flying saucers, say “live long and prosper”
“May the force be with you”, Mr. Sulu
I want to be your man, “by your command”
Don’t want us to be undone, “danger Will Robinson!”
And if I decree “beedee beedee bee”
Does that mean we’ll be through?
What would William Shatner do?
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;Trekie Girl&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the second album &lt;strong&gt;Red Alert&lt;/strong&gt;. When I first listened to this song I was a single young man, so of course I dreamed about finding my own Trekie Girl. My wife now shares my love of Trek and looks extremely hot in a starfleet uniform.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;She knows every episode
She wears the boots that go-go-go
She’s got a red miniskirt
She makes me play Captain Kirk
Trekkie girl, Trekkie girl
We go to conventions
She gives me erections
Girl – my Trekkie girl
She paints her skin green
And it’s not Halloween
She rocks my brave new world
She always acts so logical
She drives a Volvo Iike it’s our space shuttle (of love)
She looks just like Britney Spears
Just add a few pounds and some pointy ears
Trekkie girl, Trekkie girl
She loves outer space
Has a black and white face
Oh, girl – my Trekkie girl
I’m her Leonard Nimoy
She’s the real McCoy
She’s got a Spock haircut with curls
And on some nights she tells me
Put my symbiote inside her
She separates my saucer
Yeah, she knows just what to say
And on nights when I loose power
Well it doesn’t even phaser
She grabs my captain’s log
Torpedoes away
She knows every episode
She wears the boots that go-go-go
She’s got a red miniskirt
She makes me play Captain Kirk
Trekkie girl, Trekkie girl
We go to conventions
She gives me erections
Girl – my Trekkie girl
She paints her skin green
And it’s not Halloween
Oh, girl – my Trekkie girl
She loves outer space
Has a black and white face
Oh, girl – my Trekkie girl
I’m her Leonard Nimoy
She’s the real McCoy
My girl – Trekkie girl
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;A Song for People Who Never Watch Star Trek&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the third album &lt;strong&gt;Boldly go down on me&lt;/strong&gt;. This really tells you all you need to know about original series trek, plus I like singing the first line of this song to my son (also called James)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;There was this guy
His name was Jim
You can call him Kirk
Or the Captain
He had a tan
And lots of women
Every episode
He got to blow his l***
He worked with Spock
He was a rock
No emotion
Nothing could rattle him
His blood was green
And Pon Farr could make him scream
And lose control
Though that’s illogical
Each week they’d all warp through space
Fight an alien race
And the Vulcan would pinch a neck
If you want to learn more
Go to the video store
Or just listen to this
Song for people who never watch Star Trek
Then there was Bones
Dr. McCoy
Worked with Nurse Chapel
And removed the red shirt shrapnel
Chased the miniskirts
Screaming, “Dammit, Kirk!”
Wait that wasn’t him
He was screaming, “Dammit Jim!”
Each week on the Enterprise
All the red shirts would die
But no one noticed or got upset
And the next generation
Will watch in syndication
Or just listen to this
Song for people who never watch Star Trek
And for three seasons
You know what they’d do
They’d boldly go
With the rest of their crew
Like Scotty
He was a Scot
And Chekov
He screamed a lot
And Uhura
And Sulu
But let’s face it
After Kirk, Spock and McCoy
Who gives a f*** about the rest of the crew?
&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Saddest Song Ever Written About Star Trek&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From the fourth album &lt;strong&gt;It’s Dead Jim&lt;/strong&gt;. This song really encapsulates the sadness of Star Trek’s cancellation and the passing away of some of Star Treks greats.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;It was a warm summer’s night when I sat down to write
The prettiest song ever written about Star Trek
The sky was clear
Full of stars above
I thought of Kirk and his crew
And their mission of love
And I sang the first verse
Of the prettiest song ever written about Star Trek
When the words came out
Everything was wrong
For those who’d boldly go
Had already gone
‘Cause the show was cancelled
And the dream was dead
And a red alert started wailing in my head
And I realized I had written
The saddest song ever written
About Star Trek
Now the sky was dark
Devoid of love
And Roddenberry’s ashes were floating up above
Raining down on a man
Singing the saddest song ever written about Star Trek
And now Bones is nothing but bones
He finally went and took his final voyage home
And Scotty’s body just couldn’t take much more
And I’m sure this is the saddest
Song ever written about Star Trek
I thought about space
And the final frontier
And I shed a tear as I finished
The saddest song ever written about Star Trek
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>James goes on adventure with Daddy</title><link>https://blog-test.funkysi1701.com/posts/2015/james-goes-on-an-adventure-with-daddy/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 22 Oct 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/james-goes-on-an-adventure-with-daddy/</guid><category term="Baby">Baby</category><category term="James">James</category><category term="Father">Father</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/10/12074836_10153714959677792_5717618456858661253_n.jpg"/><description>&lt;p&gt;This weekend I took James on an adventure. As he is only 8 weeks old it was a fairly low key adventure but hopefully he enjoyed himself.&lt;/p&gt;
&lt;p&gt;St Michael le Belfrey have been organizing an event for Dads once a month and this month I wanted to give it a go. I have been looking forward to going for a while.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Author carrying baby James in a front carrier at a dads event" src="https://blog-test.funkysi1701.com/images/2015/10/12074836_10153714959677792_5717618456858661253_n.jpg" loading="lazy"
width="960" height="640"
/&gt;
&lt;/p&gt;
&lt;p&gt;Looking after a baby is woman’s work. Now I am not being sexist but men are just not equipped. We can’t feed them, we don’t form the same emotional bonds and I suspect I am sleeping through the worst of his crying.&lt;/p&gt;
&lt;p&gt;That said I still want to help and be involved in looking after my son. But my natural inclination is to let mummy do most things and help where needed. Going to this dads event was my first chance to do things without mummy being around.&lt;/p&gt;
&lt;p&gt;So after James had his first feed and his bag had been filled with bottles of milk, nappies, change of clothes and all the other essential accessories for looking after a baby, I left the house with him strapped to my chest.&lt;/p&gt;
&lt;p&gt;The event was very low key. Once I got there I unloaded James from my chest and was left to spend time with him with the occasional chat from other dads, offers of coffee and sausage sandwiches from the organizers.&lt;/p&gt;
&lt;p&gt;James loves staring at the ceiling and the Storehouse had lots of bright lights for him to stare at. He also got to say hello to one of the other babies he has met before at church and the mums group my wife goes to. But it was not all smooth sailing, James didn’t like me sitting down, so I had to stand up holding him close to keep him calm. If I tried to sit down and offer him his bottle he would get grumpy.&lt;/p&gt;
&lt;p&gt;I think it is great that there are events like this for parents. A lot of events are targeted at mothers which is as it should be as they have the majority of work to do, but dads need the odd event to support them as well. Hopefully me and James will be back for more adventures like this.&lt;/p&gt;
&lt;p&gt;One of the things I am looking forward to as James gets older is taking him to places and spending time 1 to 1 with him like I did with my father. I don’t know what his interests will be but whatever it is I want to be there to encourage him.&lt;/p&gt;</description></item><item><title>Backing up SQL databases to Azure</title><link>https://blog-test.funkysi1701.com/posts/2015/backing-up-sql-databases-to-azure/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 15 Oct 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/backing-up-sql-databases-to-azure/</guid><category term="DevOps">DevOps</category><category term="Backups">Backups</category><category term="Azure">Azure</category><category term="SQL">SQL</category><description>&lt;p&gt;I recently read a blog post by &lt;a href="https://blog.sqlauthority.com/2015/10/06/sql-server-steps-to-backup-to-windows-azure-storage/" target="_blank" rel="noopener noreferrer"&gt;Pinal Dave&lt;/a&gt;
about how you can backup straight to Azure Storage. The procedure he described is only available for SQL Server 2014 or later.&lt;/p&gt;
&lt;p&gt;I won’t go into detail of this method as Pinal describes it better than I can, but the basic of it requires setting up credentials and then running a backup command that includes the URL of the storage container on Azure.&lt;/p&gt;
&lt;p&gt;Unfortunately I am running SQL Server 2005 so this process will not work for me but it did start me thinking of what ways there might be for me to use.&lt;/p&gt;
&lt;p&gt;The next thing I tried was &lt;a href="https://www.microsoft.com/en-us/download/details.aspx?id=40740&amp;amp;WT.mc_id=Blog_SQL_Announce_DI" target="_blank" rel="noopener noreferrer"&gt;Microsoft SQL Server Backup to Microsoft Azure Tool&lt;/a&gt;
. Unfortunately I did not get this tool to work correctly on my setup. However it sounds like a flexible tool that allows compression and encryption of your backup files. This tool redirects your backup files to your Azure Storage so even if I had got it to work correctly it would not have been an ideal solution as I want local copies of my backup files as well.&lt;/p&gt;
&lt;p&gt;After this I started to look at powershell again. Following on from my recent success with &lt;a href="https://www.funkysi1701.com/posts/2015/copying-settings-to-an-azure-website/" target="_blank" rel="noopener noreferrer"&gt;powershell&lt;/a&gt;
I know how to connect to my Azure account so all I needed to script was copying a file from my server to Azure.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Get-ChildItem *.bak -File -Recurse | Set-AzureStorageBlobContent -Container $DestContainer -Force
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This command gets all the backup files in a directory (the recurse switch looks in sub directories as well) and then pipes them to the Set-AzureStorageBlobContent command. This command uploads them to the storage container defined in $DestContainer. I have added the Force switch so that it will replace any files on Azure which have the same name.&lt;/p&gt;
&lt;p&gt;I have only been using this script for the last few days but so far it has been working well. Now if I completely loose all data from the office I can restore from any other location using the data saved on Azure. A great improvement to my disaster recovery policy.&lt;/p&gt;</description></item><item><title>The Hunted, TNG S3 E11 reviewed</title><link>https://blog-test.funkysi1701.com/posts/2015/the-hunted-tng-s3-e11-the-battle-bridge/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 08 Oct 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/the-hunted-tng-s3-e11-the-battle-bridge/</guid><category term="StarTrek">StarTrek</category><category term="Podcast">Podcast</category><category term="Trekmate">Trekmate</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/10/Danar_captured.jpg"/><description>&lt;p&gt;My latest podcast can be found at &lt;a href="https://www.trekmate.org.uk/the-hunted-tng-s3-e11-the-battle-bridge/" target="_blank" rel="noopener noreferrer"&gt;https://www.trekmate.org.uk/the-hunted-tng-s3-e11-the-battle-bridge/&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;While the Enterprise-D is reviewing a seemingly idyllic planet’s application for Federation membership, an escaped prisoner leads its crew to discover an ugly secret: the government’s shameful treatment of its war veterans.&lt;/p&gt;
&lt;p&gt;Today James and Lou discuss (The Hunted) and what we think of it and much more as well as listener feedback with tonight’s guest host Simon.&lt;/p&gt;
&lt;p&gt;Credit: Main Title Theme (TV Edit) was arranged by &lt;a href="https://memory-alpha.fandom.com/wiki/Dennis_McCarthy" target="_blank" rel="noopener noreferrer"&gt;Dennis McCarthy&lt;/a&gt;
and composed by &lt;a href="https://memory-alpha.fandom.com/wiki/Jerry_Goldsmith" target="_blank" rel="noopener noreferrer"&gt;Jerry Goldsmith&lt;/a&gt;
and &lt;a href="https://memory-alpha.fandom.com/wiki/Alexander_Courage" target="_blank" rel="noopener noreferrer"&gt;Alexander Courage&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;You can download the MP3 version of this show by &lt;a href="https://media.blubrry.com/previouslyalpha/p/media.blubrry.com/trekmatesupplemental/p/media.blubrry.com/loutrekshow/p/media.techpodcasts.com/loutrekshow/p/www.trekmate.org.uk/battlebridge/tbb-s3e11-the_hunted.mp3" target="_blank" rel="noopener noreferrer"&gt;clicking here&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Copying settings to an Azure Website</title><link>https://blog-test.funkysi1701.com/posts/2015/copying-settings-to-an-azure-website/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 01 Oct 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/copying-settings-to-an-azure-website/</guid><category term="Cloud">Cloud</category><category term="Azure">Azure</category><category term="DevOps">DevOps</category><category term="PowerShell">PowerShell</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/09/2275.app-1.png"/><description>&lt;p&gt;The Software as a Service (SaaS) website that I work on has been sold to lots of clients now. Which is great news.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Azure website app settings configuration screen" src="https://blog-test.funkysi1701.com/images/2015/09/2275.app-1.png" loading="lazy"
width="550" height="240"
/&gt;
&lt;/p&gt;
&lt;p&gt;However the more Azure websites we have, the more websites we have to administer, especially if like us you take advantage of Traffic Manager which requires multiple website in different regions. Azure has some great options for making this administration easier. One job is adding all the settings onto the Azure portal, so far I have been manually adding these, but a quicker way is to use powershell.&lt;/p&gt;
&lt;h2 id="powershell"&gt;PowerShell&lt;a class="anchor ms-1" href="#powershell" aria-label="Permalink: PowerShell"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PowerShell is everywhere these days. You can use it to control Servers, Active Directory and Exchange. So it is no surprise that you can use it to control Azure.&lt;/p&gt;
&lt;p&gt;Open a powershell window and run the following command.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Get-AzurePublishSettingsFile
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This command opens an IE window which you can login to Azure and download a file which contains settings that Azure can use. Save the *.publishsettings file and run the following command.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Import-AzurePublishSettingsFile &amp;#34;C:\MyPublishSettings\mysubscriptions.publishsettings&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This imports your Azure settings so that PowerShell can do clever things.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Select-AzureSubscription -Default &amp;#34;mysubscription&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This selects which of your Azure subscriptions to use. Now run the following to import settings into PowerShell.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$s = @{&amp;#34;DebugEmailAccount&amp;#34;=&amp;#34;test@example.com&amp;#34;;&amp;#34;SiteWarningBannerText&amp;#34;=&amp;#34;&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And finally run the following to import this settings into the Azure website you specified.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Set-AzureWebsite azure-websitename -AppSettings $s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sounds easy doesn’t it. Well it is. The hardest part is getting the settings in the correct format to be imported but this is only string manipulation.&lt;/p&gt;
&lt;p&gt;For my project I already have a build script which populates a settings.config file with all these settings, so I have just duplicated this to create a settings.config.importtoAzure file. Next time I have a website to create, I can create it on Azure and run the above script, pasting in the settings file that my build has already produced for me.&lt;/p&gt;
&lt;p&gt;This only scratches the surface of what you can do with Azure and PowerShell, hopefully I will do far more in the future.&lt;/p&gt;</description></item><item><title>Add internet connection resilience</title><link>https://blog-test.funkysi1701.com/posts/2015/adding-internet-connection-resiliency/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 24 Sep 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/adding-internet-connection-resiliency/</guid><category term="Fibre">Fibre</category><category term="VPN">VPN</category><category term="Internet">Internet</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/internet-connection-drops-every-couple-minutes-cable-sxchu-internet1.jpg"/><description>&lt;p&gt;I have been asked to investigate adding a fail over internet connection to one of our offices.&lt;/p&gt;
&lt;p&gt;Currently this office is connected via a wireless link with our head office. Unfortunately we have recently experienced some poor performance with this connection, this has now been corrected but like all technology there is the chance of it failing in some way in the future and causing loss of business because of it.&lt;/p&gt;
&lt;h2 id="internet-connection"&gt;Internet Connection&lt;a class="anchor ms-1" href="#internet-connection" aria-label="Permalink: Internet Connection"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is one of my first considerations. I need a reliable internet connection and there are a lot of options to consider, lets look at a few.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Internet Connection" src="https://blog-test.funkysi1701.com/images/2015/internet-connection-drops-every-couple-minutes-cable-sxchu-internet1.jpg" loading="lazy"
width="2193" height="837"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ADSL Connection&lt;/strong&gt; This is your standard internet connection that most homes have, you get around 20Mb/s download but only 2Mb/s upload for a fairly low price per month. Speeds are dependent on area and the quality and distance from your exchange, some rural areas have speeds much lower than this. As this connection is for an office I want the best connection I can afford so would rather not go down this option if I can avoid it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FTTC (Fibre to the Cabinet)&lt;/strong&gt; This is what ISPs typically mean when they say superfast broadband. The cables that have been laid to your exchange cabinet have been upgraded to fibre optic cables which are capable of much faster transfer speeds (eg 40Mb/s download and 10Mb/s upload). This is my ideal choice, however BT Openreach are responsible for upgrading the country to these cables and they are not very quick about it. A few years back when investigating this FTTC had almost reached our office, but when I investigated today nothing seems to have progressed. Both FTTC and ADSL require a phone line into the office to run on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Leased Line&lt;/strong&gt; This is where your ISP connects a dedicated line to your office which provides you a much faster connection (upload and download speeds are the same) but this is very expensive. We have this for our head office as this is where our servers are located and the faster speed benefits the entire company. We do not want to do this for every branch office as it will be too expensive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spur from a Leased Line&lt;/strong&gt; It could be possible to branch or spur off the leased line to our second office. This would be one leased line that terminates in two locations instead of one. However due to the distances involved I do not think this will be possible in my case and may end up costing as much as a second leased line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ISP&lt;/strong&gt; As well as the type of connection I need to decide who will provide it. There are hundreds of ISPs out there but I like to use ISPs that have a good reputation or I have used in the past and have been happy with. I do not stick with one ISP for all my connections as I like to have some connections that continue to work should that ISP be experiencing problems. ISPs that I would recommend are YDS, Eclipse and PlusNet&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Money Off&lt;/strong&gt; While I am talking about internet connections the government has been offering a scheme offering businesses money off upgrading their connections to a superfast connection (either FTTC or Leased Line) More information can be found on your councils website, If you have an office in York have a look here for more details. We got £3000 off installation so worth investigating if you qualify.&lt;/p&gt;
&lt;h2 id="vpn-connection"&gt;VPN Connection&lt;a class="anchor ms-1" href="#vpn-connection" aria-label="Permalink: VPN Connection"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Offices require access to far more resources than just the internet. This particular office requires access to our email and database servers as a bare minimum. One way to access a remote offices network resources is through a VPN (Virtual Private Network) connection. So my next consideration is how to establish a VPN link between our offices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Software&lt;/strong&gt; Windows Server includes RRAS (Routing and Remote Access Service) which you can use to configure a VPN connection. One important thing to note is that the server needs at least two network connections, one on the internet with a public IP and one on the internal network.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hardware&lt;/strong&gt; The more expensive routers often have settings that allow the configuration of a VPN connection.&lt;/p&gt;
&lt;p&gt;I have used both of these methods in the past. RRAS is a pain to work with but has evolved with the newer versions of windows server, so may not be as bad as I remember. Using a router to do VPN introduces its own set of problems and there is no guarantee of avoiding RRAS, you may still need it to authenticate the VPN provided by your router.&lt;/p&gt;
&lt;h2 id="multiple-connection-handling"&gt;Multiple Connection Handling&lt;a class="anchor ms-1" href="#multiple-connection-handling" aria-label="Permalink: Multiple Connection Handling"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Internet connectivity is being provided in two ways, the primary way is via a Wireless link and the second way is via one of the options above.&lt;/p&gt;
&lt;p&gt;There are lots of options to deal with multiple connections, do I want to load balance both connections and use them all the time, do I want to fail over onto the second connection only if the first one fails, or do I want it to be a manual process or switching over to the backup network if problems occur.&lt;/p&gt;
&lt;p&gt;As you can see there are lots of different technologies to consider before I can add resiliency to this office and I haven’t even started to think about if an additional server will be required.&lt;/p&gt;</description></item><item><title>Unmanaged Database Deployment</title><link>https://blog-test.funkysi1701.com/posts/2015/unmanaged-database-deployment/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 10 Sep 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/unmanaged-database-deployment/</guid><category term="SQL">SQL</category><category term="Backups">Backups</category><category term="Deployment">Deployment</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/09/deploy.jpg"/><description>&lt;p&gt;For the past few months I have been deploying changes to my companies database every couple of weeks or so. Over a weekend when the database was not being used I would make a backup of the database, load up visual studio, deploy the database changes and copy a couple of front-end files.&lt;/p&gt;
&lt;p&gt;My weekends and evenings have recently become a bit more precious to me since the arrival of my son James. At suitable times to run the database upgrade I am either, asleep, about to fall asleep or be spending time with James.&lt;/p&gt;
&lt;p&gt;This entire deployment can be set to run at a time of my choosing using SQL Server Jobs, (not sure why I never thought of doing this before). I still need to check everything is working after it has run. The job can send me an email if it encounters any problems so I can still ensure the company has the minimum of problems but has more frequent changes.&lt;/p&gt;
&lt;h2 id="unmanaged-database-deployment"&gt;Unmanaged Database Deployment&lt;a class="anchor ms-1" href="#unmanaged-database-deployment" aria-label="Permalink: Unmanaged Database Deployment"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OK so what do I need to do to set this up.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Database deployment workflow diagram" src="https://blog-test.funkysi1701.com/images/2015/09/deploy.jpg" loading="lazy"
width="711" height="811"
/&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Test all your code changes are working correctly on a backup of the database and everything is committed to source control.&lt;/li&gt;
&lt;li&gt;Backup everything that is going to be changed so it can be rolled back in case of a problem. I don’t rely on the daily backup jobs for this, I do my own. Maybe I am a bit paranoid, or maybe I am just being cautious.&lt;/li&gt;
&lt;/ol&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BACKUP &lt;span style="color:#66d9ef"&gt;DATABASE&lt;/span&gt; DBName &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; DISK&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;E:\SQL Backups\Filename.bak&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I would include in the backup file name the date and time of the deployment for easy reference later on. For the front-end files these are backed up daily and only ever change during a deployment so I am going to rely on the day to day backups, plus they are in source control so in a worse case scenario I can look there.&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;From Visual Studio create a deployment script using the publish option and save as a file on your database server.&lt;/li&gt;
&lt;li&gt;Create a SQL Server Job and give it a descriptive name.&lt;/li&gt;
&lt;li&gt;In steps create a step called backup and enter the T-SQL code above. Set this to stop on failure and continue on success.&lt;/li&gt;
&lt;li&gt;Create a second step called upgrade of type operating system with the following code.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sqlcmd -S (local) -i &amp;#34;E:\SQL Backups\deploy_test.sql&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The -S parameter is the name of your SQL Server instance and the -i parameter is the path to the sql script you generated from Visual Studio above. Set this job to quit reporting success or failure.&lt;/p&gt;
&lt;ol start="7"&gt;
&lt;li&gt;In schedule create a date time you want the job to run, make sure this is a one time job as you don’t want it to try and run again possibly causing problems.&lt;/li&gt;
&lt;li&gt;In notifications I have set to email on completion, you can set it to email on failure only. I would prefer to know the outcome of the job regardless.&lt;/li&gt;
&lt;li&gt;Using SQL Server jobs to copy files over the network is possible but is not trivial to setup so I am going to use windows task scheduler for this.&lt;/li&gt;
&lt;li&gt;Create a job in task scheduler to copy all the ADPs or ADEs that have been changed. If the SQL job fails you will need to copy the old versions of these back but that is simple enough to do.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This process can be expanded to check code out of source control and do even more automated deployments but for now this is good enough for my purposes.&lt;/p&gt;</description></item><item><title>Baby Magic and Becoming a Father</title><link>https://blog-test.funkysi1701.com/posts/2015/baby-magic-and-becoming-a-father/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 03 Sep 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/baby-magic-and-becoming-a-father/</guid><category term="Father">Father</category><category term="Baby">Baby</category><category term="Family">Family</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/07/james5.jpg"/><description>&lt;p&gt;I am pleased to announce the birth of James David Martin Foster weighing 9 lb 12 on 19th August 2015.&lt;/p&gt;
&lt;p&gt;Mother and Baby (and Father) are doing well.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Newborn baby James" src="https://blog-test.funkysi1701.com/images/2015/07/james5.jpg" loading="lazy"
width="1080" height="810"
/&gt;
&lt;/p&gt;
&lt;p&gt;I am not a baby person, I hate children and I run a mile from other people’s babies.&lt;/p&gt;
&lt;p&gt;But James performed some magic on me and now I will do anything for him. If you have had children you probably know what I am talking about and if you haven’t you are probably like me 24 hours before James arrived.&lt;/p&gt;
&lt;p&gt;During the pregnancy I had been living in denial that I would become a father, despite the wife speaking about nothing else and our home filing with baby equipment. It was only minutes before I first saw my son that I changed.&lt;/p&gt;
&lt;p&gt;Due to James’s large size, the birth wasn’t easy. After about an hour of pushing the midwife called in a team of doctors and nurses to help and I think it was at this point that it started to hit me. I am not an emotional man, if anything I tend to repress my feelings but I completely and utterly failed to do that on this occasion. By the time the baby had been placed on my wife’s chest tears of joy were streaming down my face and this continued for some time. Moments after birth James had a tight grip on my finger. His tiny hands were like miniature versions of my own hands.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Baby James holding finger" src="https://blog-test.funkysi1701.com/images/2015/08/jameshand.jpg" loading="lazy"
width="562" height="1000"
/&gt;
&lt;/p&gt;
&lt;p&gt;I have been asked what it felt like holding James in my arms for the first time, this happened on the following day. I am not sure if I can put it into words, but a few adjectives come to mind, amazing, great, fantastic, humbling. James depends on me (and his mother) for everything and his existence has put a new spin on everything I do. I want to be there for him, help him learn stuff, provide for him and love him.&lt;/p&gt;
&lt;p&gt;I have been working very hard recently, spending my free time writing this blog, learning stuff and doing other work. The reasons for this hard work are now clear, I work so I can provide for James and so I can spend my free time with him.&lt;/p&gt;
&lt;p&gt;Before James arrived I had it in my head that his mother would do the majority of the caring for him. This is not going to happen now that I have met James. I want to cuddle him, change his nappies, dress him, hold his hand, take him to school, watch TV with him, stroke his head when he is ill, tell him about my life experiences, introduce him to wine, tell him about girls, help him move home, etc.&lt;/p&gt;
&lt;p&gt;I am not saying being a parent is going to be easy. I am pretty clueless about what is in store for us, but already I am worrying if he is OK, trying to calm him down when he is upset and being woken in the early hours.&lt;/p&gt;
&lt;p&gt;Anyway only time will tell if I continue being this positive about fatherhood, but so far I am loving it. Normal blog posts will hopefully resume over the next few weeks (or when I have time).&lt;/p&gt;</description></item><item><title>Due Dates</title><link>https://blog-test.funkysi1701.com/posts/2015/due-dates/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 17 Aug 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/due-dates/</guid><category term="DueDate">DueDate</category><category term="Baby">Baby</category><category term="Estimate">Estimate</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/08/928f90bcd221f78a30f18541a5ca2e7f.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Expectant parents awaiting a baby&amp;rsquo;s due date" src="https://blog-test.funkysi1701.com/images/2015/08/928f90bcd221f78a30f18541a5ca2e7f.jpg" loading="lazy"
width="404" height="337"
/&gt;
As I write this I have less than 2 days until the due date for the birth of my first child.&lt;/p&gt;
&lt;p&gt;Its a very exciting time, but it is also infuriating waiting for it to arrive. Even in the 21st century science can not predict with any accuracy when a baby is going to arrive and we just have to wait for mother nature to do its thing.&lt;/p&gt;
&lt;p&gt;I feel like I am stuck in limbo at the moment I have lots of work to do, lots of development changes to do on the databases, but I also know that at a moments notice I need to drop what I am doing and try and be a father.&lt;/p&gt;
&lt;p&gt;Due dates for babies is based on average pregnancies lasting 40 weeks, but there is no such thing as an average pregnancy. But to keep this blog post on topic I somehow need to compare due dates for pregnancy with software development.&lt;/p&gt;
&lt;p&gt;In software development we often get asked for estimates on when a particular development task will be finished. Estimates in software development are very difficult to make accurate as there are so many variables that you do not know the answer to until you start getting stuck into doing the work. One technique is to try and split the work down into small steps and estimate how long each small step will take and then add them all together. But even this technique still has a large margin of error.&lt;/p&gt;
&lt;p&gt;What would it be like if when management asked we gave an estimate similar to what pregnant women receive? Instead of a deadline when all work has to be finished by, you have a date when there is a 50% chance of the work being finished.&lt;/p&gt;
&lt;p&gt;I think management would have a difficult time dealing with this amount of uncertainty, I certainly am waiting for this baby to arrive.&lt;/p&gt;</description></item><item><title>How complex are my stored procs?</title><link>https://blog-test.funkysi1701.com/posts/2015/how-complex-are-my-stored-procedures/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 13 Aug 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/how-complex-are-my-stored-procedures/</guid><category term="Complexity">Complexity</category><category term="SQL">SQL</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/08/complexity.jpg"/><description>&lt;p&gt;Recently me and my development team have been looking at performance and how to improve it.&lt;/p&gt;
&lt;p&gt;One area of improvement we have identified is with our stored procedures, which we plan to rewrite. But how do we identify which are the easiest to rewrite and which are the hardest?&lt;/p&gt;
&lt;p&gt;My first thought was maybe to count the number of times each keyword is used and rank them somehow. eg each JOIN gets 5, OUTER APPLY gets 20, each term in WHERE gets 1, and then combine that with the length of the query and how many parameters.&lt;/p&gt;
&lt;p&gt;However doing a bit of googling I came across the following &lt;a href="https://aalamrangi.wordpress.com/2012/12/24/calculate-tsql-stored-procedure-complexity" target="_blank" rel="noopener noreferrer"&gt;blog&lt;/a&gt;
and &lt;code&gt;https://gallery.technet.microsoft.com/Calculate-TSQL-Stored-831b683a&lt;/code&gt;. This script analyses the stored procedures in terms of number of lines of code, number of parameters and number of dependencies.&lt;/p&gt;
&lt;p&gt;The complexity is divided into SIMPLE, MEDIUM and COMPLEX.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;WHEN NumberOfLines * NumberOfDependencies * NumberOfParameters &amp;lt; 5000 THEN ‘Simple’
WHEN NumberOfLines * NumberOfDependencies * NumberOfParameters &amp;lt; 10000 THEN ‘Medium’
ELSE ‘Complex’
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;
&lt;img class="img-fluid" alt="SQL stored procedure complexity report screenshot" src="https://blog-test.funkysi1701.com/images/2015/08/reportscreenshot1.png" loading="lazy"
width="674" height="235"
/&gt;
&lt;/p&gt;
&lt;p&gt;This gives a fairly good estimate of which stored procedures are the most complex and which would probably take the longest time to rewrite.&lt;/p&gt;</description></item><item><title>ICYMI What does it mean?</title><link>https://blog-test.funkysi1701.com/posts/2015/icymi-what-does-it-mean/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 10 Aug 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/icymi-what-does-it-mean/</guid><category term="ICYMI">ICYMI</category><category term="Learning">Learning</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/08/in-case-you-missed-it-small.jpg"/><description>&lt;p&gt;For a while now I have seen ICYMI splattered around the internet. I had no idea what it meant so just ignored it but I have finally had enough and I googled for a definition and I now know what it means.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ICYMI – In Case You Missed It
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;
&lt;img class="img-fluid" alt="ICYMI acronym explained as In Case You Missed It" src="https://blog-test.funkysi1701.com/images/2015/08/in-case-you-missed-it-small.jpg" loading="lazy"
width="400" height="400"
/&gt;
ICYMI is often used on social media sites to indicate articles that you might have missed.&lt;/p&gt;
&lt;p&gt;Software Development is littered with acronyms and technical terms that I don’t always know the meaning of.&lt;/p&gt;
&lt;p&gt;When reading it is easy to ignore them and try and understand the rest of the article. However there are loads of resources out there that can explain technical terms in a wide variety of different ways.&lt;/p&gt;
&lt;p&gt;I have tried to explain a few different terms and concepts on this &lt;a href="https://www.funkysi1701.com/" target="_blank" rel="noopener noreferrer"&gt;blog&lt;/a&gt;
. In the process of writing them I often do a bit of research and read a variety of different definitions, some confuse the heck out of me, while others make me go ahh that makes sense now.&lt;/p&gt;
&lt;p&gt;When reading to learn, don’t be afraid to dig deeper and understand it all, don’t read the same terms again and again not understanding them like I did with ICYMI.&lt;/p&gt;</description></item><item><title>Common git commands</title><link>https://blog-test.funkysi1701.com/posts/2015/common-git-commands/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 06 Aug 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/common-git-commands/</guid><category term="Git">Git</category><category term="SourceControl">SourceControl</category><description>&lt;p&gt;I use git as my source control system. Here are some of the most common git commands in no particular order.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check Out a git Repository &lt;strong&gt;git clone /path/to/repository&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Add files to commit &lt;strong&gt;git add &lt;filename&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Commit files to &lt;strong&gt;git git commit -m “Commit message”&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Push changes to server &lt;strong&gt;git push origin master&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Show status &lt;strong&gt;git status&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Create new branch &lt;strong&gt;git checkout -b &lt;branchname&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Switch to a branch &lt;strong&gt;git checkout &lt;branchname&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Get remote changes &lt;strong&gt;git pull&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Merge a different branch into the current one &lt;strong&gt;git merge &lt;branchname&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;View merge conflicts &lt;strong&gt;git diff&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Temporarily stash uncommitted changes &lt;strong&gt;git stash&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Undo a commit &lt;strong&gt;git reset –hard &lt;commit&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Show details about a commit &lt;strong&gt;git show &lt;commit&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Show version history of current branch &lt;strong&gt;git log&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Gets all remote branches &lt;strong&gt;git fetch origin&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most of the time I use the &lt;a href="https://sourceforge.net/projects/gitextensions/" target="_blank" rel="noopener noreferrer"&gt;git extensions&lt;/a&gt;
tools to do my git work, but there are times when only the command line will do.&lt;/p&gt;</description></item><item><title>Volunteering for a Technical Team</title><link>https://blog-test.funkysi1701.com/posts/2015/volunteering-for-a-technical-team/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 03 Aug 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/volunteering-for-a-technical-team/</guid><category term="EasyWorship">EasyWorship</category><category term="Church">Church</category><category term="Volunteers">Volunteers</category><category term="Projection">Projection</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/20150802_113719.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Church worship projection desk with screens and equipment" src="https://blog-test.funkysi1701.com/images/20150802_113719.jpg" loading="lazy"
width="5312" height="2988"
/&gt;
For the past few years I have volunteered on the technical team at my local church &lt;a href="https://www.belfrey.org/" target="_blank" rel="noopener noreferrer"&gt;St Michael le Belfrey&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;For the church to function well it requires volunteers in all sorts of roles, people to welcome visitors, people to pray, people to play music, people to look after children and many other roles.&lt;/p&gt;
&lt;p&gt;My natural ability lies more with technology than with people so when I decided that I wanted to get more involved it was the technical team that I volunteered for. The technical team is split into two main parts, the PA team which concerns itself with ensuring everyone can hear everything OK and the Projection team which concerns itself with everything that gets projected. I have no knowledge about what sounds good and what doesn’t so it was the projection team that I joined and have been involved with.&lt;/p&gt;
&lt;p&gt;The church has three projectors, one big one and two slightly smaller ones for the side aisles, and a PC located at the back of church which is what the projectionist uses to control what gets projected. There are many things that get projected, lyrics to songs, PowerPoint presentations and the occasional video and to make things easy one piece of software is used to control all of this &lt;a href="https://easyworship.com/" target="_blank" rel="noopener noreferrer"&gt;EasyWorship&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;EasyWorship contains a huge database of song lyrics, so you can quickly select what ever is being sung and project the lyrics on screen. It also allows the addition of PowerPoint files, image or video files and even a web page and they can be projected. EasyWorship allows different things to be queued up in order and that order can be saved as a schedule.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Projection team volunteers at St Michael le Belfrey church" src="https://blog-test.funkysi1701.com/images/2015/CFMwY_UUgAAc2k2.jpg" loading="lazy"
width="600" height="450"
/&gt;
&lt;/p&gt;
&lt;p&gt;The projectionist’s job is to follow along with the order of service and project things onto screen at the right time. Simple! No not really. The worship leader will skip songs, play songs in a different order, add new songs, videos will fail to play, easy worship will freeze up or crash or the liturgy that the vicar wants isn’t in the EasyWorship database.&lt;/p&gt;
&lt;p&gt;You need to be on your toes as a projectionist but over the years I have become a good projectionist and have really enjoyed my time doing this. You can see me having a laugh with the Head of Music and Worship on the right.&lt;/p&gt;
&lt;p&gt;More recently I have taken on a bigger role for the projection team. I have been coordinating the rota for the volunteers on the projection team. This has given me new challenges, but it has been great to work closely with the Technical Manager and more recently the Head of Music and Worship and get to know the whole team better. The biggest problem that the team has is insufficient volunteers, it had this problem when I joined the team and it has this problem today. If you are reading this consider if this is something you could get involved with? The team has some really hard working people who do an excellent job each week, just wish we had a few more to ease everyone’s work load.&lt;/p&gt;
&lt;p&gt;I am taking a break from the projection team as my wife is due to give birth to my first child in the next few days. I have had a great time, I have worked with some great people and for the most part I will miss volunteering. There are of course things that have not been great, volunteers that have left the team, changes at the church, and many early mornings when I would rather still be in bed but I am glad that I have been involved.&lt;/p&gt;</description></item><item><title>Upper Pylon 2 x09: The Passenger</title><link>https://blog-test.funkysi1701.com/posts/2015/upper-pylon-2-1-x-09-the-passenger/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 30 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/upper-pylon-2-1-x-09-the-passenger/</guid><category term="StarTrek">StarTrek</category><category term="Podcast">Podcast</category><category term="Trekmate">Trekmate</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/07/Bashir-Choked.jpg"/><description>&lt;p&gt;I recorded another podcast the other week; it can be found at &lt;a href="https://www.trekmate.org.uk/upper-pylon-2-1-x-09-the-passenger/" target="_blank" rel="noopener noreferrer"&gt;https://www.trekmate.org.uk/upper-pylon-2-1-x-09-the-passenger/&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Doctor Bashir being choked in DS9 episode The Passenger" src="https://blog-test.funkysi1701.com/images/2015/07/Bashir-Choked.jpg" loading="lazy"
width="638" height="480"
/&gt;
&lt;/p&gt;
&lt;p&gt;This week on Upper Pylon 2, we are joined by our first UK guest, Simon (aka &lt;a href="https://twitter.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;funkysi1701&lt;/a&gt;
) as we take a look at the Bashir-centric “mystery” episode, “The Passenger.”&lt;/p&gt;
&lt;p&gt;When a former prisioner, Rao Vantika (a name you’ll hear COUNTLESS times throughout the episode) is killed, his pursuer believes that the late murderer is not really dead, and continues her investigation at DS9 while an important shipment is scheduled to arrive. Will Vantika reappear, and if so, who will he appear as? Well, if you’ve seen the opening of the episode, it really isn’t all that hard to deduce. But join the UP2 crew as we dissect this little caper.&lt;/p&gt;
&lt;p&gt;As always, be sure to leave us your feedback about the episode!&lt;/p&gt;</description></item><item><title>10 facts about Windows 10</title><link>https://blog-test.funkysi1701.com/posts/2015/10-facts-about-windows-10/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 29 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/10-facts-about-windows-10/</guid><category term="Microsoft">Microsoft</category><category term="Windows10">Windows10</category><category term="OperatingSystem">OperatingSystem</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/07/Windows-10_Product-Family.jpg"/><description>&lt;p&gt;Today Microsoft release Windows 10 so what else can I talk about? I like many technology people are very excited today. This version of window is the first that Microsoft have release for free.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Windows 10 product family across devices" src="https://blog-test.funkysi1701.com/images/2015/07/Windows-10_Product-Family.jpg" loading="lazy"
width="1920" height="1080"
/&gt;
&lt;/p&gt;
&lt;p&gt;10 You heard that correct Windows 10 is &lt;strong&gt;free&lt;/strong&gt;. If you upgrade your device to windows 10 before 29th July 2016 it is free and will continue working on that device forever.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Upgrade to Windows 10 within the first year and it is yours free, forever.
No subscriptions, no additional costs.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;9 As with any upgrade always backup your computer and any important files before you do anything. Microsoft and any IT expert will tell you this. For a great guide to upgrading see Scott Hansleman’s &lt;a href="https://www.hanselman.com/blog/getting-started-with-windows-10" target="_blank" rel="noopener noreferrer"&gt;blog&lt;/a&gt;
. I have upgraded my laptop without any problems but there will always be exceptions so take extra care.&lt;/p&gt;
&lt;p&gt;8 Windows 10 is the &lt;strong&gt;LAST&lt;/strong&gt; version of windows. I don’t know what this means but I can take a guess.&lt;/p&gt;
&lt;p&gt;Typically Microsoft has created a new version of windows every few years. With every new version there has come headaches and problems as people try to make software and hardware work with the next version. Microsoft is instead going to try and release updates and patches to the operating system to keep things up to date.&lt;/p&gt;
&lt;p&gt;However I can see that only working for so long. Eventually Microsoft will make something new but it is unlikely to be called Windows. Maybe it will be something hosted in the Cloud, as they have a really strong presence with Azure which is only going to grow as time goes on.&lt;/p&gt;
&lt;p&gt;7 Windows 10 is available in 7 different flavours.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 10 Home – equivalent to the Home editions we have had since XP. This version is designed for your typical consumer.&lt;/li&gt;
&lt;li&gt;Windows 10 Mobile – this version is designed to run on phones and tablets. Unlike previous Phone versions, everything you can find on the desktop OS should be available on the phone (but optimised for the smaller screens)&lt;/li&gt;
&lt;li&gt;Windows 10 Pro – this is the version I will be testing with my work PCs. It is designed for small businesses and allows domain joining.&lt;/li&gt;
&lt;li&gt;Windows 10 Enterprise – this version is only available via Volume Licensing so not easily available to the typical user but is aimed at larger businesses.&lt;/li&gt;
&lt;li&gt;Windows 10 Education – another version that is only available via Volume Licensing but targeted at schools and universities.&lt;/li&gt;
&lt;li&gt;Windows 10 Mobile Enterprise – this version is for mobile and tablets in the business world. Standard policies can be applied to all your employees mobile devices.&lt;/li&gt;
&lt;li&gt;Windows 10 IoT Core – this is an interesting version designed to run on hardware and Internet of Things (IoT) devices. I would quite like to play with this version on my Raspberry Pi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;6 Windows 10 introduces a brand new web browser called Edge. For years web developers have hated Internet Explorer, for its lack of support for the latest web standards. Internet Explorer 6 caused many users to migrate away to browsers like firefox and later Chrome and despite Microsoft’s best effort with the later versions people have not moved back. Edge is an attempt at a fresh start.&lt;/p&gt;
&lt;p&gt;5 In 2011 Apple introduced the personal assistant Siri, well now Microsoft are bringing us &lt;strong&gt;Cortana&lt;/strong&gt; the windows equivalent. With Cortana you can ask your computer to do anything, set reminders, search the internet, answer questions, anything. With advanced voice recognition you can speak as well as type your questions. Cortana is now part of Windows 10.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Windows 10 desktop screenshot with Start menu" src="https://blog-test.funkysi1701.com/images/2015/05/win10.jpg" loading="lazy"
width="888" height="537"
/&gt;
&lt;/p&gt;
&lt;p&gt;4 Windows 10 brings back the start menu. The start menu you have always used to access programs works the same but features of the windows 8 start screen have been incorporated into it.&lt;/p&gt;
&lt;p&gt;3 Windows 10 is more &lt;strong&gt;secure&lt;/strong&gt;. Security patches are frequently released for all operating systems, but windows 10 has been designed with security in mind. For businesses there are options to completely lock down your users environment only allowing ‘white listed’ programs to run.&lt;/p&gt;
&lt;p&gt;2 &lt;strong&gt;Continuum&lt;/strong&gt; is one of the most revolutionary things about Windows 10. Continuum is the notion that one computing experience is continued regardless of the device used or the location. Continuum will automatically adjust your screen to make the best use of its size. Tablets and phones have the tiled view and start screen, if you connect a keyboard and monitor it will behave like a full blown PC. This is mind bending, that a phone running windows 10 can do as much as your laptop.&lt;/p&gt;
&lt;p&gt;1 Today I am off to a Windows 10 launch event where I expect many of these features will be discussed and most likely many more.&lt;/p&gt;</description></item><item><title>Writing better Git commit messages</title><link>https://blog-test.funkysi1701.com/posts/2015/writing-better-git-commit-messages/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 25 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/writing-better-git-commit-messages/</guid><category term="Git">Git</category><category term="SourceControl">SourceControl</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/07/git_commit.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="XKCD comic about Git commit messages" src="https://blog-test.funkysi1701.com/images/2015/07/git_commit.png" loading="lazy"
width="439" height="250"
/&gt;
&lt;/p&gt;
&lt;p&gt;I always use source control for my coding changes, however some of my commit messages leave something to be desired.&lt;/p&gt;
&lt;p&gt;I always try to write a commit message but I often think that the change themselves should be enough to indicate what I did. I also don’t need to include who made the change or the time and date and that gets included automatically.&lt;/p&gt;
&lt;p&gt;Here are some tips I have found that may help me in the future.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Ask yourself why you are making this change. The Who, When and What are already being covered so it is only the why that needs including in the commit message.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If your commit breaks something or causes side affects or a new dependency this should be included in the commit message. If your commit breaks functionality, consider if you really need to commit it yet, maybe only commit once fixed?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If your commit includes a long list of changes consider if the commit needs splitting into several commits. It is easy to only commit one or two files write a specific commit message and then commit the rest of the changes separately.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider including a subject for larger commits. The following comes from the git manual.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Though not required, it’s a good idea to begin the commit message with a single short
(less than 50 character) line summarizing the change, followed by a blank line and then
a more thorough description. The text up to the first blank line in a commit message
is treated as the commit title, and that title is used throughout Git.
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="5"&gt;
&lt;li&gt;If you use a subject follow the following conventions:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Limit of 50 characters&lt;/li&gt;
&lt;li&gt;Start with a capital letter&lt;/li&gt;
&lt;li&gt;Do not end with a full stop&lt;/li&gt;
&lt;li&gt;Use the imperative mood i.e. write as if issuing a command&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>My love/hate with Microsoft Access</title><link>https://blog-test.funkysi1701.com/posts/2015/microsoft-access/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 24 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/microsoft-access/</guid><category term="Database">Database</category><category term="Access">Access</category><category term="SQL">SQL</category><category term="VBA">VBA</category><category term="MicrosoftOffice">MicrosoftOffice</category><description>&lt;p&gt;For historical reasons I use Microsoft Access as the front-end for all my line of business databases.&lt;/p&gt;
&lt;p&gt;Access allows you to create an ADP file that can connect to your SQL Server database. However Office has dropped support for this, so the last version of office that I can use is Office 2010.&lt;/p&gt;
&lt;p&gt;Before I start hating on Access there are some good things about the platform. Users with very little knowledge can create a database fairly quickly. Development time is also fairly low as it doesn’t take long to create a new form, and add a few buttons which open different reports.&lt;/p&gt;
&lt;p&gt;For the last 5 years or so I have built a range of different forms in Access, (and even if I do say so myself), I have got quite good at creating forms that users can be more productive with. Access has the concept of a subform which is a form embedded in a form, each form can be connected to a different query and can be connected to each other so it is relatively easy to create something quite powerful.&lt;/p&gt;
&lt;p&gt;Access report are an easy way to create professional looking reports that can be sent out to clients, or used by management and they also have the concept of subreports, (same as subforms but embedded in a report), this means you don’t have to write one query to pull back every piece of data that shows up in a report.&lt;/p&gt;
&lt;p&gt;VBA or Visual Basic for Access allows you easily do things programmatically, like run something if something is selected or a button is clicked. This is not the easiest programming language to work with, however once you have used it for a while you get used to its quirks. My favourite function is IIF, the syntax is fairly simple IIF(expr, truepart, falsepart), if expr evaluates to true the truepart is executed (executed can be as simple as displaying certain text in certain conditions), if it is false the falsepart is executed, and you can also chain them together which I have done to produce something very complex looking.&lt;/p&gt;
&lt;p&gt;Now for the negative side of things. Access creates a binary ADP file, binary files can not be version controlled in git or subversion. This is a big problem as I want to keep track of every change I make. It also means that branching or working with others on big projects is also difficult.&lt;/p&gt;
&lt;p&gt;One work around I have found to this problem is &lt;a href="https://accesssvn.codeplex.com/" target="_blank" rel="noopener noreferrer"&gt;AccessSVN&lt;/a&gt;
. This program takes an ADP and creates text files of every form and report. It also can create an ADP from these files as well, however I have had varying success with this feature so I prefer to just create the text files if possible. What I do after I have made a change to the ADP is to run AccessSVN, create text files and commit these to source control. You can then see what controls have been changed or added. It also helps with bugs as I have found that sometimes while testing access will apply a filter to a form, which will break things if deployed, which is very annoying.&lt;/p&gt;
&lt;p&gt;Access can only do what access was designed to do. There are some advanced features that we would like to add to our databases. Things like sending emails or uploading reports to a website. This is not Access fault as it was never designed to be able to do such things but I am often asked about what is possible.&lt;/p&gt;
&lt;p&gt;End of support for Office 2010 is approaching and I have plans to stop using Access but until then I need to keep supporting our existing front ends.&lt;/p&gt;</description></item><item><title>Seven signs you are a bad programmer</title><link>https://blog-test.funkysi1701.com/posts/2015/7-warning-signs-that-you-are-a-bad-programmer/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 23 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/7-warning-signs-that-you-are-a-bad-programmer/</guid><category term="BadProgrammer">BadProgrammer</category><category term="Plan">Plan</category><category term="SourceControl">SourceControl</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/07/you_are_coding_it_wrong.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="You are coding it wrong" src="https://blog-test.funkysi1701.com/images/2015/07/you_are_coding_it_wrong.png" loading="lazy"
width="359" height="232"
/&gt;
&lt;/p&gt;
&lt;p&gt;Am I a good programmer or a bad programmer?&lt;/p&gt;
&lt;p&gt;Here are 7 signs that might mean you are more towards the bad end of the scale.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1: You fail to plan before you start coding&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am very guilty of this, I love to jump into the code before thinking. But I am slowly starting to see the advantages of sketching a few things out before I write any code.&lt;/p&gt;
&lt;p&gt;Most of my coding recently has been SQL based and I am starting to like sketching out table designs. I have also started to sketch out the UI before I start coding. I am not saying that you need to plan every single line of code, but a little bit of planning can go a long way.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2: You fail to use version control&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have blogged about using version control in the past but it really is a very useful technology. It not only keeps track of every file in your solution and stores its entire history, but you can separate different versions into branches and see who changed what and when (and if the commit message is detailed enough why).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3: You use bad variable names&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whats wrong with variable1 and variable2 as variable names? Variables should be named after what they do or what they contain, but it is very easy to start copy and pasting them and before you know it you have a variable1 and variable2 situation. Remember that Visual Studio has some powerful refactoring tools so relatively easy to get them back in order.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;4: You repeat your code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve been reading Pragmatic Programmer and one of their first tips was DRY – Don’t Repeat Yourself. They go to extremes with nothing being repeated anywhere in your code, but I don’t think you need to go too far, you can be reasonable. If you have the same code repeated four times, then creating a function for this code will dramatically improve your code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5: You struggle to understand your own code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why did I do it this way? I feel like I am always trying to remember the reasons I chose to code the way I did previously. Part of the reason for this is that I am constantly learning at the moment, but there is more that I can do to help myself understand in the future.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;6: You are selfish and don’t share&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am not selfish, if I learn something really cool I have to tell someone. I like writing stuff on here to share with the world. I am thinking of news ways to train my staff.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;7: You work on multiple projects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yes Guilty as charged with this one. I have multiple projects that I am working on at work, I also have a fair few personal projects that I would like to work on. Not sure I completely agree that multiple projects equals bad programmer.&lt;/p&gt;</description></item><item><title>Things to know before database work</title><link>https://blog-test.funkysi1701.com/posts/2015/things-to-know-before-working-on-your-databasethings-to-know-before-working-on-your-database/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 20 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/things-to-know-before-working-on-your-databasethings-to-know-before-working-on-your-database/</guid><category term="Backups">Backups</category><category term="SQL">SQL</category><category term="DisasterRecovery">DisasterRecovery</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/07/uf010206.jpg"/><description>&lt;p&gt;I recently saw this blog &lt;a href="https://www.brentozar.com/archive/2015/07/questions-to-ask-before-you-touch-a-database-server/" target="_blank" rel="noopener noreferrer"&gt;post&lt;/a&gt;
by &lt;a href="https://www.brentozar.com/team/brent-ozar/" target="_blank" rel="noopener noreferrer"&gt;Brent Ozar&lt;/a&gt;
that I thought I might discuss.&lt;/p&gt;
&lt;p&gt;Brent listed 13 questions to ask about a database before you start working with it. I am going to go through these 13 questions and expand on them based on my experiences.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Is this database in production now?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I think it should go without saying that the first thing you should find out is if your database is in production. If its not in production you can do what you like and no one will notice.
I know what databases are in production and which aren’t where I work so I can answer this one.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;If this goes down, what apps go down with it?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What apps are running on what databases is a good second question. I have at least one database which has multiple front end apps. At first glance you would think that that these two apps are not connected but they are, I need to be careful with both of these apps to make sure they don’t break each other.
I know what apps run off what databases.&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;When those apps go down, is there potential for loss of life or money?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is a difficult question so I will split it into two. Loss of life, my databases don’t control life support machines or nuclear weapons so my first instinct would be to say no. However it is not that straightforward, what if your app allowed contractors to know the location of dangers inside a property they were working in. Once your app goes down, they could have an accident due to lack of information.
Loss of money, this one is more straightforward. Time is money in the business world so any time that your app is down and your employees are not able to work is a loss of money. If your database is linked to an eCommerce site, the loss of money could be extremely high.
I know what affect downtime will have on my users and business.&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;How sensitive are these apps to temporary slowdowns?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Similar to the previous question, a slowdown can be as serious as downtime for some applications.
Luckily most of my apps are internal only so are not seriously affected by slowness.&lt;/p&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;When was the last successful backup?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I manage the backup schedule for all my databases so I know exactly when each one was last backed up. When ever I do anything to a production database I will run a backup so I can roll back in case of problems. As part of developing changes I run my changes on a backup of the data. I can script all my changes and repeatedly run them against a backup until I am sure no problems will occur.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Illustration of SQL Server database backup and restore" src="https://blog-test.funkysi1701.com/images/2015/07/uf010206.jpg" loading="lazy"
width="233" height="238"
/&gt;
&lt;/p&gt;
&lt;ol start="6"&gt;
&lt;li&gt;&lt;strong&gt;When was the last successful restore test?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;More important than a backup is testing restoring your databases. If you can’t restore data then your backup is useless. I try to test restoring my backups at least weekly so I know that I can rely on my backups.&lt;/p&gt;
&lt;ol start="7"&gt;
&lt;li&gt;&lt;strong&gt;Is everyone okay losing data back to the last successful backup?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If disaster strikes you could loose all data between now and the time of your last backup. But all is not lost transactional backups can be scheduled throughout the day, in my case the most data we could loose is 15 minutes. This could be configured to be more or less frequent depending on your data. But remember the previous question and make sure you test a restore of your transactional backups, if you can’t restore from them you will be forced to restore from the last successful backup.&lt;/p&gt;
&lt;ol start="8"&gt;
&lt;li&gt;&lt;strong&gt;When was the last successful clean corruption test?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Corruption can be a killer if it is not found quickly. If you need to restore to the last backup before corruption occurred this could result in a significant amount of data loss. To check for corruption you need to run DBCC regularly.&lt;/p&gt;
&lt;ol start="9"&gt;
&lt;li&gt;&lt;strong&gt;Do we have a development or staging environment where I can test my changes first?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the answer to this is no, then your next job is to setup a development or staging area. Having a development environment makes development a lot easier and I don’t think I could manage to do all the changes I have done recently without one.&lt;/p&gt;
&lt;ol start="10"&gt;
&lt;li&gt;&lt;strong&gt;Is there any documentation for why the server was configured this way?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I really wish we had more documentation about configurations as it would make finding out why thing were setup the way they are. So unfortunately the answer to this question is No.&lt;/p&gt;
&lt;ol start="11"&gt;
&lt;li&gt;&lt;strong&gt;What changes am I not allowed to make?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Depending on what your app does, where it is hosted, how quick the changes are needed and many other factors will all restrict what changes you can make. Historical decisions on the database can also affect what changes can be made, if the database has been structured in a certain way, it may be very difficult to restructure it in a more efficient way.&lt;/p&gt;
&lt;ol start="12"&gt;
&lt;li&gt;&lt;strong&gt;Who can test that my changes fixed the problem?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is an interesting question, from experience the best people to speak to about problems with the database are the users. If they can show you how to reproduce a problem, you should be able to fix this problem, after that you can probably get them to verify that it has been fixed.&lt;/p&gt;
&lt;ol start="13"&gt;
&lt;li&gt;&lt;strong&gt;Who can test that the apps still work as designed, and that my changes didn’t have unintended side effects?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is an extension of the previous question. The main users of your app should be your first port of call to find out if the app works as expected. However exploring side affects and undesired features is something that I would test as part of the development process. It has taken a while but I have constructed a detailed check list that can be used for testing so I know that most bugs can be found before release.&lt;/p&gt;</description></item><item><title>New Horizons Pluto Spacecraft</title><link>https://blog-test.funkysi1701.com/posts/2015/new-horizons-pluto-spacecraft/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 14 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/new-horizons-pluto-spacecraft/</guid><category term="Pluto">Pluto</category><category term="Hardware">Hardware</category><category term="Spacecraft">Spacecraft</category><category term="Software">Software</category><category term="Technology">Technology</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/07/84270464_p_lorri_fullframe_color.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Colour photograph of Pluto taken by New Horizons" src="https://blog-test.funkysi1701.com/images/2015/07/84270464_p_lorri_fullframe_color.png" loading="lazy"
width="976" height="630"
/&gt;
&lt;/p&gt;
&lt;p&gt;To explore Strange New Worlds, well today the NASA spacecraft New Horizons has been doing just that. This is the most detailed photograph yet of the furthest planet we have ever explored, Pluto.&lt;/p&gt;
&lt;p&gt;New Horizons was launched on 19th January 2006. It has been travelling for 3463 days (9.5 years).&lt;/p&gt;
&lt;p&gt;In 2006 we were still using Windows XP and Office 2003. In 2006 I wasn’t even working in IT. As a software developer it is hard to imagine writing software that won’t be used for another 9.5 years.&lt;/p&gt;
&lt;p&gt;The spacecraft carries two computer systems: the Command and Data Handling system and the Guidance and Control processor. Each of the two systems is duplicated for redundancy, for a total of four computers. The processor used for its flight computers is the Mongoose-V, a 12 MHz radiation-hardened version of the MIPS R3000 CPU. Multiple clocks and timing routines are implemented in hardware and software to help prevent faults and downtime. To conserve heat and mass, spacecraft and instrument electronics are housed together in IEMs (integrated electronics modules). There are two redundant IEMs. Including other functions such as instrument and radio electronics, each IEM contains 9 boards. The processor distributes operating commands to each subsystem, collects and processes instrument data, and sequences information sent back to Earth. It also runs the advanced “autonomy” algorithms that allow the spacecraft to check the status of each system and, if necessary, correct any problems, switch to backup systems or contact operators on Earth for help.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Diagram of the New Horizons spacecraft structure" src="https://blog-test.funkysi1701.com/images/2015/07/Mission-Spacecraft-structure.jpg" loading="lazy"
width="720" height="523"
/&gt;
&lt;/p&gt;
&lt;p&gt;For data storage, New Horizons carries two low-power solid-state recorders (one backup) that can hold up to 8 gigabytes each. The main processor collects, compresses, reformats, sorts and stores science and housekeeping (telemetry) data on the recorder – similar to a flash memory card for a digital camera – for transmission to Earth through the telecommunications subsystem.&lt;/p&gt;
&lt;p&gt;Communication with the spacecraft is via X band. The craft had a communication rate of 38 kbit/s at Jupiter; at Pluto’s distance, a rate of approximately 1000 bit/s. To put this speed into context, the size of the image at the top of this page is 649kb and would take over 86 minutes to travel from Pluto to Earth, (I am sure the actual image was much larger and took even longer to reach us.) Besides the low bandwidth, Pluto’s distance also causes a latency of about 4.5 hours (one-way). The 70 m (230 ft) NASA Deep Space Network (DSN) dishes are used to relay commands once it is beyond Jupiter. It will take 16 months to send the full set of Pluto encounter science data back to Earth.&lt;/p&gt;
&lt;p&gt;Most software encounters a problem from time to time, but the software on board this spacecraft has to keep running for almost a decade. Due to the distances involved its not possible to upload any code tweaks. Any commands that are sent to the spacecraft will take 4.5 hours to even get there so there needs to be a huge amount of autonomy and redundancy to cope with such a massive journey.&lt;/p&gt;
&lt;p&gt;I can’t even imagine how you would begin to write the software to run such a craft. I don’t think I have written any code that is as old as is running on the New Horizons craft, and if I had I would guess the quality would be quite poor certainly not good enough to work non stop for a decade.&lt;/p&gt;
&lt;p&gt;There are some incredibly clever people out there who have been involved in this project. Congratulations team you have every right on being proud as the data starts to trickle back to earth.&lt;/p&gt;</description></item><item><title>How to upgrade to Windows 10</title><link>https://blog-test.funkysi1701.com/posts/2015/how-to-upgrade-to-windows-10/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 11 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/how-to-upgrade-to-windows-10/</guid><category term="ScottHansleman">ScottHansleman</category><category term="Free">Free</category><category term="SystemAdministration">SystemAdministration</category><category term="Windows10">Windows10</category><category term="Upgrade">Upgrade</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/10/windows_10_fullwidth.jpg"/><description>&lt;p&gt;Microsoft are releasing a new operating system on July 29th called Windows 10.&lt;/p&gt;
&lt;p&gt;If you have questions about Windows 10 watch this video by &lt;a href="https://www.hanselman.com/blog/windows-10-is-comingheres-what-to-tell-nontechnical-parent" target="_blank" rel="noopener noreferrer"&gt;Scott Hansleman&lt;/a&gt;
. He explains how to upgrade from Windows 7 and 8 to Windows 10 and what to expect after you upgrade.&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/nuCpdlMFvUY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;My advice to everyone is that you backup your devices before you upgrade, this is good practice before you install any software or updates.&lt;/p&gt;
&lt;p&gt;Microsoft are offering Windows 10 for free for a whole year, so don’t panic. Take your time, backup all your important files and when you are ready install Windows 10. Nothing is going to stop working after July 29th if you don’t have the latest operating system on your machine.&lt;/p&gt;
&lt;p&gt;I hope this helps answer some of your questions about what to do at the end of the month. If not feel free to write a comment or contact me with your questions.&lt;/p&gt;</description></item><item><title>Why do we call them bugs?</title><link>https://blog-test.funkysi1701.com/posts/2015/why-do-we-call-them-bugs/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 07 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/why-do-we-call-them-bugs/</guid><category term="Debugging">Debugging</category><category term="Bugs">Bugs</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/07/11666093_10153470803062792_4914668365512645054_n.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Insect resting outdoors" src="https://blog-test.funkysi1701.com/images/2015/07/11666093_10153470803062792_4914668365512645054_n.jpg" loading="lazy"
width="960" height="540"
/&gt;
&lt;/p&gt;
&lt;p&gt;On my way home from the office I spotted this little chap. In my expert opinion it is a &amp;ldquo;bug&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;This particular &amp;ldquo;bug&amp;rdquo; is harmlessly sitting outside, but have you ever wondered why computer problems are often named after this little chap (and his friends)?&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Moth taped in Grace Hopper&amp;rsquo;s 1947 computer logbook" src="https://blog-test.funkysi1701.com/images/2015/07/H96566k.jpg" loading="lazy"
width="740" height="583"
/&gt;
&lt;/p&gt;
&lt;p&gt;The first recorded bug report was in 1947 when Grace Hopper found a moth between the relays of a Harvard Mark II, this moth was then tapped in the log book as evidence.&lt;/p&gt;
&lt;p&gt;Since then the process of removing bugs has been called &amp;ldquo;debugging&amp;rdquo;. However bugs had existed in electrical devices before this.&lt;/p&gt;
&lt;p&gt;In the early days of telegraphy, there were two types of keyers. The older “manual” keyers which required the operator to code the dots and dashes. And the newer, semi-automatic keyers that would send a string of dots automatically. These semi-automatic keyers were called &amp;ldquo;bugs&amp;rdquo;. One of the most common brands of these keyers, the Vibroplex, used a graphic of a beetle.&lt;/p&gt;
&lt;p&gt;Luckily the bugs I deal with don’t have legs or wings and are just errors in computer code. When I debug code I need to look at the inner workings of the code, looking for problems, most often it is a typo or piece of logic that doesn’t match up. But the relationship between computer bugs and living bugs does continue, the bug tracking software bugzilla uses a cartoon bug as its logo.&lt;/p&gt;</description></item><item><title>Agile Software Development</title><link>https://blog-test.funkysi1701.com/posts/2015/agile-software-development/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 04 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/agile-software-development/</guid><category term="Agile">Agile</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/07/Agile-Marketing-Series-What-is-Agile-Marketing.png"/><description>&lt;p&gt;I have heard the term &lt;strong&gt;Agile Software Development&lt;/strong&gt; quite a bit, but lets see if we can define it and see if I do any of the processes involved with it.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Agile Software Development" src="https://blog-test.funkysi1701.com/images/2015/07/Agile-Marketing-Series-What-is-Agile-Marketing.png" loading="lazy"
width="579" height="290"
/&gt;
&lt;/p&gt;
&lt;p&gt;The dictionary defines ‘Agile’ as mentally quick, or nimble, or quick in movement.&lt;/p&gt;
&lt;p&gt;In 2001 The Manifesto for Agile Software Development first introduced the term agile. The manifesto is based on 12 principles.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customer satisfaction by early and continuous delivery of useful software&lt;/li&gt;
&lt;li&gt;Welcome changing requirements, even late in development&lt;/li&gt;
&lt;li&gt;Working software is delivered frequently (weeks rather than months)&lt;/li&gt;
&lt;li&gt;Close, daily cooperation between business people and developers&lt;/li&gt;
&lt;li&gt;Projects are built around motivated individuals, who should be trusted&lt;/li&gt;
&lt;li&gt;Face-to-face conversation is the best form of communication (co-location)&lt;/li&gt;
&lt;li&gt;Working software is the principal measure of progress&lt;/li&gt;
&lt;li&gt;Sustainable development, able to maintain a constant pace&lt;/li&gt;
&lt;li&gt;Continuous attention to technical excellence and good design&lt;/li&gt;
&lt;li&gt;Simplicity—the art of maximizing the amount of work not done—is essential&lt;/li&gt;
&lt;li&gt;Self-organizing teams&lt;/li&gt;
&lt;li&gt;Regular adaptation to changing circumstance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lets go through this list one by one and examine what I understand of it and how I might have used it in the past.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customer satisfaction by early and continuous delivery of useful software&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My boss bombards me with hundreds of changes that she wants straight away, I keep her reasonably happy by giving her regular small improvements. Yesterday I released some changes, and two weeks before that I released another chunk, on Monday I will find out that I haven’t included feature Y, so in another couple of weeks feature Y will be delivered. This is my understanding of delivering continuous improvements to my software.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Welcome changing requirements, even late in development&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lets ignore the word welcome, as changing requirements are really annoying. I designed a system to track how far through a 5 step process you were, after I deployed that change it was discovered that the process was actually 18 steps. Annoying as this was, my design allowed the easy addition of these extra stages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Working software is delivered frequently&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes, I do this, see my comments above. If you make a single change and then deploy it, bug fixes are easy as most of it is still in your head. If you spend 6 months making 1000 changes, it will take you extra time to remind yourself what you did and why.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Close, daily cooperation between business people and developers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I don’t do this daily but I regularly demo my changes to other departments and directors so I can gather feedback and further revise my changes. Before I start work I always try to understand what is needed and how they want it to work and try and figure out what they need not what they want (different things)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Projects are built around motivated individuals, who should be trusted&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not sure I understand this one. There are people that use my projects that I always go to, to find out how it is being used. There are also people that are not interested in change, it is always far more difficult to convince them of the value of what I am working on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Face-to-face conversation is the best form of communication&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When I was an IT support guy, I used to like going up to someone’s desk and seeing them experience the problem, it could usually be fixed in a couple of clicks. However when you had a call from a remote office and had to talk through trying different things it could take hours to fix. The same can be said of deploying a new feature, if you talk to your users and explain what has been added they are far more likely to use it, than if you send them an email listing what you have done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Working software is the principal measure of progress&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If a Manager can click two buttons to find out how busy their department is, when before they only had out of date spreadsheets, this is a clear measure of progress. Any time spent on code that never gets deployed doesn’t improve anything, its only when that code starts being used has progress been made.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sustainable development, able to maintain a constant pace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am pretty sure I don’t do this. I work harder at some times than others. Sometimes there are other projects or other demands on my time and so development on a particular project will decrease and there are times when I eat, sleep, dream about a project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Continuous attention to technical excellence and good design&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I do strive towards good design and with each deployment aim to improve the quality of code in production. However my limited knowledge means that I don’t always produce the best code but it is improving. If I look at some work I have done in the past, I would definitely do some of that differently if working on it now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Simplicity—the art of maximizing the amount of work not done—is essential&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When I first read this one, it made no sense to me. However I believe it can be restated as minimising the amount of work done. Recently I was writing SQL code and I had about 4 or 5 different queries to produce the report that was needed. Every time the requirements changed it was a long slog through each of these queries to update them. In the end I had to rewrite this whole process using one query, it took some time but was simpler and is now easier and quicker to maintain. The simpler the code is the easier and quicker it is to maintain, and you have less work to do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Self-organizing teams&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not sure this applies to me as I work in a team of one. I do try and keep myself organised but not sure if that qualifies as self-organizing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Regular adaptation to changing circumstance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Very similar to the second point about changing requirements but I think also includes changes required due to problems you encounter along the way. A simple example of this is when you encounter a problem, there are lots of different ways to solve it. If you can’t solve something in the database layer, then it might be solved with a script or in the user interface.&lt;/p&gt;
&lt;p&gt;So in summary I am not only a developer but very close to being an Agile developer as well, assuming these 12 points are what is needed to be ‘Agile’&lt;/p&gt;</description></item><item><title>Developer Personality Test</title><link>https://blog-test.funkysi1701.com/posts/2015/developer-personality-test/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 02 Jul 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/developer-personality-test/</guid><category term="Developer">Developer</category><category term="Personaility">Personaility</category><category term="Myers-Briggs">Myers-Briggs</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/07/19etmksoopu2ojpg.jpg"/><description>&lt;p&gt;I was sent a &lt;a href="https://www.surveygizmo.com/s3/1883619/Developer-Personality-Test" target="_blank" rel="noopener noreferrer"&gt;link&lt;/a&gt;
to a developer personality test earlier. The test aims to give you a look at your developer personality similar to the famous Myers-Briggs personality test. A shorter version of this test can be found &lt;a href="https://www.surveygizmo.com/s3/1900187/Short-Developer-Personality-Test" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Myers-Briggs tells you if you are &lt;strong&gt;Introvert (I)&lt;/strong&gt; or &lt;strong&gt;Extrovert (E)&lt;/strong&gt;, &lt;strong&gt;Feeling (F)&lt;/strong&gt; or &lt;strong&gt;Thinking (T)&lt;/strong&gt;, &lt;strong&gt;Perception (P)&lt;/strong&gt; or &lt;strong&gt;Judging (J)&lt;/strong&gt; and &lt;strong&gt;Sensing (S)&lt;/strong&gt; or &lt;strong&gt;Intuition (N)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This test however tells you if you are:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Independent vs Collaborative&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Abstract vs Low-Level&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Frontier vs Conservative&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generalist vs Specialist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Idealist vs Pragmatist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Developer personality test trait spectrum diagram" src="https://blog-test.funkysi1701.com/images/2015/07/19etmksoopu2ojpg.jpg" loading="lazy"
width="1196" height="1280"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Independent:&lt;/strong&gt;
You prefer to spend most of your time working in an isolated environment. You rarely want to collaborate because you have a better chance of solving problems on your own. If you do have to collaborate on the direction of a project, you dislike it when you have to defend your position or when others try to muddy your plans for the project. It’s better to have one strong vision for a project from the lead programmer on that project. Having a large team or allowing others to have significant control over the project risks communication errors, a muddied code base, and inefficiencies. If one developer has a firm grasp on the entire codebase, they’ll be much better at fixing and improving it quickly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Collaborative:&lt;/strong&gt;
Good code doesn’t happen in a vacuum. You need a team to keep you energized and on your toes so that you’re constantly improving the project code using the entire team’s varied experience and strengths. You like to talk frequently with colleagues and discuss ideas so that you can learn from others and spark ideas. It doesn’t matter what their experience level is, you can always learn something by including everyone. A solo coder can’t possibly code a large software project with the speed and quality that a team can.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Abstract:&lt;/strong&gt;
You prefer to write in languages and frameworks that simplify development as much as possible and use as few characters and lines of code as possible. The trajectory of software development has always been toward making life easier and error-free. Programming has always been about adding more abstraction layers to simplify tasks, so why not trust the technology on your layer and don’t worry about handling the lower layers?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Low-Level:&lt;/strong&gt;
The more abstraction tools and high-level languages we build, the further we get from understanding and controlling the deeper components in our programs. This means lower performance and endless bug searches. Developers today need to have a stronger understanding of compilers, memory management, pointer arithmetic, and other low-level topics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Frontiers:&lt;/strong&gt;
You like to work at the cutting edge. Using too many old languages and technologies bores you, and it severely hinders your software’s potential to keep outdated technologies in it for too long. Developers need keep their ears to the ground for new technologies and new versions of tools that they already use. Even if the community and maturity of the project isn’t at a level that most enterprises would consider “safe,” you’re willing to be an early adopter if you believe the community and the technology has momentum. Development technology is changing faster every day, and we need to constantly be adopting new tools and methods to keep up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conservative:&lt;/strong&gt;
It seems like every 10 years we forget all the problems we solved in the previous decade and start to build ‘new’ tools that solve the same problems, even though there is a perfectly good solution that has existed for years. Enterprises have it right when they make conservative decisions about their technology stack. Why would you hang your business on a technology with only a few years of maturity in just a handful of production use cases? Technologies like PHP, Java, and SQL have been mainstays of the development industry for years, and it takes a lot of time for new technologies to make it into that maturity tier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generalist:&lt;/strong&gt;
You like to be known as a “Jack of all Trades” and a reference for others on your team. You jump at every chance to enhance your skills in a wide variety technology topics, not just the ones that apply to your day to day work. You don’t always know when it might be useful to have these extra skills, but when the time comes, you are ready. If more developers took the time to learn other skills outside of the ones relevant to their project, they’d work more seamlessly with the rest of their organization because they’d have more empathy and understanding of the challenges that their colleagues face.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Specialist:&lt;/strong&gt;
If you’re a Jack of all Trades, you’re a master of none. Mastery in one or two areas is what makes you valuable. What’s the point of learning skills for other jobs you don’t have and can’t control? When you plan for a project or do technical research, it’s always focused on something you’re working on. You don’t get side-tracked. If you learn a new skill, it’s because the project requires that you do it. Most or all of your hobby projects are also building your mastery of the skills you use at your job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Idealist:&lt;/strong&gt;
You believe in the power of well-defined processes. It’s crucial to an organization’s success that they create and follow appropriate and effective processes for building software. Trying to improvise or play it by ear invites the possibility of workflow errors that can decrease the quality of the software or even cause major product failures. Planning is also extremely important to you. You like to research all of the things you will need to know before starting a project. It’s important to find out the best architecture for your software beforehand, and then strictly implement that architecture with objective best practices. The more planning and scaffolding you do in the beginning, the less overall work you will have to do to complete the software.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pragmatist:&lt;/strong&gt;
Speed is your best weapon in a competitive industry, and to quickly prototype and build new products, you need to have a flexible, pragmatic process. You don’t have a few months to plan your projects, you need to just start coding and a good path for the project will reveal itself. Great products are made through frequent feedback and releases, so why shouldn’t your plan be just as adaptable? Your plan should be adapted to changes in the software, and your expertise should be adapted to the project. You shouldn’t spend your precious time studying a problem that you’re not certain to run into while coding your projects. Trying to build test coverage for every possible scenario and having long meetings throughout the process are a waste of time and distract you from doing more productive work.&lt;/p&gt;
&lt;p&gt;I am not going to admit where I came in this test as being a newbie developer my answers are very subjective and I don’t believe I have enough experience to really say where I lie on many of these issues.&lt;/p&gt;
&lt;p&gt;I only have experience of working on my own and in very small teams, while I think working in a bigger team would have benefits I have no experience of this.&lt;/p&gt;</description></item><item><title>Sudoku Challenge</title><link>https://blog-test.funkysi1701.com/posts/2015/sudoku-challenge/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 26 Jun 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/sudoku-challenge/</guid><category term="Dojo">Dojo</category><category term="C-Sharp">C-Sharp</category><category term="LeedsSharp">LeedsSharp</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/06/2000px-Sudoku-by-L2G-20050714.svg_.png"/><description>&lt;p&gt;Last night I went to a Code Dojo at Leeds Sharp (the coding user group I have started going to). A Code Dojo is a programming challenge that people work on usually in pairs.&lt;/p&gt;
&lt;p&gt;The challenge that we worked on was to code a solution to the puzzle game Sudoku. The code we worked with can be found on github.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Partially completed Sudoku puzzle grid" src="https://blog-test.funkysi1701.com/images/2015/06/2000px-Sudoku-by-L2G-20050714.svg_.png" loading="lazy"
width="2000" height="2000"
/&gt;
&lt;/p&gt;
&lt;p&gt;I don’t know much about Sudoku but the game goes like this. You start with a 9×9 grid, and the idea is to fill in all the missing numbers.&lt;/p&gt;
&lt;p&gt;Each Row can only use each digit 1 to 9 once, each column can only use each digit 1 to 9 once and each subgrid (3×3) can only use each digit once.&lt;/p&gt;
&lt;p&gt;I worked with Richard one of the Leeds Sharp organisers, we started by trying to loop through each empty cell and insert values in a brute force attack, but this approach didn’t get us very far (literally as the application crashed!)&lt;/p&gt;
&lt;p&gt;The approach that we needed to use was to loop through calculating possible values.&lt;/p&gt;
&lt;p&gt;It was only when I sat down at this dojo did I realise how much I still have to learn, but while talking with Richard about different approaches and different coding structures I started to learn.&lt;/p&gt;</description></item><item><title>Fathers Day</title><link>https://blog-test.funkysi1701.com/posts/2015/fathers-day/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 21 Jun 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/fathers-day/</guid><category term="Father">Father</category><category term="BASIC">BASIC</category><category term="1980s">1980s</category><category term="Lynx">Lynx</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/06/PRODPIC-2926.jpg"/><description>&lt;p&gt;In the UK today is Fathers Day. Happy Fathers Day Dad!&lt;/p&gt;
&lt;p&gt;I thought I might talk about how he encouraged my interest in technology, especially as in about 8 weeks I will become a parent and will have someone to encourage and inspire.&lt;/p&gt;
&lt;p&gt;I am going to sound really old but when I was born there was no internet, no mobile phones and computers more often appeared in sci-fi than in your home.&lt;/p&gt;
&lt;p&gt;The first computer I remember us owning was a Lynx. A quick google reveals there were a number of different models, I have no idea what we had but here is what I found.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Camputers Lynx home computer" src="https://blog-test.funkysi1701.com/images/2015/06/PRODPIC-2926.jpg" loading="lazy"
width="500" height="308"
/&gt;
&lt;/p&gt;
&lt;p&gt;In March 1983 the Lynx 48K was released, in September this was upgraded to 96K. In December 1983 a new Lynx was released with 128K. To put these numbers in perspective on my desktop is an image file that is 123K! The CPU in this computer was rated at between 4 and 6Mhz. (Modern PCs have CPUs around the 1.5Ghz or 1500Mhz)&lt;/p&gt;
&lt;p&gt;The Lynx we had, didn’t have a disk drive or a mouse. Programs were loaded from audio tapes (Audio tape was a form of data storage that came before CDs where data was stored on magnetic tape, most often used for music) The tapes we had would often get stuck and data wouldn’t load. The answer to this was to fast-forward/rewind the tape or hit the tape on your leg. For some reason this is a memory I still have of my dad hitting a tape on his leg to get a game or something else to load on the lynx. We also had a joystick for playing some of the games. I believe we also had an early thermal printer.&lt;/p&gt;
&lt;p&gt;My memory of the Lynx is in black and white. The reason for this is that the Lynx was connected to an old black and white TV, it was a special treat when we connected the main colour TV to the Lynx.&lt;/p&gt;
&lt;p&gt;We had a wide range of games for the Lynx, I can remember Jet Set Willy, and Diggerman. But there were also programs which my father had created. The Lynx had a form of BASIC where you can write you own programs and my father spent many hours writing programs for me and my sister. (We actually never realized this at the time)&lt;/p&gt;
&lt;p&gt;With that as my introduction to computers is it any wonder that I do what I do now? Now what should I do for my child to encourage them in a similar way?&lt;/p&gt;
&lt;p&gt;As a family we never owned a games console. Not sure if this was a financial or moral choice but it is something I will have to think about. I want my child to be knowledgeable about computers and able to compete in the competitive job market, but I also want them to know about science and nature and to enjoy their childhood. Lots of technology choices to make over the next few years.&lt;/p&gt;</description></item><item><title>50th Blog Post</title><link>https://blog-test.funkysi1701.com/posts/2015/50th-blog-post/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 17 Jun 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/50th-blog-post/</guid><category term="Blog">Blog</category><category term="50">50</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/06/top-50-2012.jpg"/><description>&lt;p&gt;WOW! I have reached the milestone of 50 blog posts.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Top 50" src="https://blog-test.funkysi1701.com/images/2015/06/top-50-2012.jpg" loading="lazy"
width="1500" height="1125"
/&gt;
&lt;/p&gt;
&lt;p&gt;I have tried to blog at least every week and I have learnt a lot. I have talked about my work, technology, things I have learnt, things I want to do and many more things. It is too soon to tell if my blog is going to be a success, but I think I am starting to find my ‘blog’ voice and I intend to keep on blogging.&lt;/p&gt;
&lt;p&gt;To celebrate here are some of my highlights.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/user-groups-and-f/" target="_blank" rel="noopener noreferrer"&gt;User Groups and F#&lt;/a&gt;
By far my most popular blog post. I talk about my first visit to the Leeds Sharp group and an introduction to the F# language.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/monitoring-screens/" target="_blank" rel="noopener noreferrer"&gt;Monitoring Screens&lt;/a&gt;
I talk about creating a big screen of vital monitoring information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/ten-forward-episode-135-anti-firbob-is-back-or-simons-desert-island-trek/" target="_blank" rel="noopener noreferrer"&gt;Ten Forward Episode #135&lt;/a&gt;
– Simon’s Desert Island Trek My appearance on the Ten Forward Podcast&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/building-something-with-a-raspberry-pi/" target="_blank" rel="noopener noreferrer"&gt;Building something with a Raspberry Pi&lt;/a&gt;
I blog about getting a Raspberry Pi to play around with&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/javascript-progress/" target="_blank" rel="noopener noreferrer"&gt;Javascript progress&lt;/a&gt;
About learning javascript&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/the-raspberry-pi-adventure-starts/" target="_blank" rel="noopener noreferrer"&gt;The Raspberry Pi Adventure Starts&lt;/a&gt;
I get a Raspberry Pi and start building something with it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/weakest-database-design/" target="_blank" rel="noopener noreferrer"&gt;Weakest Database Design&lt;/a&gt;
I talk about database design&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/trying-windows-10/" target="_blank" rel="noopener noreferrer"&gt;Trying Windows 10&lt;/a&gt;
I talk about my experience with the latest windows operating system&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.funkysi1701.com/posts/2015/laziness/" target="_blank" rel="noopener noreferrer"&gt;Laziness&lt;/a&gt;
I talk about the extreme ways IT Professionals go to be more lazy&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Requirement Gathering</title><link>https://blog-test.funkysi1701.com/posts/2015/requirement-gathering/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 16 Jun 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/requirement-gathering/</guid><category term="Database">Database</category><category term="Requirements">Requirements</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/06/Requirements-Gathering-User-Experience-UX-Project-Cartoon.jpg"/><description>&lt;p&gt;&lt;strong&gt;Why is it so hard to find out exactly what is needed when designing changes to a system?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Cartoon illustrating requirements gathering problems in software projects" src="https://blog-test.funkysi1701.com/images/2015/06/Requirements-Gathering-User-Experience-UX-Project-Cartoon.jpg" loading="lazy"
width="728" height="543"
/&gt;
&lt;/p&gt;
&lt;p&gt;When adding functionality to databases I always like to dive in and start adding extra columns and new tables. But at some point you need to find out what is needed.&lt;/p&gt;
&lt;p&gt;The process of gathering requirements that I have followed goes something like this.&lt;/p&gt;
&lt;p&gt;My boss tells me that we need a system to solve x problem. This is the broad overview of what is needed.&lt;/p&gt;
&lt;p&gt;Next I need to find out specifically how the system is being used and what things need adding. Discussing the specifics with my boss often results in a high level of confusion. I always try to speak with the users that will be using this system on a daily basis. If I create something that isn’t liked people will avoid using it and it won’t solve the original problem so I always think it is very important to speak to the day to day user.&lt;/p&gt;
&lt;p&gt;After I have an idea of what is needed, I build something. Once I have something that sort of works, I will try and demonstrate this to the user to gather feedback. This feedback is invaluable as it will often reveal if I am going in the right direction and reveal missing requirements that need to be incorporated in the finished solution.&lt;/p&gt;
&lt;p&gt;I will often repeat the last stage a few times especially if there is a big change needed, once I am happy I will demonstrate to my boss before deploying the solution.&lt;/p&gt;
&lt;p&gt;After deployment there is often a period of fixing issues and gathering feedback before I can consider the project finished.&lt;/p&gt;
&lt;p&gt;This whole process is very time consuming as there is a period of changes being tweaked back and forth following feedback. A better way is to gather a detailed specification of what is needed and work towards delivering that.&lt;/p&gt;</description></item><item><title>Runaway SQL Log growth</title><link>https://blog-test.funkysi1701.com/posts/2015/runaway-sql-log-growth/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 12 Jun 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/runaway-sql-log-growth/</guid><category term="ITAdmin">ITAdmin</category><category term="Backups">Backups</category><category term="SQL">SQL</category><description>&lt;p&gt;Today is my day off, but I wake up and have a quick look at &lt;a href="https://www.funkysi1701.com/posts/2014/i-love-nagios/" target="_blank" rel="noopener noreferrer"&gt;nagios&lt;/a&gt;
to see if there is anything I need to worry about. Yes there is, SQL Server has run out of disk space on its data disk.&lt;/p&gt;
&lt;p&gt;I race downstairs and VPN onto the server to find out what has happened. One of my monitoring databases has had runaway log growth and is over 80Gb is size.&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BACKUP LOG [DBName] &lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt; TRUNCATE_ONLY
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DBCC SHRINKFILE(&lt;span style="color:#e6db74"&gt;&amp;#39;DBName_Log&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Free disk space is back to normal, all users will be unaware of the problem and everything is fine again. I create a daily job that runs the above code, that way it should stay a manageable size.&lt;/p&gt;
&lt;p&gt;Next I need to find out why it happened and to prevent it happening again in the future (Next time I have a day off I want to lie in!)&lt;/p&gt;
&lt;p&gt;I check the SQL logs and notice&lt;/p&gt;
&lt;p&gt;BACKUP LOG WITH TRUNCATE_ONLY or WITH NO_LOG is deprecated. The simple recovery model should be used to automatically truncate the transaction log.&lt;/p&gt;
&lt;p&gt;Then I remember what I have done to cause this issue. I have a separate disk for my backup files and earlier in the week I noticed this disk was filling up, a large amount of space was taken up by transactional backup files. I thought I don’t need to backup the transactions for this non critical database, I will just do a full backup at the start of everyday.&lt;/p&gt;
&lt;p&gt;However what I forgot is that a transactional backup keeps the log file under control, once this backup was stopped the log file grew uncontrollably. The answer, change the database from FULL mode to SIMPLE.
&lt;img class="img-fluid" alt="image002" src="https://blog-test.funkysi1701.com/images/2015/image002-300x270.png" loading="lazy"
width="300" height="270"
/&gt;
&lt;/p&gt;
&lt;p&gt;This is my understanding of how backups work in FULL mode. A full backup is done at the start of the day which resets the log file, then changes in the database are stored in the log file, this is backed up into a transactional backup and the log file gets reset. If you have regular transactional backups throughout the day the log file doesn’t grow too much, however with no transactional backups your log file contains an entire days worth of changes and so for a monitoring database this could be quite large.&lt;/p&gt;
&lt;p&gt;In SIMPLE mode you can’t do transactional backups and the log doesn’t grow uncontrollably. This shouldn’t be used for production databases as if there is a problem you could loose data.&lt;/p&gt;</description></item><item><title>Don’t Live with Broken Windows</title><link>https://blog-test.funkysi1701.com/posts/2015/pragmatic-programmer-broken-windows/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 08 Jun 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/pragmatic-programmer-broken-windows/</guid><category term="Windows">Windows</category><category term="Books">Books</category><category term="Tips">Tips</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/06/tpp.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Building with a broken window illustrating broken windows theory" src="https://blog-test.funkysi1701.com/images/2015/06/1-ucIHdOcnByPsF5eX0j_mhg.jpeg" loading="lazy"
width="2000" height="1360"
/&gt;
&lt;/p&gt;
&lt;p&gt;Last night I started reading &lt;a href="https://www.amazon.com/Pragmatic-Programmer-Journeyman-Master-ebook/dp/B003GCTQAE/ref=mt_kindle?_encoding=UTF8&amp;amp;me=" target="_blank" rel="noopener noreferrer"&gt;The Pragmatic Programmer by Andrew Hunt and David Thomas&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;One practical tip that immediately jumped out at me as useful in my quest to be a better programmer: &lt;strong&gt;Don’t live with broken windows&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Cover of The Pragmatic Programmer book" src="https://blog-test.funkysi1701.com/images/2015/06/tpp.jpg" loading="lazy"
width="2200" height="2800"
/&gt;
&lt;/p&gt;
&lt;p&gt;The theory goes like this: an abandoned building with a single broken window attracts additional broken windows, graffiti, litter, and a sense that no one cares about this building. However this can be avoided if the authorities repair the window straight away.&lt;/p&gt;
&lt;p&gt;You can apply this theory to other walks of life, too, like keeping your kitchen clean. After you’ve spent hours cleaning your kitchen to make it spotless, you make an effort to keep it clean. But if your kitchen is piled high with dirty pans, leaving out an extra mug or dirty bowl isn’t going to feel like it makes any difference.&lt;/p&gt;
&lt;p&gt;The software engineering implications of this theory are that if you take care to keep your code tidy, it will stay that way. If you know something is broken but never make time to fix it, other bugs and issues will creep into it, until it’s a mess that no one dares touch.&lt;/p&gt;
&lt;p&gt;We have a website that is starting to get a bit buggy. It’s not broken, but it’s been a while since anyone has given it any love. Bits of its functionality are starting to get flaky.&lt;/p&gt;
&lt;p&gt;Being the only programmer in my place of work, I seldom have time to think about this website — let alone sit down and maintain it.&lt;/p&gt;
&lt;p&gt;But the number of related support calls have been gradually increasing — more windows are breaking — and I’m spending more and more time patching its bugs to keep people happy.&lt;/p&gt;
&lt;p&gt;Know that I’m aware of the broken windows principle, I know exactly what to do: sit down with this website for a couple of days and find out what exactly is causing these issues.&lt;/p&gt;
&lt;p&gt;Then I’ll rebuild the flaky bits, replace the proverbial cracked glass, and wash down a few walls while I’m at it.&lt;/p&gt;</description></item><item><title>I’m a developer now</title><link>https://blog-test.funkysi1701.com/posts/2015/im-a-developer-now/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 03 Jun 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/im-a-developer-now/</guid><category term="Self-Belief">Self-Belief</category><description>&lt;p&gt;For a while now I have been at the door of describing myself as a developer, but I think I have finally gone through that door.&lt;/p&gt;
&lt;p&gt;It is all a state of mind, its not about having x amount of knowledge, its just about saying “Yeah, I’m a developer now.”&lt;/p&gt;
&lt;p&gt;One thing that pushed me through that door, was an application form for something in which I ticked the software developer box instead of the IT Manager box.&lt;/p&gt;
&lt;p&gt;The other thing is some of the tasks I worked on recently. One of our databases has a Web Service running that supplies a website with some figures, and we found out recently that this needed changing due to a change on this website. Our contractor quoted us to do this work, I think it was 8 hours. My boss said why don’t you have a go at doing it instead and save us money.&lt;/p&gt;
&lt;p&gt;So I had a go, thinking this will take me a couple of days at least, as I will have to figure out how the code works and end up not understanding it. But no I had the changes done in less time than the contractor had quoted us. Go Me! I will say that these changes have yet to be fully tested, so I still might end up spending more time on this.&lt;/p&gt;</description></item><item><title>User Groups and F#</title><link>https://blog-test.funkysi1701.com/posts/2015/user-groups-and-f/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 30 May 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/user-groups-and-f/</guid><category term="F-Sharp">F-Sharp</category><category term="C-Sharp">C-Sharp</category><category term="LeedsSharp">LeedsSharp</category><category term="UserGroups">UserGroups</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/05/CGHJLlbWEAAbl14.jpg"/><description>&lt;p&gt;For a while I have been threatening to try a user group. Well this week I went to my first meeting.&lt;/p&gt;
&lt;p&gt;The user group I went to is called &lt;a href="https://www.meetup.com/leeds-sharp/" target="_blank" rel="noopener noreferrer"&gt;Leeds Sharp&lt;/a&gt;
who are celebrating their third birthday, happy birthday guys and thanks for the cake.&lt;/p&gt;
&lt;p&gt;The talk was all about F#. I know nothing about &lt;a href="https://fsharp.org/" target="_blank" rel="noopener noreferrer"&gt;F#&lt;/a&gt;
other than it is in visual studio. The speaker was &lt;a href="https://twitter.com/ptrelford" target="_blank" rel="noopener noreferrer"&gt;Phil Trelford&lt;/a&gt;
an expert in F# and former game developer who regularly speaks at conferences. Phil is an expert programmer, one of his stories was that while he had a broken arm, he wrote a copy of Excel in F#. Even with two hands I wouldn’t know where to start on something like that.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Leeds Sharp user group third birthday cake" src="https://blog-test.funkysi1701.com/images/2015/05/CGHJLlbWEAAbl14.jpg" loading="lazy"
width="1024" height="577"
/&gt;
&lt;/p&gt;
&lt;p&gt;There are plenty of advantages to using F# over C#, fewer lines of code was one. In Phil’s example he had some C# code which was about 30 lines but the F# was 2, part of the reason for this is F# has no {}.&lt;/p&gt;
&lt;p&gt;I found myself thinking this must be too good to be true there must be some disadvantages to using F#?&lt;/p&gt;
&lt;p&gt;I don’t know what they are yet, I am guessing you need to play around with the language a bit to really understand them.&lt;/p&gt;
&lt;p&gt;One claim that was made was that F# has less bugs. I am unsure how this can be true. Code is written by humans, humans will make mistakes which ever language they choose, there will be bugs.&lt;/p&gt;
&lt;p&gt;After the group I came away with a few things to try out. Try the F# tutorial that can be found in Visual Studio, try a Koan, this is a piece of code that contains failing tests, in the process of fixing the tests you learn the language, come back next time to Leeds Sharp and learn something else.&lt;/p&gt;</description></item><item><title>Visual Studio</title><link>https://blog-test.funkysi1701.com/posts/2015/visual-studio/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 26 May 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/visual-studio/</guid><category term="CodeLens">CodeLens</category><category term="Azure">Azure</category><category term="VisualStudio">VisualStudio</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/05/i1.png"/><description>&lt;p&gt;I recently replaced my installation of Visual Studio 2013 with Visual Studio 2015 RC.&lt;/p&gt;
&lt;p&gt;I like the new version, I am not a Visual Studio expert so it will probably take me a while to find all the good stuff but here are some initial thoughts.&lt;/p&gt;
&lt;p&gt;Being as my MSDN subscription is still valid I have installed the professional version to take advantage of its extra features like CodeLens.&lt;/p&gt;
&lt;p&gt;One of the first things I spotted was that the integration with Azure has been improved. In the last version it was difficult to sign in to Azure with the correct credentials, especially if you have more than one Azure account. Now you can add multiple Accounts and Subscriptions.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Visual Studio Azure account and subscription settings" src="https://blog-test.funkysi1701.com/images/2015/05/i1.png" loading="lazy"
width="582" height="252"
/&gt;
&lt;/p&gt;
&lt;p&gt;CodeLens is a feature that has been around in Visual Studio since 2013, but in 2015 it is available in Professional meaning more people have access to it.&lt;/p&gt;
&lt;p&gt;CodeLens gives coders useful information at a glance. Above each class/method is listed how many references there are. If you click on the number of references you can see where that class or method is referenced in the rest of your code. Useful to be able to see which methods or classes are not being used.&lt;/p&gt;
&lt;p&gt;Next CodeLens shows who (according to git) last changed the class or method and how many days ago that was. Clicking on it shows a cool graph of when changes have happened and who did them.&lt;/p&gt;
&lt;p&gt;Next you can see the number of changes that have been made, basically a source control history, but without having to load up your git client.&lt;/p&gt;
&lt;p&gt;For code that doesn’t contain classes or methods such as T_SQL you can see at the bottom of your code window the last two CodeLens information to help you track down what changes have happened recently.&lt;/p&gt;
&lt;p&gt;The last new feature that I have noticed is the Light Bulbs that keep showing up all over my code. I think the Light Bulbs might be called Quick Actions, but whatever they are called they are suggestions on how to improve your code. So far they have suggested to be to get rid of using references that are not used, simplify a fully qualified name, drop unneeded this keywords. I am sure more will popup as I do more coding.&lt;/p&gt;
&lt;p&gt;These improvements to Visual Studio I like, and I am sure there are many more that I haven’t noticed. I expect support for the vNext .net framework is also in there somewhere which hopefully I can play around with soon.&lt;/p&gt;</description></item><item><title>Overflow</title><link>https://blog-test.funkysi1701.com/posts/2015/overflow/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 22 May 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/overflow/</guid><category term="Database">Database</category><category term="Access">Access</category><category term="Integer">Integer</category><category term="SQL">SQL</category><category term="Overflow">Overflow</category><category term="Variables">Variables</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/05/error.jpg"/><description>&lt;p&gt;Today I encountered a new error.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Microsoft Access run-time error 6 overflow dialog" src="https://blog-test.funkysi1701.com/images/2015/05/error.jpg" loading="lazy"
width="385" height="220"
/&gt;
&lt;/p&gt;
&lt;p&gt;Run-time error ‘6’: Overflow doesn’t really tell me much. The error was occurring in the Access ADP front-end of our main database. It was only occurring for one particular Id number which was really confusing me.&lt;/p&gt;
&lt;p&gt;First thing I tried was to remove the most recent changes I had made, this made no difference. So time to look at the VBA code that was run just before the error.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Dim iPropertyId As Integer
iPropertyId = DLookup(“PropertyId”, “Survey”, “[ProjectNo]=” &amp;amp; Me.ProjectNo)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All looks good, even running the Dlookup query in SQL Management Studio threw no errors.&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; PropertyId &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; dbo.Survey &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; ProjectNo &lt;span style="color:#f92672"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next thing I tried was explicitly setting iPropertyId to the problematic Id, still the same error.&lt;/p&gt;
&lt;p&gt;This made me look at the error message again. Overflow suggest something being too big, but what could it be.&lt;/p&gt;
&lt;p&gt;Integer has a size limit of 32,767 and the value I was trying to pass into iProperty was 32779. This was what was causing the problem, my database had grown to such a size that Integer was too small, I needed to change it to a Long Integer. Long has a size of 2,147,483,647 so my database should keep working for a while more.&lt;/p&gt;
&lt;p&gt;The famous programming help website &lt;a href="https://stackoverflow.com/questions" target="_blank" rel="noopener noreferrer"&gt;Stack Overflow&lt;/a&gt;
is named after such an error. This error shows how difficult it is to decide what variable type to use, as you don’t know how quickly your database will grow.&lt;/p&gt;</description></item><item><title>Trying windows 10</title><link>https://blog-test.funkysi1701.com/posts/2015/trying-windows-10/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 17 May 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/trying-windows-10/</guid><category term="Windows8">Windows8</category><category term="Windows10">Windows10</category><category term="Format">Format</category><category term="Reinstall">Reinstall</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/05/win10.jpg"/><description>&lt;p&gt;My laptop has been getting a bit cluttered up with stuff so this weekend I gave it a reset.&lt;/p&gt;
&lt;p&gt;As I am using windows 8 this was much easier than doing a format reinstall which I have done many times with previous OSes. Open settings and select recovery and after about 4 hours everything was back to factory settings.&lt;/p&gt;
&lt;p&gt;I then installed a few updates and then installed the windows 10 preview. One of the requirements for windows 10 is Windows 8 Update (the one that came after 8.1), it took a few reboots and updates until I got that installed.&lt;/p&gt;
&lt;p&gt;I had purchased the pro pack which gives you the same features as windows 8 pro but I didn’t notice until after I installed 10 that this hadn’t been installed. I will need to roll back to windows 8 apply the update and then reinstall 10 again. I can’t really be bothered to do that, so I will live without HyperV for now. As it is I have done a lot of sitting around waiting for things to finish installing.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Windows 10 desktop on a laptop" src="https://blog-test.funkysi1701.com/images/2015/05/win10.jpg" loading="lazy"
width="888" height="537"
/&gt;
&lt;/p&gt;
&lt;p&gt;I much prefer Windows 10 to Windows 8, an earlier preview had an issue with drivers for my second screen but that appears to have been resolved now. The start menu is back and I prefer it, to being taken to that extra screen of options that windows 8 had.&lt;/p&gt;
&lt;p&gt;I prefer the email client that windows 8 had to the windows 10 version as my work emails don’t work with it. I assume this is due to how my exchange server has been configured and maybe a later preview will allow my email to work or failing that I will have to get emails at work fixed properly.&lt;/p&gt;
&lt;p&gt;All apps now open in windows which is much nicer. Cortana is very similar to Google Home on my phone where I can talk and ask it stuff. But I never use this sort of feature apart from testing it.&lt;/p&gt;
&lt;p&gt;The new web browser has some nice features like the option to scribble over a web page but nothing that special that I think I will change my default browser from Chrome. It will be interesting to see how it performs in browser stats.&lt;/p&gt;
&lt;p&gt;I am part way through installing Visual Studio 2015 RC, but I think that will have to be a separate post.&lt;/p&gt;</description></item><item><title>As A Service</title><link>https://blog-test.funkysi1701.com/posts/2015/as-a-service/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 16 May 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/as-a-service/</guid><category term="Azure">Azure</category><category term="AsAService">AsAService</category><category term="Cloud">Cloud</category><category term="PaaS">PaaS</category><category term="IaaS">IaaS</category><category term="SaaS">SaaS</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/05/19656ee.jpg"/><description>&lt;p&gt;In Cloud Computing there are a lot of terms that end aas or As a Service. Most of these I hadn’t heard of until I started writing this list.&lt;/p&gt;
&lt;p&gt;Any service that is delivered over the internet instead of hosted locally on your network or PC could in theory be described as an As a Service.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Pizza as a Service diagram comparing SaaS, PaaS and IaaS" src="https://blog-test.funkysi1701.com/images/2015/05/19656ee.jpg" loading="lazy"
width="841" height="675"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PaaS Platform As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is one of the big ones. Microsoft Azure provides a Platform as a Service which I am familiar with. Platform as a Service is where a provider provides a platform where you can build apps or websites.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SaaS Software As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another popular one. Software as a Service can be as simple as a website that runs a service that a customer wants to use, I work for a company that provides a SaaS product.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IaaS Infrastructure As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The last of the big ones. A good example of IaaS is a Virtual Machine which can either be hosted on a server somewhere (a private cloud) or on the internet via a company such as Azure (public cloud) The Pizza as a Service diagram illustrates the differences between Saas, PaaS and Iaas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NaaS Network As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is just a type of IaaS that specializes in providing networking. Anything that provides network connectivity could be included in this category.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CaaS Communications As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another subtype of IaaS this time specializing in communications, this could include Voice over IP or other similar technologies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MONaaS Monitoring As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you have a SaaS, PaaS or IaaS you will most likely want to monitor that it is working, I certainly do. This is something that is often included in your IaaS or PaaS package. Azure has various tools for monitoring and this could be included in this category.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BaaS Backup As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With the growth of cloud storage and the decrease in its cost, backing up to the cloud is a very attractive option. Any service that allows you to backup and restore from the internet can be included in this category. Your provider needs to manage your backups for it to be truly BaaS rather than just another place to store your files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DaaS Desktop As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is where your desktop is visualized and stored in the cloud. I know very little about this as I have never used it, but I would imagine you need a strong internet connection for it to work reliably.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DBaaS Database As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is a simple one if your database is stored in the cloud like Azure SQL Database then it fits into this category. If you run your own sql server install on a VM then it doesn’t fit in this category as you are still managing it yourself and is IaaS&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HaaS Hardware As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;HaaS this is another subcategory of IaaS which concentrates on hardware.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IDaaS Identity As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is where the management of who you are is managed in the cloud. Single Sign-On could be achieved if a website redirected determining if you are who you say you are to a particular IDaaS. Azure Active Directory is an example of this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SaaS Storage As a Service&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You get the idea now, storing files on a remote cloud product is an example of Storage as a Service. DropBox or OneDrive are good examples of this.&lt;/p&gt;
&lt;p&gt;Writing this blog post has given me a better understanding of all the aaS that are out there. I am sure I haven’t explained some of these very well and no doubt missed some off.&lt;/p&gt;</description></item><item><title>Top 25 Star Trek Characters</title><link>https://blog-test.funkysi1701.com/posts/2015/top-25-star-trek-characters/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 10 May 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/top-25-star-trek-characters/</guid><category term="StarTrek">StarTrek</category><category term="TNG">TNG</category><category term="DS9">DS9</category><category term="Voyager">Voyager</category><category term="TOS">TOS</category><category term="Enterprise">Enterprise</category><category term="Spock">Spock</category><category term="Picard">Picard</category><category term="Data">Data</category><category term="Kirk">Kirk</category><category term="Rankings">Rankings</category><category term="SciFi">SciFi</category><category term="Television">Television</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/02/Spock_2293.jpg"/><description>&lt;p&gt;I am going to take a break this week from talking about technology to talk about Star Trek.&lt;/p&gt;
&lt;p&gt;I have just listened to a &lt;a href="https://www.trekmate.org.uk/ten-forward-episode-146-lists-are-dumb-but-this-episode-is-not/" target="_blank" rel="noopener noreferrer"&gt;podcast&lt;/a&gt;
where they consider this &lt;a href="https://www.ign.com/articles/2009/05/08/top-25-star-trek-characters" target="_blank" rel="noopener noreferrer"&gt;list&lt;/a&gt;
of great Star Trek Characters. I am now going to try and come up with my own top 25 characters. Here we go.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Spock&lt;/strong&gt;. My number one star trek character is Spock. Leonard Nimoy who recently passed away brilliantly brought this character to life. We have the inner turmoil that many of us can associate with, we have a journey to become more human, we have the pursuit of logic. We have the great interplay between him and McCoy and Kirk.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Spock as played by Leonard Nimoy" src="https://blog-test.funkysi1701.com/images/2015/02/Spock_2293.jpg" loading="lazy"
width="720" height="544"
/&gt;
&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data&lt;/strong&gt;. My second number one star trek character, well OK, second star trek character is Data. His weekly exploration of what it meant to be human is star trek&amp;rsquo;s best exploration of the human condition. There are so many moments which make me like Data but I think when he builds his daughter, Lal is possibly my favourite.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Picard&lt;/strong&gt;. The Captain of the Enterprise. You want to know about leadership or diplomacy you watch Captain Picard in action. If only more of our world leaders could be like Captain Picard we would have all our Earthly problems sorted by tea-time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kirk&lt;/strong&gt;. The original captain of the Enterprise, not so much a Diplomat but could talk a computer to death in minutes. A fun guy to be around as long as you didn’t work in security or want a long lasting relationship with him, (sorry ladies this guy is married to the Enterprise)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Worf&lt;/strong&gt;. Our favourite Klingon. The most honourable man on this list and could handle himself in a battle. Also popular with the ladies if Troi and Dax have anything to say about it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sisko&lt;/strong&gt;. Our third captain, but Sisko had much more on his plate than the others. He had a Son to bring up, he lost his wife, he was in the middle of the biggest war the Federation has ever seen (at least on screen anyway), he became a religious icon and later a God.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;7 of 9&lt;/strong&gt;. The sexy borg from Voyager what’s not to like? Also brought some much needed conflict to the Voyager crew.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Garak&lt;/strong&gt;. The plain and simple tailor from DS9. But is he also a spy? There are so many layers to Garak you have no idea what to believe.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;McCoy&lt;/strong&gt;. Bones to his friends. A great Doctor but even greater friend to Jim Kirk and Spock (not that either of them would admit it.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;EMH&lt;/strong&gt;. Please state the nature of the medical emergency, started the show off as just another piece of technology and ended up one of the crews most important characters.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Janeway&lt;/strong&gt; Coffee Addict and defeated the Borg our first female captain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dukat&lt;/strong&gt;. DS9s regular bad guy. Started off Bad, then softened to be a good guy for a bit and then signed an alliance that started a war, in the middle of that he went crazy and ended up going to the Bajoran Hell&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Weyoun&lt;/strong&gt;. The leader of the dominion from the Gamma Quadrant. Was a clone so he could be killed off a few times and still come back. Had some great interplay with Dukat and later Damar.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Damar&lt;/strong&gt;. Started life as Dukat’s lieutenant and rose in rank to leader of his people, before switching sides to lead a rebellion.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scotty&lt;/strong&gt;. You cannae change the laws of Physics. An engineer that weekly performed miracles, more often because of large repair estimates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Barclay&lt;/strong&gt;. The only Starfleet officer that was unsure of himself and couldn&amp;rsquo;t talk to people (Oh a bit like me then)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Riker&lt;/strong&gt; The Captain Kirk of Picard’s crew, could inspire his crew and was popular with the ladies, but looks better with a beard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;O’Brien&lt;/strong&gt;. The everyman of DS9. He constantly had a station that was falling apart but he managed to keep it going, a bit like how I feel sometimes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quark/Rom/Nog&lt;/strong&gt;. These three Ferengi made the Ferengi good again. Nog started off as comic relief and ended up a Starfleet officer after turning his back on the acquisition of profit. Rom like his son turned his back on profit to fix things, and Quark was the businessman always had his eye for profit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Odo&lt;/strong&gt;. The shape shifting outsider that maintained order. Was truly an outsider with no idea where he had come from, but eventually he came to tolerate and even love us Solids.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Martok&lt;/strong&gt; Klingon with one eye that welcomed Worf into his house after his second dis-commendation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zefram Cochrane&lt;/strong&gt; Without this guy there would be no Star Trek. Invented the warp drive and enjoyed drinking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Uhura&lt;/strong&gt; Just a communications officer, but in reality was so much more. One of the first black women on television and inspired a generation to better themselves, was the other half of the first inter-racial kiss&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mirror Universe Hoshi&lt;/strong&gt;. Our universe Hoshi Sato was timid and scared of warp drive, the mirror universe version ended up empress of an entire Empire.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kai Winn&lt;/strong&gt; Power corrupts and Absolute power corrupts absolutely and Kai Winn is a prime example of this, so blinded by power she couldn&amp;rsquo;t hear what her precious Gods were telling her and ended up sleeping with her arch enemy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="more-star-trek-content"&gt;More Star Trek Content&lt;a class="anchor ms-1" href="#more-star-trek-content" aria-label="Permalink: More Star Trek Content"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you enjoyed this character ranking, check out these other Star Trek articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2016/top-50-star-trek-episodes/"&gt;Top 50 Star Trek Episodes&lt;/a&gt;
- My ranking of the greatest episodes across all series&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2021/a-comparison-of-all-good-things-and-star-trek-picard/"&gt;A Comparison of All Good Things and Star Trek Picard&lt;/a&gt;
- Examining how Picard&amp;rsquo;s future was predicted&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2016/star-trek-episode-review-the-best-of-both-worlds/"&gt;Star Trek Episode Review: The Best of Both Worlds&lt;/a&gt;
- A deep dive into the iconic Borg episode featuring Picard&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2023/picard-season-three"&gt;Picard Season 3&lt;/a&gt;
- My thoughts on the final season of Star Trek Picard&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/trekranks"&gt;TrekRanks #174&lt;/a&gt;
- My appearance on the TrekRanks podcast&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Want more Trek content?&lt;/strong&gt; Browse all my &lt;a href="https://blog-test.funkysi1701.com/tags/star-trek/"&gt;Star Trek articles&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;All 900+ Star Trek episodes are now available in &lt;a href="https://www.episodeatlas.com/" target="_blank" rel="noopener noreferrer"&gt;Episode Atlas&lt;/a&gt;
. Track episodes featuring your favorite characters.&lt;/p&gt;</description></item><item><title>Using your Rubber Duck</title><link>https://blog-test.funkysi1701.com/posts/2015/rubber-duck/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 04 May 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/rubber-duck/</guid><category term="Lonely">Lonely</category><category term="RubberDuck">RubberDuck</category><category term="Troubleshooting">Troubleshooting</category><description>&lt;p&gt;Rubber Duck is a process in development where you talk through an issue with an inanimate object such as a Rubber Duck. It gets its name from the book The Pragmatic Programmer where it was first used.&lt;/p&gt;
&lt;p&gt;I am the only programmer where I work and often I find myself with a question that I can’t find the answer to. I do however have a few friends who are far more knowledgeable than I am about this sort of thing. I often find myself explaining my problem via an email to them. During the process of writing this email I have to explain my problem and this sometime reveals the problem and I don’t even need to send the email. At other times by the time they have replied to me, my brain has moved on with the problem sufficiently that I am close to a solution if I am not already there.&lt;/p&gt;
&lt;p&gt;Other people use different items as their ‘Rubber Duck’, people on the code newbie forum have used items such as a cat, stuffed octopus, a Lego minfig, or just plain old talking to yourself.&lt;/p&gt;
&lt;p&gt;Being the only programmer in my office is difficult. A simple what do you think of this question that could be asked across the office has to be done inside my head and I may think a needlessly complex solution is better than a simple one just because I haven’t thought of the simpler version yet. There are of course advantages to being the only programmer, I can do what I want and learn any technology I like, but I am starting to think the advantages of programming in a group are outweighing programming alone.&lt;/p&gt;</description></item><item><title>I might actually like SQL Server</title><link>https://blog-test.funkysi1701.com/posts/2015/i-might-actually-like-sql-server/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 23 Apr 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/i-might-actually-like-sql-server/</guid><category term="Learning">Learning</category><category term="SQL">SQL</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/download.jpg"/><description>&lt;p&gt;How did this happen I think I may actually like SQL Server now?&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="SQL Server logo" src="https://blog-test.funkysi1701.com/images/2015/download.jpg" loading="lazy"
width="248" height="203"
/&gt;
&lt;/p&gt;
&lt;p&gt;I remember a few years back when I used to grumble about writing a SQL query that included a JOIN. For some reason back then I could never get my head around JOINs.&lt;/p&gt;
&lt;p&gt;Today is a totally different story. I wrote a deployment script that did the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;dropped a database,&lt;/li&gt;
&lt;li&gt;restored a database from a backup file,&lt;/li&gt;
&lt;li&gt;Created a database table,&lt;/li&gt;
&lt;li&gt;copied the contents of a table into this table,&lt;/li&gt;
&lt;li&gt;disabled and re-enabled some triggers,&lt;/li&gt;
&lt;li&gt;dropped some constraints and columns from a table&lt;/li&gt;
&lt;li&gt;and renamed some columns.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s not like I woke up this morning with SQL Server knowledge. For many years I have been adding extra features and changing functionality to our line of business database and over time my SQL confidence has grown.&lt;/p&gt;
&lt;p&gt;For every single one of the steps above I googled and looked up the SQL syntax (every time I write an insert or update statement I look up the syntax, one day it will stick in my brain!) I think the main reason is once you have used SQL for a while you get to see how it works and can split it down into small steps.&lt;/p&gt;
&lt;p&gt;As I &lt;a href="https://www.funkysi1701.com/posts/2015/weakest-database-design/" target="_blank" rel="noopener noreferrer"&gt;blogged&lt;/a&gt;
the other day I am currently working on improving a bad database and today I wanted to test the deployment process. All my changes are in a SSDT project so I took a backup of my database and tried to publish.&lt;/p&gt;
&lt;p&gt;Error! Your changes will result in data loss, no surprises there as I was expecting that error. The main culprit for this was a trigger I wrote but I didn’t find that out until the end of the day.&lt;/p&gt;
&lt;p&gt;As I was working on a backup I could do what I like including destructive changes. I tried creating a pre deployment script. I thought if that runs first, I can persuade SSDT that it matches SQL Server and therefore no data is being lost.&lt;/p&gt;
&lt;p&gt;This didn’t work, but I had created the start of my script mentioned above. I had steps 3 and 4. Lets try running my script first and then try running the deployment of my SSDT project. To get this to work I am going to have to rebuild my database a few times, I did this manually with SQL Management studio a couple of times until I thought, I could add this to my script – that’s step 1 and 2 done.&lt;/p&gt;
&lt;p&gt;Then I got some errors about triggers so I tried disabling them and re-enabling them after it had finished. That’s step 5.&lt;/p&gt;
&lt;p&gt;Finally I needed to drop some columns, this resulted in an error about a constraint. A few trial and error run through’s to find out which constraints I needed to drop and then I could drop the columns.&lt;/p&gt;
&lt;p&gt;The last step was to rename some columns. I thought after this I can run publish from visual studio. No it still complained about data loss. I dropped another trigger and then I could run everything without any errors.&lt;/p&gt;
&lt;p&gt;Wohoo! Aren’t I clever. A simplified version of my code is below&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;USE master &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;can&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt;t &lt;span style="color:#66d9ef"&gt;drop&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; its &lt;span style="color:#66d9ef"&gt;open&lt;/span&gt;&lt;span style="color:#f92672"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;Step &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DROP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATABASE&lt;/span&gt; DBName
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;Step &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RESTORE &lt;span style="color:#66d9ef"&gt;DATABASE&lt;/span&gt; DBName &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; DISK&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt;E:&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;DBName.bak&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;WITH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;MOVE&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;‘&lt;/span&gt;DBName_dat&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;‘&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;C&lt;/span&gt;:&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;Program Files (x86)&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;Microsoft &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt; Server&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;MSSQL12.MSSQLSERVER&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;MSSQL&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;DATA&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;DBName.mdf&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;MOVE&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;‘&lt;/span&gt;DBName_log&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;‘&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;C&lt;/span&gt;:&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;Program Files (x86)&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;Microsoft &lt;span style="color:#66d9ef"&gt;SQL&lt;/span&gt; Server&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;MSSQL12.MSSQLSERVER&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;MSSQL&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;DATA&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;DBName.ldf&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;REPLACE&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;STATS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;USE DBName &lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;swap back &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; the &lt;span style="color:#66d9ef"&gt;database&lt;/span&gt; you just restored
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;Step &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; TName2 (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ID INT &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Name NVARCHAR(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Address NVARCHAR(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;City NVARCHAR(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Postcode NVARCHAR(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;Step &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DISABLE &lt;span style="color:#66d9ef"&gt;TRIGGER&lt;/span&gt; TR_Trigger &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; TName1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;Step &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; TName2 (Id,Name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; Id, Name &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; TName1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;Step &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; TName1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DROP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONSTRAINT&lt;/span&gt; [DF_Id], [DF_Name]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ALTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; TName1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DROP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;COLUMN&lt;/span&gt; Id, Name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;Step &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sp_RENAME &lt;span style="color:#960050;background-color:#1e0010"&gt;‘&lt;/span&gt;TName1.City&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt;, &lt;span style="color:#960050;background-color:#1e0010"&gt;‘&lt;/span&gt;Area&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt; , &lt;span style="color:#960050;background-color:#1e0010"&gt;‘&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;COLUMN&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;’&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;drop&lt;/span&gt; that &lt;span style="color:#66d9ef"&gt;last&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;trigger&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DROP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRIGGER&lt;/span&gt; TR_Trigger2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;–&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;Step &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ENABLE &lt;span style="color:#66d9ef"&gt;TRIGGER&lt;/span&gt; TR_Trigger &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; TName1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Weakest Database Design</title><link>https://blog-test.funkysi1701.com/posts/2015/weakest-database-design/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 21 Apr 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/weakest-database-design/</guid><category term="BadDesign">BadDesign</category><category term="SQL">SQL</category><category term="DatabaseDesign">DatabaseDesign</category><description>&lt;p&gt;I have been recently working on a database that hasn’t been designed but has been hacked together by lots of people over the years.&lt;/p&gt;
&lt;p&gt;It started life as an Microsoft Access database created by my director to keep track of all the projects that our company does. It was not much more than one table listing everything. At some point the data and frontend was split with the data being stored in SQL Server and the front end being an Microsoft Access ADP.&lt;/p&gt;
&lt;p&gt;Over the years more and more columns have been added to this table that it long ago became pretty much unmanageable. A few normalized tables exist but for the most part everything is stored in this one table which makes querying it very difficult. At the last count there were 81 columns in this one database table.&lt;/p&gt;
&lt;p&gt;Attempts to improve this database have been tried before but due to the fact that the whole company basically runs off this database and no one person knows everything that the database needs to do causes any changes to be very difficult. I suspect it may be beyond my abilities but I am going to give it a go.&lt;/p&gt;
&lt;p&gt;One advantage I have is version control. All the tables and the structure is in version control, so when I break things I can roll them back. Any changes to the front end are also in source control, these are harder to roll back in case of problems but not impossible.&lt;/p&gt;
&lt;p&gt;I have met with department heads to try and establish which of the 81 columns are being used and which could be dropped. Database design shouldn’t be a democracy, your databases should be designed in a way to store your data most efficiently. In this case it felt a bit like the database was playing “the weakest link” with everyone voting off unpopular columns. “You are the weakest database column. Goodbye!” After much discussion I have over 30 columns that can be dropped and 10 or so that require further investigation.&lt;/p&gt;
&lt;p&gt;Using the Visual Studio project of the database, I removed the columns. This generated thousands of errors as most columns are included in loads of views and stored procedures. All these references need removing, so not a small job. This is made worse by the fact that the views and stored procedures are in a mess, and it is very hard to read the T-SQL code and see what is doing what. Part of my next job is going to be tidying up all these queries so I can see what’s what.&lt;/p&gt;
&lt;p&gt;The advantage of using the Visual Studio project to do these changes is that I can generate a SQL script of the changes and I can rerun a few times and test restoring different columns as it is unlikely to be a smooth deployment.&lt;/p&gt;</description></item><item><title>Raspberry Pi security camera project</title><link>https://blog-test.funkysi1701.com/posts/2015/security-camera-with-raspberry-pi-camera/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 15 Apr 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/security-camera-with-raspberry-pi-camera/</guid><category term="PHP">PHP</category><category term="Camera">Camera</category><category term="Bash">Bash</category><category term="RaspberryPi">RaspberryPi</category><category term="Project">Project</category><description>&lt;p&gt;So my first Raspberry Pi project is a security camera. If you have read my previous Raspberry Pi posts you will know that I have been playing about with the camera but I had one or two problems with Pidora so I am using Raspbian for this example.&lt;/p&gt;
&lt;p&gt;To take a photo with the camera module you can use the command raspistill, this has lots of options you can view the full list by just running the command with no arguments. I will list a few options I have used.&lt;/p&gt;
&lt;p&gt;-o filename : this outputs an image to a file with name filename
-vf : vertical flip
-hf: horizontal flip these are useful if the camera is upside down etc
-q number: quality of jpg image between 0 and 100, the default image size is around 3 Mb, I reduced it to quality = 10 which gave me an image size of 300Kb which is more reasonable
-a text: annotate you image with some text, I found that the text needed to start with a character, numbers only failed for me.&lt;/p&gt;
&lt;p&gt;I want to script the creation of images, so I decided to name the files my script created with the time and date.&lt;/p&gt;
&lt;p&gt;This is fairly easy with a bash script.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;DATE=$(date +”%Y-%m-%d_%H%M”)
raspistill -q 10 -vf -hf -a a$DATE -o /var/www/$DATE.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first $DATE is the date I have added to the image itself, because of the problem I encountered with annotating numbers only I have added an extra a to the start of this.&lt;/p&gt;
&lt;p&gt;It is now very easy to get CRON to run this script every few minutes, I decided to run it every 2 minutes.&lt;/p&gt;
&lt;p&gt;My next script tidies up so you don’t get overrun with images.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cd /var/www
ls *.jpg &amp;gt; stills.txt
mencoder -nosound -ovc lavc -lavcopts vcodec=mpeg4:aspect=16/9:vbitrate=8000000 -vf scale=1920:1080 -o timelapse.avi -mf type=jpeg:fps=24 mf://@stills.txt
rm /var/www/*.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The third line in this script does something really rather clever it creates a video from all the images you have taken. In order for this to work you will need to install mencoder (sudo apt-get install mencoder)&lt;/p&gt;
&lt;p&gt;This is all rather good but wouldn’t it be rather cool if this images were uploaded somewhere. If someone was up to no good and they might want to disable your security camera. My first thought was to use something like DropBox, but unfortunately it is not supported by the processor on a raspberry pi. However I have found &lt;code&gt;copy.com&lt;/code&gt; to be rather good for syncing files.&lt;/p&gt;
&lt;p&gt;To install just run wget &lt;code&gt;https://copy.com/install/linux/Copy.tgz&lt;/code&gt; and extract the file to install the client on your raspberry pi.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;./CopyConsole -daemon -u=gary@example.com -p=’mypass’ -root=/home/pi/Copy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This command syncs the folder you have set in -root with copy.com.&lt;/p&gt;
&lt;p&gt;The last thing I did was create a php file running on the webserver that allows you to scroll through the different images. I experimented with using javascript to auto scroll through the images but I found the manual way more useful. All the files I have written I have added to my &lt;a href="https://github.com/funkysi1701/RaspberryPi" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
page.&lt;/p&gt;</description></item><item><title>The Raspberry Pi Adventure Starts</title><link>https://blog-test.funkysi1701.com/posts/2015/the-raspberry-pi-adventure-starts/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 11 Apr 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/the-raspberry-pi-adventure-starts/</guid><category term="Linux">Linux</category><category term="Fedora">Fedora</category><category term="Camera">Camera</category><category term="RaspberryPi">RaspberryPi</category><category term="Pidora">Pidora</category><description>&lt;p&gt;I am currently buzzing with excitement about my Raspberry Pi. I will try to document here what I have done so far.&lt;/p&gt;
&lt;p&gt;I decided to buy the camera module along with my Pi. It was straightforward to connect them up, lift the connector behind the network port, insert the ribbon cable, push connector back down.&lt;/p&gt;
&lt;p&gt;Next I connected up Keyboard, Mouse, Monitor, SD Card and Power. And my Pi had life.&lt;/p&gt;
&lt;p&gt;I was then given a screen full of options to install, Pidora is an OS which is based on Fedora which I have some experience of so I went with that one.&lt;/p&gt;
&lt;p&gt;After that was installed I was presented with a standard desktop with various programs installed.&lt;/p&gt;
&lt;p&gt;So far I had not plugged in a network cable because that would mean sitting in the hall next to the router, I thought before I do that lets see if wifi will work. I have a usb wifi adapter that I use with my PC, so I plugged that in.&lt;/p&gt;
&lt;p&gt;Nothing happened, having some experience of linux I wasn’t surprised. I went to network connections filled in the name of my wifi connection and its password and it connected. WOW! That was easy.&lt;/p&gt;
&lt;p&gt;So I then installed &lt;a href="https://www.webmin.com/download.html" target="_blank" rel="noopener noreferrer"&gt;webmin&lt;/a&gt;
so I could remotely administer it and updated it with YUM. I also started the SSH service so I can use putty to login to my Pi from the comfort of my laptop. Even better than that I found a SSH client for my smart phone so I can even control my Pi from my phone!&lt;/p&gt;
&lt;p&gt;EDIT: I forgot that in order to get webmin to work I needed to do the following.&lt;/p&gt;
&lt;p&gt;mv /etc/redhat-release /etc/redhat-release.bak
echo “Fedora release 20 (Heisenbug)” &amp;gt; /etc/redhat-release&lt;/p&gt;
&lt;p&gt;OK So now I am able to configure settings on my Pi from a browser or use SSH (Secure SHell) to login to run any command I like.&lt;/p&gt;
&lt;p&gt;Now lets lookup how to use the camera. The &lt;a href="https://www.raspberrypi.com/documentation/configuration/camera.md" target="_blank" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;
says that the camera first needs enabling using the command raspi-config. This command doesn’t exist in Pidora. Lets skip it and see if it works anyway. It does! The command raspistill -v -o test.jpg took a picture of my ceiling.&lt;/p&gt;
&lt;p&gt;Now how do I look at this picture remotely. SSH is a command line only interface, so I can see a 2Mb file has been created. How about installing a web server on my Pi?&lt;/p&gt;
&lt;p&gt;yum install httpd&lt;/p&gt;
&lt;p&gt;This install apache which is the default (and very popular) web server.&lt;/p&gt;
&lt;p&gt;service httpd start&lt;/p&gt;
&lt;p&gt;This starts the web server. Going to https://[IP] where [IP] is the ip address of your raspberry pi will show you the default apache page.&lt;/p&gt;
&lt;p&gt;Now if you run raspistill -v -o /var/www/html/image1.jpg it will create your photo on the web server.&lt;/p&gt;
&lt;p&gt;Not bad for my first steps, the command above could be scheduled and images taken every hour. There is also options for recording video.&lt;/p&gt;</description></item><item><title>Building something with Raspberry Pi</title><link>https://blog-test.funkysi1701.com/posts/2015/building-something-with-a-raspberry-pi/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 05 Apr 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/building-something-with-a-raspberry-pi/</guid><category term="MarchIsForMakers">MarchIsForMakers</category><category term="C-Sharp">C-Sharp</category><category term="Arduino">Arduino</category><category term="Hardware">Hardware</category><category term="Electronics">Electronics</category><category term="RaspberryPi">RaspberryPi</category><category term="Project">Project</category><category term="Mono">Mono</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/04/Raspberry_Pi_-_Model_A.jpg"/><description>&lt;p&gt;Many years ago I spent a lot of time learning about electronics. It was great fun, I can’t remember specific things I built, but learning what resistors and capacitors do was fascinating.&lt;/p&gt;
&lt;p&gt;I haven’t really thought about this much as my interests have been concentrated on computers and programming, but recently my interest has been peaked again.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Raspberry Pi Model A board" src="https://blog-test.funkysi1701.com/images/2015/04/Raspberry_Pi_-_Model_A.jpg" loading="lazy"
width="600" height="600"
/&gt;
&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://www.codenewbie.org/" target="_blank" rel="noopener noreferrer"&gt;CodeNewbie&lt;/a&gt;
and &lt;a href="https://hanselminutes.com/" target="_blank" rel="noopener noreferrer"&gt;Hanselminutes&lt;/a&gt;
podcasts have been running a month of stuff about making things and doing clever things with hardware called &lt;a href="https://marchisformakers.com/" target="_blank" rel="noopener noreferrer"&gt;#Marchisformakers&lt;/a&gt;
, this began to start me thinking about this stuff again.&lt;/p&gt;
&lt;p&gt;Yesterday a friend of mine was showing me what he had been doing with a Raspberry Pi and Arduino. It is amazing what you can do with these tiny bits of technology and I was very impressed.&lt;/p&gt;
&lt;p&gt;Now I am thinking what mini project could I play around with and which piece of hardware should I base it on. I don’t know much about the two platforms yet but I have found a &lt;a href="https://www.codenewbie.org/blogs/everything-you-ever-wanted-to-know-about-arduino-and-raspberry-pi" target="_blank" rel="noopener noreferrer"&gt;blog&lt;/a&gt;
post that introduces the two. My current thoughts are to start with the Raspberry Pi, it is a UK technology and it uses a linux OS (which I have some knowledge of).&lt;/p&gt;
&lt;p&gt;Being a windows developer, most of my programming knowledge is with C# and Visual Studio. To use my existing knowledge I could install and use MONO, which means I can program the Raspberry Pi using C# (see &lt;code&gt;https://logicalgenetics.com/raspberry-pi-and-mono-hello-world&lt;/code&gt; for more details about MONO on Raspberry Pi).&lt;/p&gt;
&lt;p&gt;But deciding on a language to use, doesn’t help me choose a project. I haven’t even got myself a Raspberry Pi yet so I may decide more once I have had a play around with it. Thoughts so far include getting wi-fi to work on the Raspberry Pi or maybe adding a camera and sticking it somewhere and taking pictures, maybe even build myself a baby monitor (might go down well with the wife if its baby related)&lt;/p&gt;</description></item><item><title>Building a CI Server with TeamCity</title><link>https://blog-test.funkysi1701.com/posts/2015/teamcity/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 01 Apr 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/teamcity/</guid><category term="ContinuousIntegration">ContinuousIntegration</category><category term="DevOps">DevOps</category><category term="TeamCity">TeamCity</category><category term="Test">Test</category><description>&lt;p&gt;TeamCity is a Continuous Integration software package which is very easy to install and set up. So easy I managed it over a weekend.&lt;/p&gt;
&lt;p&gt;First of all I fired up a VM in Azure. I found that a Basic A1 VM was sufficient so running a CI server doesn’t have to be expensive, alternatively you could always set a Virtual or Physical server on your own network, but that of course takes a bit longer to set up.&lt;/p&gt;
&lt;p&gt;Before I get too far you are probably asking what is Continuous Integration. A Continuous Integration server takes your code from your source control repository, it then automatically builds it, runs automated tests against it and can even deploy it to production. The main advantages of this is that you can see the health of you code, you can also test different configurations.&lt;/p&gt;
&lt;p&gt;So once you have a server ready, you need to install a few things. First &lt;a href="https://www.jetbrains.com/teamcity/download/" target="_blank" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt;
, just install with the default settings. My project is a Visual Studio project so I also needed to install Visual Studio (They have a free edition which does everything I need now, Thank you Microsoft) and SQL Server Express Edition.&lt;/p&gt;
&lt;p&gt;Once TeamCity is installed the rest of the config can be made via the web interface. To make it easier I pointed a domain at my VM (a CNAME record is probably better as an Azure IP address may change) and opened port 80 in the Azure config. First create a build config and then create a VCS Root, this is where you specify where your source control is. TeamCity supports Github and bitbucket and probably many others. You can specify which branch you want to checkout so you can test out the latest features you have written.&lt;/p&gt;
&lt;p&gt;Next you need to configure the steps needed to build your project, whatever you do in Visual Studio can be configured here. You then need to configure how often the build should run, it can be scheduled at specific times, this is how I remember CI servers being configured but now you can also have builds being triggered after commits to source control, very clever.&lt;/p&gt;
&lt;p&gt;That is just about all I have configured so far. My project has a few NUnit tests written for it, these are scheduled to run after every build. In my case 94 of them are currently failing so I now need to learn how my tests work.&lt;/p&gt;
&lt;p&gt;There are additional deployment steps that can be configured but I have not investigated these yet. Notifications about what CI is doing is also possible usually by email but there are other options available.&lt;/p&gt;</description></item><item><title>Monitoring Screens</title><link>https://blog-test.funkysi1701.com/posts/2015/monitoring-screens/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 25 Mar 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/monitoring-screens/</guid><category term="BigScreen">BigScreen</category><category term="Azure">Azure</category><category term="jQuery">jQuery</category><category term="JavaScript">JavaScript</category><category term="Nagios">Nagios</category><category term="Monitoring">Monitoring</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/03/perf.jpg"/><description>&lt;p&gt;We all know that it is important to monitor your servers and services, so you can spot issues before they become problems. I personally have spent a lot of time configuring &lt;a href="https://www.funkysi1701.com/posts/2014/i-love-nagios/" target="_blank" rel="noopener noreferrer"&gt;nagios&lt;/a&gt;
to email me about issues and I have recently been configuring various different alerts in Azure.&lt;/p&gt;
&lt;p&gt;My old boss has this idea that I should have a big monitor screen displaying all the vital stats of my servers and services, I personally disagree with this idea and think that notifications on my phone and email alerts are sufficient. He will no doubt correct my thinking when he reads this, but I believe part of his thinking is to make the monitoring of your infrastructure move visible and make it obvious to anyone that walks past that you have your eye on everything.&lt;/p&gt;
&lt;p&gt;For the purpose of this blog post lets assume he has convinced me and I have convinced my actual boss to spend money on the required technology to do this (No easy feat). What exactly would I display on this screen?&lt;/p&gt;
&lt;p&gt;I have Google Chromecast that I use for streaming various things to my TV, this is a relatively cheap bit of technology that could allow a TV or monitor to display a web page with the required stats displayed.
&lt;img class="img-fluid" alt="Server performance graphs on a monitoring dashboard" src="https://blog-test.funkysi1701.com/images/2015/03/perf.jpg" loading="lazy"
width="980" height="349"
/&gt;
&lt;/p&gt;
&lt;p&gt;The two main sources of information that I want to display are New Relic for monitoring my azure websites and Nagios for monitoring my internal servers. New Relic allows you to easily export live performance data as iframes so I quickly threw together a web page full of these graphs. However if you have a static screen on the wall you don’t want to have to scroll to see different information so I needed to come up with another way to display this information.&lt;/p&gt;
&lt;p&gt;My first thought was a slide show. There are lots of javascript scripts that cycle through a series of images like a slideshow, this could be adapted to cycle through a series of iframes and display everything I want.&lt;/p&gt;
&lt;p&gt;My script goes something like this and requires jquery as well as javascript. First of all the script waits for the page to load completely with the ready function, it then defines the urls which will be put into the iframe one at a time. It than counts the number of urls you have. It then loops through changing the contents of the src attribute in the iframe every few seconds, in my example it changes every 9 seconds but once this is used in production you may want to increase 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-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;(document).&lt;span style="color:#a6e22e"&gt;ready&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;locations&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;URL1&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;URL2&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;etc&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;len&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;locations&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;iframe&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;#frame&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setInterval&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;iframe&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;src&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;locations&lt;/span&gt;[&lt;span style="color:#f92672"&gt;++&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;len&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;9000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now what information wants to be included in a script like this? Showing too much performance data can almost be as bad as not doing it at all as problems gets drowned out in the noise. For me I have performance of my websites, followed by Nagios problems, followed by the azure status page, followed by memory usage of all my servers and lastly showing number of connections to my databases. Another question to consider is what time scales do you want to graph over, too long and you don’t see what is happening now, but too short and you may only worry about an intermittent issue?&lt;/p&gt;</description></item><item><title>Networking Event</title><link>https://blog-test.funkysi1701.com/posts/2015/networking-event/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 22 Mar 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/networking-event/</guid><category term="ITManagers">ITManagers</category><category term="Change">Change</category><category term="Networking">Networking</category><category term="ITBoss">ITBoss</category><category term="Strategy">Strategy</category><description>&lt;p&gt;I recently went to an event called ITBoss organised by &lt;a href="https://www.corecomconsulting.co.uk/" target="_blank" rel="noopener noreferrer"&gt;Core Com Consulting&lt;/a&gt;
. It was really good, helped partly by a free bar and great food.&lt;/p&gt;
&lt;p&gt;The event was hosted in a pub in central Leeds, so I rushed to the train station from work to get there. And yes I was the first to arrive (Why do I always do that?). The event was targeted at IT Leaders and Managers and was limited to about 20 people.&lt;/p&gt;
&lt;p&gt;To begin with I just chatted to the hosts and other people as we waited for everyone to arrive. Once we got going we had a short presentation about the need for Strategy. Interestingly the next day I suggested a strategy meeting with my director, so something must have sunk in from this.&lt;/p&gt;
&lt;p&gt;The main gist of the talk was that IT leaders need to pop there head up from day to day work to look at where they are going, and this should be matched with the overall direction of the company. I agree with this, recently I have been thinking of what direction our infrastructure needs to go in, it is currently just in my head, but at least that is a start. However our company directors are poor at sharing their long term vision, so it is hard for me to know where the company is going. I need to step up and challenge this behavior, so I can deliver the changes that are needed. Not easy but that is what the best IT leaders are doing.&lt;/p&gt;
&lt;p&gt;After this we broke for food, which was very nice. I had a chat with a couple of people. I found it interesting that one gentleman was surprised that I wanted to get into development. I think I understand why, most of the people in the room where senior managers, while I share their job titles, I don’t share their salaries. He saw development as a demotion, I see it as a promotion.&lt;/p&gt;
&lt;p&gt;After food we had some discussion questions. Mine was the first, How to convince others of the need for change? Some interesting ideas where presented, but it is the need to work closely with others, find out their requirements which is the difficult part not anything technical. The other topics of discussion where relating to recruiting people with skills that you have no knowledge of and around the topic of security and privacy in this modern age. Both were very interesting with lots of viewpoints expressed.&lt;/p&gt;
&lt;p&gt;I enjoyed the evening and hope to go to another at some point. Previous events I have been to have been technical, but lacked the networking that this one had. While I am not very good at networking, at this event it was easy to have a conversation or two with people.&lt;/p&gt;</description></item><item><title>Source Control Fail</title><link>https://blog-test.funkysi1701.com/posts/2015/source-control-fail/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 16 Mar 2015 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/source-control-fail/</guid><category term="Git">Git</category><description>&lt;p&gt;Every developer uses source control, it is a great tool for keeping track of changes to your code, seeing who has done what.&lt;/p&gt;
&lt;p&gt;However I keep messing up, my use of it. I am fairly disciplined when creating new features, all my changes will get committed to source control and when I am happy I will deploy these changes to the live system. But as soon as there is a bug, especially one where the client is chasing for a fix, I will deploy a fix as soon as humanly possible on to the live system.&lt;/p&gt;
&lt;p&gt;At first glance there is nothing wrong with what I have described but what happens the next time I deploy a new feature. Yes the bug the client was complaining about gets deployed with the new feature as the fix was never committed into source control. The client gets angry as the bug he was screaming about is back again.&lt;/p&gt;
&lt;p&gt;Every change you make to the system &lt;strong&gt;MUST&lt;/strong&gt; be committed to source control. If it isn’t that change will look like it never existed. I have worked with source control for over 5 years why do I keep making this rookie mistake over and over.&lt;/p&gt;
&lt;p&gt;Troy Hunt has a &lt;a href="https://www.troyhunt.com/10-commandments-of-good-source-control/" target="_blank" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;
about the 10 commandments of using source control. His number two commandment is “If it’s not in source control, it doesn’t exist” He talks more about code you have written being not saved into source control, but the principal is the same for my example as his.&lt;/p&gt;
&lt;p&gt;There are ways to automatically deploy from source control, however most of the time you don’t want your live database being rebuilt because you fixed a typo. Additional steps will need to be implemented and there is still the chance that you might want to bypass these steps to fix the urgent problem. The only way past this problem is for you and everyone on your team to be disciplined and only ever commit to source control first, and only after that deploy live (either automatically or manually)&lt;/p&gt;</description></item><item><title>Azure Traffic Manager</title><link>https://blog-test.funkysi1701.com/posts/2015/azure-traffic-manager/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 12 Mar 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/azure-traffic-manager/</guid><category term="Azure">Azure</category><category term="DevOps">DevOps</category><category term="ITAdmin">ITAdmin</category><description>&lt;p&gt;I have spent most of the day tweaking my Azure websites. Lots of fun!&lt;/p&gt;
&lt;p&gt;Last week unfortunately Azure had some problems and many websites that were running in the North Europe data centre were unavailable for several hours. And you guessed it my websites were hosted here.&lt;/p&gt;
&lt;p&gt;All hosting providers are going to have downtime from time to time and this is just something you have to take on the chin. The important thing to do in times like these is communicate with your customers about what is going on and that you are doing everything you can to restore service.&lt;/p&gt;
&lt;p&gt;However Azure has some amazing features that you can configure to help manage when downtime occurs.&lt;/p&gt;
&lt;p&gt;Azure is Microsoft’s global cloud platform. And it really is global, there are data centres in North Europe, West Europe, Brazil, Japan, two more in Asia and five in the US. In the event of problems it is highly unlikely that more than one of these would go down at once. If all of these are unavailable, I expect the planet earth is facing some kind of cataclysmic event and the fact that my website is down is not a priority.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Azure Traffic Manager" src="https://blog-test.funkysi1701.com/images/2015/IC750592.jpg" loading="lazy"
width="856" height="449"
/&gt;
To take advantage of these multiple data centres, Azure has something called a Traffic Manager.&lt;/p&gt;
&lt;p&gt;Traffic Manager has various settings but I am using it in failover mode. This means that if one website goes down, the next one is used.&lt;/p&gt;
&lt;p&gt;All you need to do is create a traffic manager, add two or more websites to it (called endpoints) and choose a page that needs to be monitored so Azure knows which websites are up and which are down.&lt;/p&gt;
&lt;p&gt;If you are using SSL or custom domain names, there are a few extra steps you need to do. Your custom domain name needs pointing at the traffic manager, not the individual websites. The websites themselves have three domain names, the traffic manager address, the azure address and the custom domain name. The SSL certificate can then be assigned to each website that you have added to the traffic manager.&lt;/p&gt;
&lt;p&gt;That was easy wasn’t it, and now if a website goes down traffic manager will use the next one. While testing this, the transition to the next website was almost immediate. I did notice that if you had a browser showing the website open during a problem you sometimes got an error page, I think this was probably due to browser caching, reopening a tab or browser fixed this issue.&lt;/p&gt;</description></item><item><title>Tidying my desktop</title><link>https://blog-test.funkysi1701.com/posts/2015/tidying-my-desktop/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 11 Mar 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/tidying-my-desktop/</guid><category term="PowerShell">PowerShell</category><category term="Desktop">Desktop</category><category term="ITAdmin">ITAdmin</category><description>&lt;p&gt;My desktop is always a mess. I constantly download files there and forget all about them.&lt;/p&gt;
&lt;p&gt;Every now and then I copy files into sub directories, so my desktop looks sane for a day or two before it gets out of control again.&lt;/p&gt;
&lt;p&gt;Why don’t I write a script that I can schedule to do this for me. Then my desktop will always be tidy.&lt;/p&gt;
&lt;p&gt;I have written a few simple batch scripts, but of course the best scripting language out there at the moment is PowerShell. Lets use that.&lt;/p&gt;
&lt;p&gt;Windows provides a nice little utility for writing scripts called the Windows PowerShell ISE, so let&amp;rsquo;s start by loading that up.&lt;/p&gt;
&lt;p&gt;PS has lots of help included to help you, just run &lt;strong&gt;Get-Help [name of ps command]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To move files you can use &lt;strong&gt;Move-Item&lt;/strong&gt; which works very similar to copy, specify source and destination. In my case I moved files based on their file extension.&lt;/p&gt;
&lt;p&gt;Move-Item *.pdf folder&lt;/p&gt;
&lt;p&gt;Now all I need to do is schedule this script to run either every day or so, or maybe every time I login or switch my computer on.&lt;/p&gt;
&lt;p&gt;PowerShell can do lots more interesting things which hopefully I will blog about soon.&lt;/p&gt;</description></item><item><title>Database Deployment</title><link>https://blog-test.funkysi1701.com/posts/2015/database-deployment/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 05 Mar 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/database-deployment/</guid><category term="Deployment">Deployment</category><category term="Database">Database</category><category term="SQL">SQL</category><description>&lt;p&gt;One of my jobs is adding extra features to our internal databases. There is a fair amount of risk in doing this. I could make a change to one of the queries in the database that stops the rest of the company using it as they need to. This could be a costly mistake, almost as bad as the database server being inaccessible.&lt;/p&gt;
&lt;p&gt;One way to reduce this risk is to test, test and test the database. First I take a backup of the database and make my changes to that. I can do anything I like to my backup database without worrying that it will affect anyone else. Once I have finished making my changes and I have tested that everything is working exactly as I want, I need to apply my changes to the production database.&lt;/p&gt;
&lt;p&gt;Until recently I made a note of every change that I have made and then made the same change to the production database. But what if I forget to apply one of my changes to production, I have a broken database on my hands, disaster!&lt;/p&gt;
&lt;p&gt;But there is a better way to track database changes. SSDT or SQL Server Data Tools.&lt;/p&gt;
&lt;p&gt;Create a Database project with Visual Studio, you can then point this at your live database. This will scan the database and save scripts for all the Tables, Views, Stored Procedures, Triggers and any other object in the database. This doesn’t import the data, just the structures that contain the data. So no data protection issues or problems because your database is terabytes in size.&lt;/p&gt;
&lt;p&gt;Now comes the really cool part, Visual Studio allows you to build a copy of the database from these scripts. All you need to do is edit the scripts and test like you did before. Once you are happy with your changes and everything is working as you want, you can point your visual studio project back at your production database and it will magically deploy all your changes, or if you are as paranoid as me about breaking things, it will create a script that you can thoroughly analyse before running on your production database.&lt;/p&gt;
&lt;p&gt;I do not know why I never thought of setting this up until recently, it will reduce the number of times I roll out my changes but forget to setup permissions, (these can be scripted) or forget that tiny change I did weeks ago but never rolled out.&lt;/p&gt;
&lt;p&gt;And of course all the changes that you make can be saved in source control, so easy to see what changes have been made and by whom.&lt;/p&gt;
&lt;p&gt;This process even works with complicated database structures, in my case I needed to setup three database projects that depend on each other. Dependencies can be setup, and the test databases can even be built with different names for testing on the production server, (although I wouldn’t recommend it!)&lt;/p&gt;</description></item><item><title>Leonard Nimoy lives while remembered</title><link>https://blog-test.funkysi1701.com/posts/2015/hes-really-not-dead-as-long-as-we-remember-him/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 28 Feb 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/hes-really-not-dead-as-long-as-we-remember-him/</guid><category term="Science">Science</category><category term="LeonardNimoy">LeonardNimoy</category><category term="StarTrek">StarTrek</category><category term="Spock">Spock</category><category term="Technology">Technology</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/02/74cc28416b646ae6f87d5a502fbd03b7.jpg"/><description>&lt;p&gt;In the film Star Trek 2: The Wrath of Khan Spock sacrifices himself to save the Enterprise from destruction. What follows is a very moving funeral scene and his coffin is launched into space. McCoy tells Kirk that he is not dead as long as we remember him.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Spock as played by Leonard Nimoy" src="https://blog-test.funkysi1701.com/images/2015/02/Spock_2293.jpg" loading="lazy"
width="720" height="544"
/&gt;
&lt;/p&gt;
&lt;p&gt;Yesterday the actor Leonard Nimoy passed away and millions of trekkies around the world are taking comfort in those words.&lt;/p&gt;
&lt;p&gt;Reading social media it is clear that he affected the lives of millions of people with his portrayal of Spock. I have seen tweets from NASA and astronauts saying how they were encouraged by Star Trek. The chip manufacturer Intel even tweeted about his death. I am sure there are many in the science and technology space that could say Mr Spock encouraged them in some way.&lt;/p&gt;
&lt;p&gt;The portrayal of science and technology in Star Trek had an affect on me. I studied Mathematics, Chemistry and Physics at school, I later did a Physics degree. All because the spark of curiosity about how stuff works was encouraged by a TV show. I remember one time while studying physics learning about the hysteresis curve, then Star Trek the next day mentions detecting changes in the hysteresis curve might solve some problem. Wow the stuff I am learning is in Star Trek!&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Leonard Nimoy colour headshot portrait" src="https://blog-test.funkysi1701.com/images/2015/02/color_nimoy_headshot.jpg" loading="lazy"
width="393" height="500"
/&gt;
&lt;/p&gt;
&lt;p&gt;Later in my life I got involved in working with computers, and as science officer Mr Spock was the first expert in computers I knew.&lt;/p&gt;
&lt;p&gt;But Mr Spock was half Vulcan and suppressed his emotions. There have been times in my life where I have tried really hard to suppress my emotions. I can think of a time when a family member has died and I needed to shut myself in a room, similar to Spock in Naked Time, and wrestle with my emotions. In recent years I have had a more Data approach of exploring my feelings and my humanity as a Vulcan lifestyle of suppressed emotion is not healthy.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Leonard Nimoy giving the Vulcan Live Long and Prosper salute" src="https://blog-test.funkysi1701.com/images/2015/02/74cc28416b646ae6f87d5a502fbd03b7.jpg" loading="lazy"
width="500" height="503"
/&gt;
&lt;/p&gt;
&lt;p&gt;Thank you Leonard Nimoy for all that you gave us, although I never met you I can continue to watch and enjoy your work, Live Long and Prosper.&lt;/p&gt;</description></item><item><title>Source Code for Game of Life</title><link>https://blog-test.funkysi1701.com/posts/2015/source-code-for-game-of-life/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 21 Feb 2015 09:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/source-code-for-game-of-life/</guid><category term="Java">Java</category><category term="SourceCode">SourceCode</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/02/Life.jpg"/><description>&lt;p&gt;Last week I blogged about the Game of Life.&lt;/p&gt;
&lt;p&gt;Well it took some searching through dead hard drives and old USB storage but I found the program I wrote, and better than that I have figured out how to turn it back into source code.&lt;/p&gt;
&lt;p&gt;The file date is November 2004 and the source code has no comments so I don’t know what was going through my head when I wrote it, or even what some of it does.&lt;/p&gt;
&lt;p&gt;To view the source code download &lt;a href="https://blog-test.funkysi1701.com/images/2015/02/Life.src_.zip"&gt;Life.src&lt;/a&gt;
, to download the finished program download &lt;a href="https://blog-test.funkysi1701.com/images/2015/02/Life.zip"&gt;Life&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Life" src="https://blog-test.funkysi1701.com/images/2015/02/Life.jpg" loading="lazy"
width="595" height="300"
/&gt;
&lt;/p&gt;
&lt;p&gt;I am actually surprised I was expected the code to be much worse than it was, I am not saying it is good, but I can see more than one method and I can’t see any code that obviously is repeated. I can see some terrible variable names. Note to future self don’t use tmp676_674!&lt;/p&gt;
&lt;p&gt;Assuming that I wrote this in 2004 what would I have been doing then? It was before I started working in IT. (Hard to imagine I know!) It may even have been before I started living with Keith, before he recruited me for my first IT role. I think I was probably working as an administrator for Defra at this point.&lt;/p&gt;
&lt;p&gt;If we put 2004 in technical terms, it was before I joined facebook, Office 2003 and XP would have been installed on my PC, and probably felt brand new.&lt;/p&gt;</description></item><item><title>Cloud Computing</title><link>https://blog-test.funkysi1701.com/posts/2015/cloud-computing/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 19 Feb 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/cloud-computing/</guid><category term="Cloud">Cloud</category><category term="Azure">Azure</category><category term="Google">Google</category><category term="Computing">Computing</category><category term="OneDrive">OneDrive</category><description>&lt;p&gt;I work for a company that provides a cloud computing website, but what is Cloud Computing?&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Cloud_computing" target="_blank" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;
defines it as “Cloud computing involves deploying groups of remote servers and software networks that allow centralized data storage and online access to computer services or resources.”&lt;/p&gt;
&lt;p&gt;Erm. What does that mean? Well in simple terms it means storing you data on a remote server. Any time you submit information onto a website, you are submitting your information to the “Cloud”&lt;/p&gt;
&lt;p&gt;But there is more that the Cloud can do for you. The search giant Google, which also develops the android mobile phone operating system, have developed a range of cloud computing products. The Google Drive product allows you to upload and even create files, these files are saved into the Cloud, once in the cloud they can be accessed from any device that has an internet connection. No longer do you run the risk of your favourite file being on a computer that won’t turn on or being on a dead hard drive, save it to the cloud and you will always have access to it.&lt;/p&gt;
&lt;p&gt;Google isn’t the only one that does this, Microsoft have OneDrive which they are incorporating into the heart of their operating system, Apple and many other companies have released similar products.&lt;/p&gt;
&lt;p&gt;This age of cloud computing allows a clearer separation between your data and your device. It won’t be long before whatever device you are using your files will be there to be worked on. You are in the office working on a spreadsheet, you save it to the Cloud, you can then continue working on it with your tablet while on the road. Just before bed you want to check if you added something to that doc, so you quickly check your phone. How cool is this!&lt;/p&gt;
&lt;p&gt;But if I put my system administer hat on, Cloud computing goes far further than that. Microsoft Azure allows many of the services you would typically have running on your server, saved into the cloud. This has many advantages and allows you to concentrate on other problems while leaving the cloud to look after these services.&lt;/p&gt;</description></item><item><title>Choosing a Blog Theme</title><link>https://blog-test.funkysi1701.com/posts/2015/blog-theme/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 15 Feb 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/blog-theme/</guid><category term="Theme">Theme</category><category term="Blogging">Blogging</category><category term="WordPress">WordPress</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/02/unnamed.png"/><description>&lt;p&gt;You may have noticed that my blog has a new home. It can now be found on its own domain &lt;a href="https://www.funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;https://www.funkysi1701.com&lt;/a&gt;
. This change not only gives me more flexibility to make any change I like, it also feels good to have a website again. If you had followed my blog, do keep following it at the new location.&lt;/p&gt;
&lt;p&gt;I have also been playing about with giving the site a new look, hope you all like it. I have gone for a more image focussed front page. No doubt in a few weeks I will be bored and change the look again.&lt;/p&gt;
&lt;p&gt;I have recently been reading about blogging and one suggestion is to have a clear theme, or idea of what the blog is about. I am not sure my blog has a clear theme.&lt;/p&gt;
&lt;p&gt;When I started blogging I was more interested in blogging than thinking about what I was blogging about. The vague theme I worked off was to talk about what I do, to answer the question, &amp;ldquo;What do you do?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I think this is a fairly good theme, but it could probably do with some refinement. The best themed blogs are specialist or about something specific. As I am generally learning about development, rather than doing development I think this should be part of what I concentrate my blogs about. A minority of my blogs can continue to be about the other things I spend my time doing, as it’s always good to have a break from the main “meat” of the blog every now and then.&lt;/p&gt;
&lt;p&gt;The people who read my blogs are split between technical people and non-technical people, so I would like to continue to explain what I do in non-technical terms. This is an essential skill for a developer (or SysAdmin) as you will always need to explain what you are doing, or discuss requirements. It is not an easy skill and like development itself, the more I do it the better at it I will become.&lt;/p&gt;
&lt;p&gt;So watch this space for the blogs to come. I know I will be working with Azure over the next few weeks so maybe some blogs about that, maybe some more SQL blogs or maybe about what I learn next.&lt;/p&gt;</description></item><item><title>Ten Forward 135: desert island Trek</title><link>https://blog-test.funkysi1701.com/posts/2015/ten-forward-episode-135-anti-firbob-is-back-or-simons-desert-island-trek/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 13 Feb 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/ten-forward-episode-135-anti-firbob-is-back-or-simons-desert-island-trek/</guid><category term="StarTrek">StarTrek</category><category term="Podcast">Podcast</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/02/Spock_and_Horta_mind_meld1.jpg"/><description>&lt;p&gt;The podcast I recorded the other week has been released — why not have a listen by heading over to &lt;a href="https://www.trekmate.org.uk/ten-forward-episode-135-anti-firbob-is-back-or-simons-desert-island-trek/" target="_blank" rel="noopener noreferrer"&gt;trekmate.org.uk&lt;/a&gt;
?&lt;/p&gt;
&lt;p&gt;This week Sina, Chris and Paul welcome Simon Foster, Trek Mate’s News Editor, to do discuss his Desert Island Trek choices. Paul becomes Firbob, or AntiFirbob, or&amp;hellip;something like that. Boo hiss Firbob. Every one listen and decide – Simon or Firbob?&lt;/p&gt;
&lt;p&gt;You can reach Simon here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Complaints to @firbob1&lt;/p&gt;
&lt;p&gt;You can reach the rest of the gang here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/queenkatblue" target="_blank" rel="noopener noreferrer"&gt;@queenkatblue&lt;/a&gt;
, &lt;a href="https://twitter.com/chriscantfly" target="_blank" rel="noopener noreferrer"&gt;@chriscantfly&lt;/a&gt;
, or &lt;a href="https://www.facebook.com/TenForwardPod" target="_blank" rel="noopener noreferrer"&gt;facebook.com/TenForwardPod&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Game of Life</title><link>https://blog-test.funkysi1701.com/posts/2015/game-of-life/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 11 Feb 2015 09:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/game-of-life/</guid><category term="Java">Java</category><description>&lt;p&gt;Many, many years ago I tried to learn Java. I didn’t get very far but one of the things I built was The Game of Life.&lt;/p&gt;
&lt;p&gt;Unfortunately I can not find the code I wrote, probably a good things as it is probably amusingly bad.&lt;/p&gt;
&lt;p&gt;Now you are probably asking what is the &lt;a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life" target="_blank" rel="noopener noreferrer"&gt;Game of Life&lt;/a&gt;
? The game of life, sometimes called cellular automation, is a simulation of cells being born and dying. It is sometimes called Conway’s Game of Life after the British mathematician who devised it in 1970.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Gosper&amp;rsquo;s glider gun pattern in Conway&amp;rsquo;s Game of Life" src="https://blog-test.funkysi1701.com/images/Gospers_glider_gun.gif" loading="lazy"
width="250" height="180"
/&gt;
&lt;/p&gt;
&lt;p&gt;The game has several rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Any cell with less than three neighbours will die on the next turn&lt;/li&gt;
&lt;li&gt;Any cell with three neighbours lives on to the next turn&lt;/li&gt;
&lt;li&gt;Any cell with more than three neighbours will die on the next turn&lt;/li&gt;
&lt;li&gt;Any dead cell with three live neighbours will be born on the next turn&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now I had not thought about this game until the other day when I came across a &lt;code&gt;https://chaosnil.wordpress.com/2015/02/09/new-project-conways-game-of-life-in-every-language/&lt;/code&gt; and a &lt;code&gt;https://github.com/chaomodus/gameoflife&lt;/code&gt; which sparked my interest again. This version is written in javascript, but the blog mentions a desire to build this program in many different languages. I want to build this with visual studio in C# as it should provide a good training exercise.&lt;/p&gt;
&lt;p&gt;There are several problems I need to overcome to achieve this, I am currently trying to work out how to &amp;ldquo;draw&amp;rdquo; the cells. My current thinking is that maybe I can code it using characters to display the cells and then replace with pixels once I have the logic correct. Well lots for me to learn!&lt;/p&gt;</description></item><item><title>Great British Code Off</title><link>https://blog-test.funkysi1701.com/posts/2015/great-british-code-off/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 07 Feb 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/great-british-code-off/</guid><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/02/logo1.jpg"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Great British Code Off" src="https://blog-test.funkysi1701.com/images/2015/02/logo.jpg" loading="lazy"
width="242" height="157"
/&gt;
&lt;/p&gt;
&lt;p&gt;The Great British Bake Off and The Great British Sewing Bee are very popular TV shows. Each week the contestants take part in a baking or sewing challenge and the judges choose the best and the worst, with the worst having to leave. This is very entertaining as you watch the drama between the contestants and the reactions as the judges tell them they are rubbish.&lt;/p&gt;
&lt;p&gt;Could this simple format be applied to computer programming? I think it could.&lt;/p&gt;
&lt;p&gt;The only developers I know argue about the best way of tackling different problems, despite being friends. I am going to assume that this is typical behaviour and not unique to them. So for this TV show, we will split the contestants into pairs, that way we would get the added drama of how well they work together.&lt;/p&gt;
&lt;p&gt;I am still undecided if the pairs stick together each week with one pair leaving or if we randomize the pairs with one person leaves. The second option would cause there to be a group of three every other week, not sure if this would be a benefit or a curse for that group.&lt;/p&gt;
&lt;p&gt;My friends who are experienced programmers have agreed to be the judges, they both have experience of hiring and firing people, know what to look for in good code, and never agree so should be entertaining enough.&lt;/p&gt;
&lt;p&gt;On the bake off the contestants don’t really know how well they have done until the judges cut into their cake and take a bite. For the code off we could not compile the code until the judges run it, would make coding extra difficult as if the contestants are anything like me, I run my code every five minutes to see what affect that change has made.&lt;/p&gt;
&lt;p&gt;So what challenges can we come up with?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web Design week&lt;/li&gt;
&lt;li&gt;Stored Procedure week&lt;/li&gt;
&lt;li&gt;Mobile App week&lt;/li&gt;
&lt;li&gt;Loops&lt;/li&gt;
&lt;li&gt;Logic problems&lt;/li&gt;
&lt;li&gt;Bugs weeks&lt;/li&gt;
&lt;li&gt;Performance issues&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think we are onto a winner here. What does everyone else think?&lt;/p&gt;</description></item><item><title>Laziness</title><link>https://blog-test.funkysi1701.com/posts/2015/laziness/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 04 Feb 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/laziness/</guid><category term="PowerShell">PowerShell</category><category term="RDP">RDP</category><category term="Lazy">Lazy</category><category term="ITAdmin">ITAdmin</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/02/bill-gates-quote.jpg"/><description>&lt;p&gt;I am lazy, I won’t try and deny that. When my alarm goes off in the morning, I will snooze it for twenty minutes or so before getting out of bed.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Bill Gates quote about hiring a lazy person for a difficult job" src="https://blog-test.funkysi1701.com/images/2015/02/bill-gates-quote.jpg" loading="lazy"
width="460" height="298"
/&gt;
&lt;/p&gt;
&lt;p&gt;In my work my laziness continues. Remote Desktop (or RDP) is probably my number one laziness tool. For those that don’t know RDP allows you to connect to another computer and access it like you were sat in front of it. So I can be sat at my desk and RDP into any other computer in the office including any server. However this laziness tool does sometimes require a bit of effort sometimes, powering on the target computer, logging on locally, making sure the user account you are using is allowed to use RDP.&lt;/p&gt;
&lt;p&gt;Writing a script is another example of a laziness tool. I often get asked to do tedious and long-winded task, because I am lazy I will go out of my way to learn how to write a script to do this, so that I can run this script and do this long-winded task in a matter of seconds. There are loads of different types of scripts from database SQL scripts, to PowerShell scripts that can do almost anything on your server.&lt;/p&gt;
&lt;p&gt;PowerShell is something Microsoft are really pushing at the moment, you can even write scripts to create new user accounts, so no longer will you have to remember to tick that tickbox for every new user account. And because PowerShell is part of almost all MS technologies you can link Exchange to Active Directory and you don’t even have to remember the right syntax as PowerShell has a built-in help command to tell you how to run that useful command.&lt;/p&gt;
&lt;p&gt;As I am now moving into a more developer role can I continue to be lazy? I sure can. Code should be written once and reused as often as possible and this is one of the features of OOP (Object Oriented Programming).&lt;/p&gt;
&lt;p&gt;It can be as simple as creating a master page so you don’t need to recreate the same code on every one of your webpages. Or every time you find yourself rewriting the same code again, you plug it into a method so it can be called again and again.&lt;/p&gt;
&lt;p&gt;But of course the ultimate way to be lazy is of course get yourself some staff and spend all day getting them to do everything. If you are lucky they may even try and adopt some of these lazy ideas.&lt;/p&gt;</description></item><item><title>Podcasts</title><link>https://blog-test.funkysi1701.com/posts/2015/podcasts/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 27 Jan 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/podcasts/</guid><category term="ITAdmin">ITAdmin</category><category term="StarTrek">StarTrek</category><category term="Podcast">Podcast</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/01/128900.png"/><description>&lt;p&gt;For a while now I have been listening to podcasts. For those that don’t know a podcast is an audio file that you can download and listen to, usually about a topic you are interested in. The topics that interest me are obviously Star Trek, Science and Technology and IT stuff. I mainly listen to them in the car when I am driving, but sometimes it will be at home when doing jobs around the house.&lt;/p&gt;
&lt;p&gt;I think the first podcast I listened to was &lt;a href="https://www.trekmate.org.uk/" target="_blank" rel="noopener noreferrer"&gt;Trekmate&lt;/a&gt;
. Trekmate as the name suggests is about Star Trek, it’s a few guys talking about Star Trek. It’s very similar to those conversations you have in the pub with your mates. Trekmate do lots of podcasts, one for almost every flavour of Star Trek out there, I don’t keep up with all of them, but the ones I listen to I really enjoy.&lt;/p&gt;
&lt;p&gt;My favourite podcast that is work related is &lt;a href="https://www.runasradio.com/" target="_blank" rel="noopener noreferrer"&gt;RunAs Radio&lt;/a&gt;
. If you are a SysAdmin or have an interest in servers or IT you should listen to this. The host Richard Campbell interviews IT experts about a particular piece of technology, one week it will be Exchange, the next Security, and then SQL Server. Often I will learn something that I will want to try out, some weeks I won’t learn something specific but will give be an insight into which way IT for businesses is going. I think it was probably only after listening to RunAs Radio that are started having more of a long term plan for my IT infrastructure at work.&lt;/p&gt;
&lt;p&gt;As I have blogged about before I am learning Development so obviously I listen to &lt;a href="https://www.dotnetrocks.com/" target="_blank" rel="noopener noreferrer"&gt;.NET Rocks&lt;/a&gt;
. This is hosted by Carl Franklin and Richard Campbell (yes the same guy that does RunAs Radio) who talk to developers about code, learning and IT from a more Developer point of view. This is released 3 times a week so is a bit hit and miss sometimes, but most weeks there will be something relevant to me or worth listening to.&lt;/p&gt;
&lt;p&gt;A few days ago I did something for the first time, I was a guest on one of the Trekmate pods, TenForward. I reviewed 5 Star Trek episodes. This was a bit of a leap for me as an introvert I don’t like to be the center of attention and I certainly don’t like how my voice sounds recorded. Hopefully when released people will like it and I will do lots more of these in the future. Once it has been released I will put a link up here so you can all have a listen.&lt;/p&gt;</description></item><item><title>Pair Programming</title><link>https://blog-test.funkysi1701.com/posts/2015/pair-programming/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 19 Jan 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/pair-programming/</guid><category term="PairProgramming">PairProgramming</category><category term="FreeCodeCamp">FreeCodeCamp</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2015/01/PairProgrammingInAction.jpg"/><description>&lt;p&gt;So I have been working through the challenges on the &lt;a href="https://www.freecodecamp.org/" target="_blank" rel="noopener noreferrer"&gt;freecodecamp&lt;/a&gt;
website and one of the unique things that this site does is give you the chance to program with another person.&lt;/p&gt;
&lt;p&gt;I am an introvert and if you were to ask me to pick up the phone and ring someone I will procrastinate a lot before doing it (if I do it at all), I also am not good at speaking with strangers but I have been enjoying the pair programming I have done so far.&lt;/p&gt;
&lt;p&gt;I have only pair programmed a couple of times so far, so I am no expert. The first time was with someone from North America, it was weird to begin with talking to your computer and hearing an american voice respond, but you soon forget that as you concentrate on the problems you are working on.&lt;/p&gt;
&lt;p&gt;The second time was with someone from the Netherlands. This time we tackled some trickier problems. Both times I took more of a back seat but I think contributed useful stuff and I certainly learnt a lot from the other person.&lt;/p&gt;
&lt;p&gt;I think that is the key thing about pair programming, you learn so much about how to look at a problem from another angle, or learn about a function you haven’t heard of before. If you are reading this and it was you that I pair programmed with a big thank you for spending the time with me, I learnt a lot.&lt;/p&gt;
&lt;p&gt;I was trying to pair program again tonight but technical problems prevented me. One problem I have found is finding a partner, was hoping to do some yesterday but no one else was around to partner with.&lt;/p&gt;
&lt;p&gt;I would be interested to learn what companies use pair programming. I imagine a pointy haired boss would say why pay two people to do one job, when you could get them working on different things. However if you want to build up your team and give them loads more skills then pair programming would be great. I also think there are probably some problems that are crying out for pair programming.&lt;/p&gt;</description></item><item><title>Javascript progress</title><link>https://blog-test.funkysi1701.com/posts/2015/javascript-progress/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 16 Jan 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/javascript-progress/</guid><category term="JavaScript">JavaScript</category><category term="SourceCode">SourceCode</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/01/logo_JavaScript.png"/><description>&lt;p&gt;I got excited earlier this week as I started playing around with the javascript I have been learning.&lt;/p&gt;
&lt;p&gt;I thought I would try and create useful javascript that could be applied to an online filestore. Somewhere that you could upload, delete, edit files and folders and various options to do with your files would popup via javascript or jquery code.&lt;/p&gt;
&lt;p&gt;So far I have created a static HTML page which lists a few dummy files. I have added a button which adds a new row into my table and I have used jquery to highlight any selected files and also when the mouse passes over.&lt;/p&gt;
&lt;p&gt;If you want to follow my progress I have put my files on &lt;a href="https://github.com/funkysi1701/CodeSamples/tree/master/clouds-js" target="_blank" rel="noopener noreferrer"&gt;github&lt;/a&gt;
. It’s very basic stuff and I have already got a few lines I would like to refactor but not bad for an evenings work. I have lots of feature ideas to add to this page which should help me learn the basics.&lt;/p&gt;
&lt;p&gt;The trouble with learning all this javascript is that I am starting to get all my programming languages confused. Earlier this week I started writing a for loop in javascript, only problem was I was working on an MS Access ADP (Don’t ask!) which requires the code in VBA. That is never going to work. Oh well.&lt;/p&gt;
&lt;p&gt;If anyone knows good ways to stop myself getting my programming languages all confused do let me know.&lt;/p&gt;</description></item><item><title>My Year of Code</title><link>https://blog-test.funkysi1701.com/posts/2015/my-year-of-code/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 09 Jan 2015 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2015/my-year-of-code/</guid><category term="JavaScript">JavaScript</category><category term="jQuery">jQuery</category><category term="FreeCodeCamp">FreeCodeCamp</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2015/01/AK29YaTf_400x400.png"/><description>&lt;p&gt;There is no escaping the fact that we are in 2015 now. My new years resolution is to do more coding.&lt;/p&gt;
&lt;p&gt;Over Christmas I thought I would have a go at &lt;a href="https://www.codecademy.com" target="_blank" rel="noopener noreferrer"&gt;https://www.codecademy.com&lt;/a&gt;
I completed the javascript course and I was just wondering what I should try next when I saw a tweet about &lt;a href="https://www.freecodecamp.org/" target="_blank" rel="noopener noreferrer"&gt;freecodecamp&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Since then I have been addicted to doing the exercises that they have, almost everyday I have made a bit of progress.&lt;/p&gt;
&lt;p&gt;But this site is not just about teaching you how to code, it has an active forum where you can ask questions and understand more about what it takes to become a developer.&lt;/p&gt;
&lt;p&gt;Before I started these exercises I didn’t know much javascript or jquery but I am starting to learn quite a few commands that hopefully I can put into use at some point. Whatever development I end up doing I am sure I am going to need javascript at some point.&lt;/p&gt;
&lt;p&gt;One of the tips I have learnt is that you need to practise daily. Did you ever use flash cards to help pass exams? Well there is an electronic version of them now called Anki. Just add a question/answer pair to your deck of cards and review them each day, the ones you find difficult you review more often than the ones you have learnt.&lt;/p&gt;
&lt;p&gt;Hopefully I can keep this up and later in the year I will be well on way to writing lots of useful code.&lt;/p&gt;</description></item><item><title>2014 in review: lessons I learned</title><link>https://blog-test.funkysi1701.com/posts/2014/looking-back-at-2014/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 31 Dec 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/looking-back-at-2014/</guid><category term="Goals">Goals</category><category term="Azure">Azure</category><category term="ITAdmin">ITAdmin</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/12/2014-Numbers-Happy-2014-Wallpaper-New-Year-Image-1024x768.jpg"/><description>&lt;p&gt;As today is New Years eve I thought it would be a good chance to look back over the last year.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Tangled network cables illustrating IT complexity" src="https://blog-test.funkysi1701.com/images/2014/12/tangle.jpg" loading="lazy"
width="1065" height="909"
/&gt;
&lt;/p&gt;
&lt;p&gt;At the start of the year I finally got agreement for the installation of a 30MB leased line. This was an amazing achievement as I had been really struggling to keep everything working on our ADSL connections and the complexity of the connections was starting to cause problems itself.&lt;/p&gt;
&lt;p&gt;However it was not a smooth process, the site survey revealed a substantial installation cost would be required, however the Council was about to launch a voucher scheme that would give us £3000 off. So most of this was just waiting around for the Council to get things going. By April we had it installed and I have been very happy with the ISP we chose, York Data Service (YDS).&lt;/p&gt;
&lt;p&gt;Also during April this year was the end of support for Windows XP and Office 2003. This didn’t impact us too much, mostly due to my constant nagging of the directors to replace our oldest machines. We now only have a couple of machines still running XP and no machines running Office 2003. Most machines are now running Windows 7, I have one Director running Windows 8 for presentations and a few surveyor tablets running windows 8 as well. Like many businesses I am waiting for Windows 10 next year before doing any more substantial replacement of OS.&lt;/p&gt;
&lt;p&gt;In May it was decided that I would move more into development work, so I got a new desktop PC and Visual Studio. I am very happy with my new machine (subject to dell fixing a problem later today) So far I have only dipped my toe into development work, this is largely due to needing more time to build up others to do what I do.&lt;/p&gt;
&lt;p&gt;In June I made another huge achievement. I got agreement for a new server. This was our first Server 2012 server and allowed us to make huge strides towards virtualizing our services. Once we had this server up and running I was able to decommission two of our Windows Server 2003 machines well before it goes out of support next year.&lt;/p&gt;
&lt;p&gt;I am a huge fan of this new server, I have only used a fraction of its memory. Hyper V is really great and I hope to make progress next year into HyperV replication.&lt;/p&gt;
&lt;p&gt;Also during 2014 we made huge progress with our clouds software. Within the last few weeks it is running on the Azure platform which will not only make it far easier to expand and create new features it will provide us with cost savings. I am looking forward to learning more about Azure as I get deeper into development.&lt;/p&gt;
&lt;p&gt;Wow I achieved a lot didn’t I, on top of this I hired a new IT person and trained him up (still more to do), I have also fixed lots of printers, websites, servers (had a server motherboard die!), and made hundreds of changes to our internal databases.&lt;/p&gt;
&lt;p&gt;I don’t know what is in store for 2015. I expect a lots of the same with hopefully more focus on developing in Visual Studio, training myself and my department and getting the last few tweaks into our internal servers.&lt;/p&gt;
&lt;p&gt;I would also like to thank everyone that I have worked with over the last 12 months (you know who you are), as you made a lot of what I have just described possible.&lt;/p&gt;</description></item><item><title>Ultimate software developer quiz</title><link>https://blog-test.funkysi1701.com/posts/2014/software-developer-quiz/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Fri, 05 Dec 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/software-developer-quiz/</guid><category term="Quiz">Quiz</category><category term=""/><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/12/Quiz-e1354812026198.jpg"/><description>&lt;p&gt;Moving house, lack of internet and lack of inspiration has caused a lack of posts recently but hopefully more to come. Been doing some filing and found an old software developer quiz. Thought I would have a go.&lt;/p&gt;
&lt;p&gt;Many thanks to &lt;a href="https://twitter.com/zogface"&gt;Keith&lt;/a&gt; for originally writing the quiz.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Questions:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a function that determines if a string starts with an upper-case letter A-Z&lt;/li&gt;
&lt;li&gt;Write a function that determines the area of a circle given the radius&lt;/li&gt;
&lt;li&gt;Add up all the values in an array of integers&lt;/li&gt;
&lt;li&gt;Given a table called &amp;ldquo;Nodes&amp;rdquo; with the following structure and sample data (see below after questions):
…where ID is the primary key,andParentID references ID, complete the following:
&lt;ul&gt;
&lt;li&gt;write a stored procedure to return all nodes beneath a given node ID&lt;/li&gt;
&lt;li&gt;describe how you might write a query to return all nodes at any depth below a given node ID (i.e. recursively)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Write a function to get the prime numbers up to 1,000,000&lt;/li&gt;
&lt;li&gt;You’ve been given the following code to review (below table)– what comments would you give back to the developer?&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;ParentID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Depth&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;My Documents&lt;/td&gt;
&lt;td&gt;Folder&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;My Pictures&lt;/td&gt;
&lt;td&gt;Folder&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;My CV&lt;/td&gt;
&lt;td&gt;Document&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Photo of me&lt;/td&gt;
&lt;td&gt;Document&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PROCEDURE&lt;/span&gt; GetNode
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;@&lt;/span&gt;NodeId INT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DECLARE&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID INT, &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ParentID INT, &lt;span style="color:#f92672"&gt;@&lt;/span&gt;Name NVARCHAR(&lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;DECLARE&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; NVARCHAR(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;), &lt;span style="color:#f92672"&gt;@&lt;/span&gt;Depth INT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ID &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; Nodes &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ParentID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ParentID &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; Nodes &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;IF&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;EXISTS&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; Nodes &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID &lt;span style="color:#66d9ef"&gt;AND&lt;/span&gt; Name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;Name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ELSE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;Name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Name &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; Nodes &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; Nodes &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;Depth &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Depth &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; Nodes &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ID, &lt;span style="color:#f92672"&gt;@&lt;/span&gt;ParentID, &lt;span style="color:#f92672"&gt;@&lt;/span&gt;Name, &lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Type&lt;/span&gt;, &lt;span style="color:#f92672"&gt;@&lt;/span&gt;Depth
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;My Answers:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; GetUpper(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;.IsUpper(&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;double&lt;/span&gt; AreaOfCircle(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; radius)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;double&lt;/span&gt; area = &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; area = Math.PI * radius * radius;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; area;
&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;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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; SumArray()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;[] MyArray = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;] { &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; Sum = MyArray.Sum();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Sum;
&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;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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;create&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;procedure&lt;/span&gt; getnodes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;node int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; dbo.nodes &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; parentid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;node
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For a recursive query I would write something along the lines of, but it would need to be customised depending on the depth, eg more joins for higher depths&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; dbo.nodes n1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; dbo.nodes n2 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; n1.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; n2.ParentId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;join&lt;/span&gt; dbo.nodes n3 &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; n2.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; n3.ParentId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; n1.parentid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4544054&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; prime()
&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; Console.WriteLine(&lt;span style="color:#e6db74"&gt;&amp;#34;Prime: 1&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; i = &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;; i &amp;lt;= &lt;span style="color:#ae81ff"&gt;1000000&lt;/span&gt;;i++ )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; isprime = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; j = &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;; j &amp;lt;i; j++)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(i%j==&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isprime = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (isprime)
&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; Console.WriteLine(&lt;span style="color:#e6db74"&gt;&amp;#34;Prime: &amp;#34;&lt;/span&gt;+i);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No Brackets around parameters, @NodeId parameter never used, select @id = id from dbo.nodes where id = @id is pointless as same id that is passed it being set, Name = NULL should be Name is NULL, no from specified in last query. There are probably more issues as well.&lt;/p&gt;</description></item><item><title>Get in the zone, boost productivity</title><link>https://blog-test.funkysi1701.com/posts/2014/in-the-zone/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 02 Nov 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/in-the-zone/</guid><category term="Zone">Zone</category><category term="VisualStudio">VisualStudio</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2014/11/keep-calm-and-get-in-the-zone.png"/><description>&lt;p&gt;On Friday night I had the urge to fire up Visual Studio and tomorrow (Monday) I move house.&lt;/p&gt;
&lt;p&gt;What’s with that? Why am I in a programming mood when I have boxes to pack and shelves to take apart?&lt;/p&gt;
&lt;p&gt;For the last few weeks I have been too busy with other things to do much programming or when I had the time I felt more like relaxing than learning anything new.&lt;/p&gt;
&lt;p&gt;How do I get into the programming zone, what was it about this particular weekend that made me want to? Was it just the fact I had no time to concentrate on it, or is there some more useful factor that controls my desire to code?&lt;/p&gt;
&lt;p&gt;I can think of a few factors that I should make note of.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Peace and quiet – Friday night I had the place to myself so I could concentrate and do whatever I wanted.&lt;/li&gt;
&lt;li&gt;Ideas – Before I started I had some ideas, why don’t I try doing x. Once I have a coding idea I need to investigate it and see where it goes.&lt;/li&gt;
&lt;li&gt;Break from routine – Friday night was the start of a whole week away from work, this gives me more time to forget about the daily stress of the office and think about other things.&lt;/li&gt;
&lt;li&gt;Goals – Work annoyed me on Friday and if I want to achieve my goal of working in development more then I need to work at it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I am not sure how I can put these into practise so that I spend more time on development but we will see. One thing I want to achieve in my new home is a quiet place to concentrate and think without distractions, I have a few options which I will investigate over the next few weeks.&lt;/p&gt;
&lt;p&gt;Anyway need to get back to packing boxes.&lt;/p&gt;</description></item><item><title>If you had £5,000 for technology</title><link>https://blog-test.funkysi1701.com/posts/2014/if-you-had-5000-to-spend-on-technology-what-would-you-get/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 26 Oct 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/if-you-had-5000-to-spend-on-technology-what-would-you-get/</guid><category term="Servers">Servers</category><category term="Spending">Spending</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/itunes_dnr.jpg"/><description>&lt;p&gt;I listen to the dot net rocks podcast and they ask this question every show. (If you don’t listen then you should!)&lt;/p&gt;
&lt;p&gt;I don’t know what my answer would be as there are so many gadgets and cool things that I like the sound of.&lt;/p&gt;
&lt;p&gt;I might get a surface pro 3, it’s a tablet with attachable keyboard that’s more powerful than my current laptop. But at £600 it’s expensive so maybe not. Maybe instead I would install a SSD into my existing laptop to increase disk performance.&lt;/p&gt;
&lt;p&gt;I’d like a new car with lots of gadgets built-in. A friend gave me a ride in his new BMW and it’s nice. Bluetooth so I don’t have to have an audio cable to listen to podcasts. Parking sensors so no chance the wife will prang it. Built in satnav etc&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Google self-driving car prototype" src="https://blog-test.funkysi1701.com/images/2014/google-car.png" loading="lazy"
width="599" height="428"
/&gt;
&lt;/p&gt;
&lt;p&gt;While we are on the subject of cars eventually I’d like a google self driving car as I think Google is a better driver than me. Think about it I drive to a friends I have a drink I sleep in the back seat as my car drives me home. Once all cars are automated I believe the roads will be much safer.&lt;/p&gt;
&lt;p&gt;The last thing I would spend on is an intensive training course on development, I would really like to get further in dev and more training would really help. Specifically something that would help solve my current dev problems. I am sure it is possible for me to learn dev with self-study but that requires a discipline I don’t think I have, I easily eat my time up with my current job, wife and other interests.&lt;/p&gt;
&lt;p&gt;I recently had £6500 to spend on improving my employers IT infrastructure. That was really hard. It sounds like a lot of money, but it really isn’t.&lt;/p&gt;
&lt;p&gt;Once I started looking at the problems that I wanted to solve and what hardware I wanted I quickly used it all up and that was before I factored in license and software costs. In the end I just had to order what I wanted and hope that on a future date I could spend on other areas. I got a super powerful server that I could virtualize almost all our existing physical servers with it I needed licences, which left me just enough to get a NAS for file storage.&lt;/p&gt;</description></item><item><title>Top IT interview questions to answer</title><link>https://blog-test.funkysi1701.com/posts/2014/interview-questions/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Thu, 23 Oct 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/interview-questions/</guid><category term="ITAdmin">ITAdmin</category><category term="Interview">Interview</category><category term="Technical">Technical</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/10/how-not-to-ace-the-technical-interview.jpg"/><description>&lt;p&gt;I have done a few interviews from both sides of the table, I’m not very good at either but thought I would have a go at answering my favourite questions.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="How not to ace the technical interview cartoon" src="https://blog-test.funkysi1701.com/images/2014/10/how-not-to-ace-the-technical-interview.jpg" loading="lazy"
width="550" height="454"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Describe an IT disaster and what you did to turn it around?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The question is all about the turn it around bit. I’ve had lots of answers that emphasise the problem rather than what the candidate did to turn things around.&lt;/p&gt;
&lt;p&gt;My answer would be: on a Saturday I was rearranging the server room and when I came to turn on our main file server and pdc it wouldn’t boot. My plans for the weekend went out the window it was all about getting this server back up. I tried the usual unplug everything and reconnect still nothing. I rang a friend to get a second opinion and between the two of us we formulated a plan of action. I then rang my director to tell her that I was having problems and what I was going to try. (keeping people informed is an essential skill)&lt;/p&gt;
&lt;p&gt;So the server in question was getting power but nothing was happening during boot. The motherboard had died. What I needed to do was connect the raid card to another server so I could copy the data from it to our Nas drive (luckily I had an upgrade plan and this failure had just accelerated it)&lt;/p&gt;
&lt;p&gt;A few hours later the data was copying and I could breathe again. I told my director that I had fixed things but there would be minor issues on Monday.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Describe your strengths and weaknesses?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It wouldn’t be an interview without a strengths and weaknesses question. As an interviewer I want at least one weakness and I want it to actually be a weakness.&lt;/p&gt;
&lt;p&gt;My strengths are my problem solving skills, I can look at a problem and investigate what is going on and find a solution. If its a technology I haven’t used before I can read up about it and find out how it works and then use it to solve the issue.&lt;/p&gt;
&lt;p&gt;My weakness is my interpersonal skills, I am much better at analysing a computer issue than figuring out why one member of my staff is not performing. This is an area that is improving over the last few years I have taken on more responsibility over people and I am learning more about getting the best out of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Technical Questions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have never included technical questions in one of my interviews until recently and I think it is a good way to gauge ability. I often come out of an interview unsure how well that person would perform under the stresses of my job. If I have something down on paper it is a good start.&lt;/p&gt;
&lt;p&gt;But the personality that comes through during the interview must also be considered as most knowledge can be taught.&lt;/p&gt;
&lt;p&gt;A good technical question I have used in the past is write a paragraph explaining DHCP. This question illustrates what their knowledge is like for an essential technology, but it also indicates what their writing style is like. Could the passage they have written be given to a Director or Client?&lt;/p&gt;
&lt;p&gt;Good IT people need both technical knowledge and the ability to communicate at all levels, I still struggle to know if someone is good or not and even sometimes if I am any good.&lt;/p&gt;</description></item><item><title>Boldly go where no SQL has gone, 2</title><link>https://blog-test.funkysi1701.com/posts/2014/to-boldly-go-where-no-sql-has-gone-before-part-2/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Tue, 21 Oct 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/to-boldly-go-where-no-sql-has-gone-before-part-2/</guid><category term="StarTrek">StarTrek</category><category term="SQL">SQL</category><category term="Database">Database</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/10/c285ab50-86a9-44c3-a0ce-d790acae7db1.jpg"/><description>&lt;p&gt;Let’s continue looking at a database schema for storing details of every Star Trek Episode. If you are new to databases, a schema is just the design of the structure of the database.&lt;/p&gt;
&lt;p&gt;We have three tables, Episode, EpisodeWriter and Writer. See my last post for more details of these. It has been suggested that a slight change to this structure would enable storage of more of the creative staff.&lt;/p&gt;
&lt;p&gt;Lets rename Writer and call it Credit, and rename EpisodeWriter and call it EpisodeCredit. Now any creative staff member involved in an episode can be stored in the Credit table. Lets alter EpisodeCredit and add an extra column called CreditType. CreditType is just a text field that stores the role that creative person had on that episode, it can be anything from Director, Writer, Actor, Science Consultant etc.&lt;/p&gt;
&lt;p&gt;We now have the ability to store information relating to the episode in the episode table and any creative people in the credit table. What else can we add to the database? How about a table that can be used to record when an episode was last watched. I am probably weird but sometimes I want to watch a Star Trek episode that I like but I haven’t watched in ages.&lt;/p&gt;
&lt;p&gt;The last watched table is really simple and just have a datetime field and episodeId. This can be further expanded to have a userId field if you wanted to keep track of what episodes your friends had been watching.&lt;/p&gt;
&lt;p&gt;Another idea could be to tag episodes with certain themes or topics like Klingon episodes or meaning of life episodes or Kirk talks a computer to death episodes. Again this is fairly simple table containing TagName and EpisodeId.&lt;/p&gt;</description></item><item><title>Beyond SQL: to boldly go further</title><link>https://blog-test.funkysi1701.com/posts/2014/to-boldly-go-where-no-sql-has-gone-before/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 12 Oct 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/to-boldly-go-where-no-sql-has-gone-before/</guid><category term="StarTrek">StarTrek</category><category term="SQL">SQL</category><category term="Database">Database</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/10/enterprise.jpg"/><description>&lt;p&gt;My last post proved quite popular so I am wondering if I can combine a post about IT and Star Trek.&lt;/p&gt;
&lt;p&gt;Years ago I used to have lists of Star Trek episodes, which included such information like original air date, production number, episode title and brief description.&lt;/p&gt;
&lt;p&gt;One thing that was hard to keep track of was how many episodes were written by a specific person. This is because episodes are written by multiple people. A column called writer would then need to contain multiple people, another option would be to have columns called writer1, writer2 etc. This wouldn’t help either as you wouldn’t know which column a specific writer had been saved in.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Database diagram showing a many-to-many relationship between episodes and writers" src="https://blog-test.funkysi1701.com/images/2014/10/manytomany.jpg" loading="lazy"
width="559" height="334"
/&gt;
&lt;/p&gt;
&lt;p&gt;The relationship between writer and episode is known as a many to many relationship. An episode can have many writers and a writer can have written many episodes. To achieve this structure in a SQL database you will need three database tables as it is not possible to create a many to many join between two tables. The first table will contain all the episodes, the second table will contain all the writers, the third table known as a junction table, will contain the relationship between the two.&lt;/p&gt;
&lt;p&gt;Let’s do an example so we can see how this would work. Gene Roddenberry creator of Star Trek wrote the pilot episode ‘The Cage’. So Gene would be added to the writers table with an id of 1 and The Cage would be added to the episode table with an id of 1. In the junction table, it has two columns episode and writer, so we would enter 1 and 1 into these columns.&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; Episode e
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Join&lt;/span&gt; EpisodeWriter ew &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; e.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ew.EpisodeId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;Join&lt;/span&gt; Writer w &lt;span style="color:#66d9ef"&gt;on&lt;/span&gt; w.id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ew.WriterId
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But if Gene Coon and Gene Roddenberry had writing credits on The Cage we would need to add Gene Coon to the writing table and add an extra entry to the episodewriter table.&lt;/p&gt;
&lt;p&gt;I am going to do more posts based on this as I expand the database structure to include other information, I may go on to create stored procedures for bringing back certain information or I may use this as an example to talk about coding a user interface.&lt;/p&gt;</description></item><item><title>Destination Star Trek</title><link>https://blog-test.funkysi1701.com/posts/2014/destination-star-trek/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sun, 05 Oct 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/destination-star-trek/</guid><category term="StarTrek">StarTrek</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/DST3_Logo.jpg"/><description>&lt;p&gt;As a break from my usual topics I am going to talk about what I did over the weekend.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Simon and Laura in Star Trek costume at Destination Star Trek" src="https://blog-test.funkysi1701.com/images/2014/10670061_10152884492389155_77781042960777157_n.jpg" loading="lazy"
width="360" height="640"
/&gt;
&lt;/p&gt;
&lt;p&gt;I am a huge star trek fan, so me and my wife Laura went to Destination Star Trek, a convention held in London. This is a picture of us in costume, my wife created a tribble costume (A tribble is an alien race that just consists of a ball of fur) and I am wearing an original series captains uniform. We had a great time.&lt;/p&gt;
&lt;p&gt;There are several things that made this trip special.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Friends&lt;/strong&gt;: After the last convention I remember thinking how much better the convention would be with a group of friends. Shortly afterwards I started listening to the trekmate podcast, eventually this lead to me helping out with their website and making friends via twitter with many of the hosts. This weekend was the first time I met up with them and it was great to put faces to names (or twitter names)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writers and Directors&lt;/strong&gt;: Star Trek has a great philosophy. In the future human beings will put their differences aside and work together to explore the galaxy, this is one reason why Star Trek is so popular even after almost 50 years. This philosophy has been created by the writers and other creative staff over the years. My favourite Star Trek film is Wrath of Khan which was directed by Nicholas Meyer, this weekend I got my DVD signed by him and was able to tell him how I still enjoyed that film over 30 years after it was made. He said that he really appreciated me saying that. Listening to his talk later on, it was fascinating to hear his insights into making my favourite film. It is the writers and directors that make our favourite characters who they are, the actors themselves aren’t allowed to ad lib, all they do is flesh them out with a bit of emotion or a mannerism, it is the writer that create our favourite lines or situations that we remember.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seven of Nine&lt;/strong&gt;: During my teenage years I had lots of posters of Seven on my walls. Seven of Nine was the ex-borg that walked around the ship in a skin tight catsuit, but she was also highly intelligent and continued to explore what it was to be human. It was great to have my photo taken with her, even if it was rushed due to the large number of people that wanted their picture taken.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trivia&lt;/strong&gt;: On the Friday of the convention, Laura took part in the beginners trivia challenge, she won. On Saturday I took part in the intermediate trivia challenge, I did really badly only got 3 correct, On Sunday I took part in the captain level challenge and I won. I really wasn’t expecting that, after I did so badly the day before. Thanks Marc Stamper and Destination Star Trek for organising that it was great fun, and also fun to meet the other trekkies who I had been competing against via twitter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Party!&lt;/strong&gt;: On Saturday night we went to a party, we had Romulan Ale to drink, we had some of the actors performing songs (James Darren was particularly good), and some of the actors mingled with fans, it was great to see the actors relaxing and if you were lucky you could chat to them, I asked Vaughn Armstrong how he was enjoying the music, he loved it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is just a taste of what I got up to, there was lots more, like seeing alien costumes, listening to talks, sitting on a mockup of the bridge. Only one way to end this post, &lt;strong&gt;Live Long and Prosper!&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Windows 9 or do I mean 10</title><link>https://blog-test.funkysi1701.com/posts/2014/windows-9-or-do-i-mean-10/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 01 Oct 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/windows-9-or-do-i-mean-10/</guid><category term="Windows">Windows</category><category term="Microsoft">Microsoft</category><category term="ITAdmin">ITAdmin</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/10/windows_10_fullwidth.jpg"/><description>&lt;p&gt;Like many systems administrators I watched as the news came out yesterday about the latest version of windows. What would it be like? What would it be called? Would it be better or worse than previous versions?&lt;/p&gt;
&lt;p&gt;I was shocked when the name of the new operating system was revealed to be Windows 10. What really!? At first I though someone had tweeted a photoshopped image of the press conference, but no it was really going to be called Windows 10.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Windows 10" src="https://blog-test.funkysi1701.com/images/2014/10/windows_10_fullwidth.jpg" loading="lazy"
width="800" height="478"
/&gt;
&lt;/p&gt;
&lt;p&gt;Windows 10 is the next operating system to be released after windows 8, many had been calling it windows 9 or windows Threshold.&lt;/p&gt;
&lt;p&gt;Microsoft has never had a fixed naming convention for its OSes, so should we really be that surprised at its new name.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 1.0 (1985)&lt;/li&gt;
&lt;li&gt;Windows 2.0 (1987)&lt;/li&gt;
&lt;li&gt;Windows 3.0 (1990)&lt;/li&gt;
&lt;li&gt;Windows 95 (1995)&lt;/li&gt;
&lt;li&gt;Windows 98 (1998)&lt;/li&gt;
&lt;li&gt;Windows ME (2000)&lt;/li&gt;
&lt;li&gt;Windows XP (2001)&lt;/li&gt;
&lt;li&gt;Windows Vista (2007)&lt;/li&gt;
&lt;li&gt;Windows 7 (2009)&lt;/li&gt;
&lt;li&gt;Windows 8 (2012)&lt;/li&gt;
&lt;li&gt;Windows 10 (2015)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Windows 11 (2021)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One reason Microsoft may have gone with with Windows 10 is because they wanted to signify that the coming Windows release would be the last “major” Windows update. What does it mean to be the last major update?&lt;/p&gt;
&lt;p&gt;If you look at the list of OSes above you will see that between XP and Vista was a huge 6 years, this gap is/has caused a huge headache for IT professionals (me included). Software was written for XP because that is all that was available, when XP moved out of support earlier this year it caused loads as problems as people tried to get this software to work on more modern OSes.&lt;/p&gt;
&lt;p&gt;If windows 10 is around for a long time we may end up with a similar situation to XP, in that loads of software will run only on it and cause problems if you try and port it to whatever comes next. I am only a trainee developer so I don’t know what is involved with building an OS, but I would imagine there must be things that are very difficult or almost impossible to fix without ripping them out and starting again which is what happens when a new version of an OS is written.&lt;/p&gt;
&lt;p&gt;Only time will tell if Windows 10 really is the last version of windows and what will happen to the OS in the future. What ever the case I am downloading a preview so I can have a look (I want my start menu back!)&lt;/p&gt;</description></item><item><title>What is the difference: Dev vs Ops</title><link>https://blog-test.funkysi1701.com/posts/2014/what-is-the-difference-between-dev-and-ops/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Sat, 27 Sep 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/what-is-the-difference-between-dev-and-ops/</guid><category term="DevOps">DevOps</category><category term="Operations">Operations</category><category term="ITAdmin">ITAdmin</category><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/2014/09/DevOps-Cloud.jpg"/><description>&lt;p&gt;I want to learn Development and eventually move into a development role. But what is the difference between development and what I already do?&lt;/p&gt;
&lt;p&gt;Put simply Development or programming is the creation of new programs, websites or databases.&lt;/p&gt;
&lt;p&gt;IT Operations or System Administration is the administration of existing servers, websites or databases.&lt;/p&gt;
&lt;p&gt;I have been doing System Administration since I started my job back in 2006. What you do as part of this role can be very simple like setting up new users or computers to something very complex like upgrading the version of Exchange that the company uses for its emails.&lt;/p&gt;
&lt;p&gt;As part of my role I have done a lot of tasks that could be described as development. I have created databases and built new database structures like tables, views and stored procedures. I have also assisted the development department with testing, setting up visual studio, building websites and databases from code.&lt;/p&gt;
&lt;p&gt;Can I describe myself as a developer? I would say yes, I have done plenty of work that is development work.&lt;/p&gt;
&lt;p&gt;Can I get a job as a developer? Possibly but it would depend on the role. I have many of the skills that developers use, but I have limited knowledge in many areas. What I need to do is concentrate my efforts onto the development work I do and delegate as much administration work as I can so my knowledge can increase.&lt;/p&gt;
&lt;p&gt;A Buzz word in IT at the moment is DevOps. I have lost count of the number of times .NetRocks or RunAsRadio have mentioned it.&lt;/p&gt;
&lt;p&gt;DevOps is the integration of IT Development and Operations, it emphasises the need for the two departments to work closely together to achieve common goals. In big companies the two departments can pull against each other if you are not careful, but in my case as I do both roles, it would be very difficult for the development side of myself to blame the operations side of myself for a problem.&lt;/p&gt;
&lt;p&gt;This I think puts me in a good position, I just need to learn more development and I will make a valuable addition to someone’s development team.&lt;/p&gt;</description></item><item><title>I love Nagios</title><link>https://blog-test.funkysi1701.com/posts/2014/i-love-nagios/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Wed, 24 Sep 2014 20:00:45 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2014/i-love-nagios/</guid><category term="ITAdmin">ITAdmin</category><category term="Monitoring">Monitoring</category><category term="Servers">Servers</category><category term="Nagios">Nagios</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2014/nagios.png"/><description>&lt;p&gt;
&lt;img class="img-fluid" alt="Nagios" src="https://blog-test.funkysi1701.com/images/2014/nagios.png" loading="lazy"
width="212" height="50"
/&gt;
&lt;/p&gt;
&lt;p&gt;You may not have heard of Nagios but it has saved my bacon quite a few times.&lt;/p&gt;
&lt;p&gt;Nagios is an open source server monitoring application that runs on many linux flavours.&lt;/p&gt;
&lt;p&gt;I can’t remember exactly when I first installed nagios but I am guessing it was sometime in 2007/8. My boss gave me a book about it (which I never read) and told me to create a system to monitor the companies servers.&lt;/p&gt;
&lt;p&gt;Nagios is not simple to set up. It relies on setting up various Hosts and services. Hosts are usually physical servers that you want to monitor and services are all the services you want to monitor. As this is a linux program all these can be configured by editing the right config file&lt;/p&gt;
&lt;p&gt;Nagios is very flexible and can be expanded easily with the use of plugins, if you want to monitor something there is usually a plugin available. If you have a dell server running openmanage software there is even a plugin that allows the temperature of your server to be monitored.&lt;/p&gt;
&lt;p&gt;If you want to monitor windows servers the use of nsclient++ is a real advantage. This is a simple client that runs as a service on your windows server. This allows nagios to track memory, cpu, disk space, performance and services, in fact almost everything that you would want to monitor.&lt;/p&gt;
&lt;p&gt;Over the years I have kept a close eye on Nagios and added extra checks as new services were added or problems encountered. A few years ago I dabbled with sending alerts out via SMS message and once I got a smart phone found an app to keep track of Nagios 24/7.&lt;/p&gt;
&lt;p&gt;But recently I have started wondering if Nagios is the best way to monitor modern servers like 2012 or remote services like Azure. I want something that is easy to expand as your IT infrastructure expands. Something that relies on running on a linux OS requires your IT staff have a knowledge of linux and you keep that server maintained and updated.&lt;/p&gt;
&lt;p&gt;My question is: Is Nagios still the best way to monitor my servers?&lt;/p&gt;</description></item><item><title>About Me</title><link>https://blog-test.funkysi1701.com/about/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/about/</guid><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/1922276.jpg"/><description>&lt;img alt="Funky Si profile image" src="https://blog-test.funkysi1701.com/images/1922276.jpg" style="float: left; padding-right: 15px; height: 150px" /&gt;
&lt;h2 id="hey-im-simon-foster"&gt;Hey, I’m Simon Foster&lt;a class="anchor ms-1" href="#hey-im-simon-foster" aria-label="Permalink: Hey, I’m Simon Foster"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My online persona is &lt;strong&gt;Funky Si&lt;/strong&gt; — a nickname from university days that somehow stuck. I&amp;rsquo;m a full-stack developer passionate about building scalable, maintainable applications and robust DevOps practices.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;18+ years&lt;/strong&gt; in IT departments (since 2006), I&amp;rsquo;ve worn many hats: software developer, systems administrator, infrastructure engineer, database specialist, and DevOps advocate. My career has evolved from traditional ops work into modern cloud-native development, and I genuinely enjoy the intersection of development and infrastructure.&lt;/p&gt;
&lt;h3 id="what-i-do"&gt;What I Do&lt;a class="anchor ms-1" href="#what-i-do" aria-label="Permalink: What I Do"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I specialize in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backend Development&lt;/strong&gt;: .NET, C#, SQL Server, scalable API design&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud &amp;amp; DevOps&lt;/strong&gt;: Azure, AWS, Terraform, containerization (Docker/Kubernetes), CI/CD automation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture&lt;/strong&gt;: Designing systems that are secure, performant, and maintainable&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="certifications"&gt;Certifications&lt;a class="anchor ms-1" href="#certifications" aria-label="Permalink: Certifications"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.credly.com/badges/adacf718-d696-4254-a68d-5b32f720ac78/public_url" style="float:left; padding-right: 15px;"&gt;&lt;img src="https://blog-test.funkysi1701.com/images/azure.png" alt="Azure Fundamentals" width="150" /&gt;&lt;/a&gt;
&lt;a href="https://www.credly.com/badges/3aab54c8-a109-4018-bcad-dbe0d6a1fc0c/public_url" style="float:left;"&gt;&lt;img src="https://blog-test.funkysi1701.com/images/awscp.png" alt="AWS Cloud Practitioner" width="150" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div style="clear: both;"&gt;&lt;/div&gt;
&lt;h2 id="technology-stack"&gt;Technology Stack&lt;a class="anchor ms-1" href="#technology-stack" aria-label="Permalink: Technology Stack"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Organized by category:&lt;/p&gt;
&lt;h3 id="languages"&gt;Languages&lt;a class="anchor ms-1" href="#languages" aria-label="Permalink: Languages"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;C#&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;PowerShell&lt;/li&gt;
&lt;li&gt;SQL&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="frameworks--platforms"&gt;Frameworks &amp; Platforms&lt;a class="anchor ms-1" href="#frameworks--platforms" aria-label="Permalink: Frameworks &amp;amp; Platforms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;.NET (Framework &amp;amp; Core)&lt;/li&gt;
&lt;li&gt;Blazor&lt;/li&gt;
&lt;li&gt;ASP.NET&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="databases"&gt;Databases&lt;a class="anchor ms-1" href="#databases" aria-label="Permalink: Databases"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SQL Server&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cloud--infrastructure"&gt;Cloud &amp; Infrastructure&lt;a class="anchor ms-1" href="#cloud--infrastructure" aria-label="Permalink: Cloud &amp;amp; Infrastructure"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft Azure (AppService, Functions, DevOps, KeyVault)&lt;/li&gt;
&lt;li&gt;Amazon Web Services&lt;/li&gt;
&lt;li&gt;Terraform&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Kubernetes&lt;/li&gt;
&lt;li&gt;Helm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tools--services"&gt;Tools &amp; Services&lt;a class="anchor ms-1" href="#tools--services" aria-label="Permalink: Tools &amp;amp; Services"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;Azure DevOps&lt;/li&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;CI/CD pipelines&lt;/li&gt;
&lt;li&gt;And many more&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="featured-technologies--projects"&gt;Featured Technologies &amp; Projects&lt;a class="anchor ms-1" href="#featured-technologies--projects" aria-label="Permalink: Featured Technologies &amp;amp; Projects"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recent work and areas of focus:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kubernetes &amp;amp; Helm&lt;/strong&gt; - Orchestration and deployment automation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt; - Observability, logging, and distributed tracing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elasticsearch&lt;/strong&gt; - Search and analytics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Infrastructure&lt;/strong&gt; - AppService, Functions, DevOps, networking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure as Code&lt;/strong&gt; - Terraform, ARM templates, Helm charts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI/CD Pipelines&lt;/strong&gt; - GitHub Actions, Azure Pipelines&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI &amp;amp; Machine Learning&lt;/strong&gt; - Exploring applications in modern development&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="community"&gt;Community&lt;a class="anchor ms-1" href="#community" aria-label="Permalink: Community"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m passionate about sharing knowledge with the tech community:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blogger&lt;/strong&gt; - 11+ years of writing about technology, DevOps practices, cloud architecture, and professional development on my blog&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tech Enthusiast&lt;/strong&gt; - Continuously learning and exploring emerging technologies like AI, Kubernetes, and observability&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="blog--writing"&gt;Blog &amp; Writing&lt;a class="anchor ms-1" href="#blog--writing" aria-label="Permalink: Blog &amp;amp; Writing"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I regularly write about topics including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloud architecture and infrastructure as code&lt;/li&gt;
&lt;li&gt;.NET and C# development best practices&lt;/li&gt;
&lt;li&gt;DevOps tooling and automation&lt;/li&gt;
&lt;li&gt;Azure services and cloud deployment patterns&lt;/li&gt;
&lt;li&gt;Kubernetes and container orchestration&lt;/li&gt;
&lt;li&gt;Observability, monitoring, and logging&lt;/li&gt;
&lt;li&gt;Professional development and career growth&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;New here? &lt;a href="https://blog-test.funkysi1701.com/start-here/"&gt;Start with these recommended posts&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="connect-with-me"&gt;Connect With Me&lt;a class="anchor ms-1" href="#connect-with-me" aria-label="Permalink: Connect With Me"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Want to collaborate, chat about tech, or discuss DevOps and cloud architecture? Connect with me on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt; - &lt;a href="https://github.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Twitter/X&lt;/strong&gt; - &lt;a href="https://twitter.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BlueSky&lt;/strong&gt; - &lt;a href="https://bsky.app/profile/funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mastodon&lt;/strong&gt; - &lt;a href="https://hachyderm.io/@funkysi1701" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt; - &lt;a href="https://linkedin.com/in/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Facebook&lt;/strong&gt; - &lt;a href="https://www.facebook.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blog&lt;/strong&gt; - Explore my latest posts and articles here on this site&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to reach out with questions, collaboration opportunities, or just to chat about technology!&lt;/p&gt;
&lt;h2 id="recommendations"&gt;Recommendations&lt;a class="anchor ms-1" href="#recommendations" aria-label="Permalink: Recommendations"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Simon is an excellent developer, always looking for new methods and technology to improve existing solutions, along with his own skills. He is open to new ideas, though not afraid to share his thoughts and feedback and guide others to the best solution possible. It’s worth noting that Simon has vast knowledge on hardware and infrastructure which really does compliment his skill as a developer.&lt;/em&gt; - Alasdair Thomson (Head of Business Data Solutions at NPD Travel Retail)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Simon worked for my company for a number of years and was a very valued member of staff, and later on management. He is an intelligent and conscientious worker who gives over and above on a regular basis. He leads by example and was respected by his peers and the directors of the company. I would not hesitate to recommend Simon both in terms of the quality of his work and his ethics and values in life in general.&lt;/em&gt; - Alison Davies (CEO at Eurosafe UK)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you want a developer who really understands DevOps, then Si is your man. With a mixture of operations, support, development and management experience, he can bring a balanced skillset to a team, as well as excellent knowledge of Azure, .NET, SQL and the web.&lt;/em&gt; - Keith Williams (Development Manager at IRIS for Cascade HR and KashFlow Payroll)&lt;/p&gt;</description></item><item><title>Contact</title><link>https://blog-test.funkysi1701.com/contact/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/contact/</guid><description>&lt;h2 id="get-in-touch"&gt;Get In Touch&lt;a class="anchor ms-1" href="#get-in-touch" aria-label="Permalink: Get In Touch"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;d love to hear from you! Whether you have a question about my blog posts or want to discuss a potential collaboration, feel free to reach out.&lt;/p&gt;
&lt;h3 id="email"&gt;Email&lt;a class="anchor ms-1" href="#email" aria-label="Permalink: Email"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can contact me directly at: &lt;strong&gt;&lt;a href="mailto:funkysi1701@gmail.com"&gt;funkysi1701@gmail.com&lt;/a&gt;
&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="social-media"&gt;Social Media&lt;a class="anchor ms-1" href="#social-media" aria-label="Permalink: Social Media"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Connect with me on social media:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt; - &lt;a href="https://github.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Twitter/X&lt;/strong&gt; - &lt;a href="https://twitter.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BlueSky&lt;/strong&gt; - &lt;a href="https://bsky.app/profile/funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mastodon&lt;/strong&gt; - &lt;a href="https://hachyderm.io/@funkysi1701" target="_blank" rel="noopener noreferrer"&gt;@funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt; - &lt;a href="https://linkedin.com/in/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Facebook&lt;/strong&gt; - &lt;a href="https://www.facebook.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;funkysi1701&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="what-i-can-help-with"&gt;What I Can Help With&lt;a class="anchor ms-1" href="#what-i-can-help-with" aria-label="Permalink: What I Can Help With"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Technical Writing&lt;/strong&gt;: Guest posts and technical content&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaboration&lt;/strong&gt;: Open source projects and community initiatives&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="newsletter"&gt;Newsletter&lt;a class="anchor ms-1" href="#newsletter" aria-label="Permalink: Newsletter"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Want to stay updated with my latest posts and insights? &lt;a href="https://blog-test.funkysi1701.com/newsletter"&gt;Subscribe to my newsletter&lt;/a&gt;
.&lt;/p&gt;
&lt;h3 id="support-my-work"&gt;Support My Work&lt;a class="anchor ms-1" href="#support-my-work" aria-label="Permalink: Support My Work"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you find my content helpful, consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://buymeacoffee.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;Buy Me a Coffee&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sponsors/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;GitHub Sponsor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Check out my &lt;a href="https://blog-test.funkysi1701.com/tools-and-resources"&gt;Tools &amp;amp; Resources&lt;/a&gt;
which includes referral links&lt;/li&gt;
&lt;li&gt;Sharing my posts with your network&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you for reaching out! I look forward to connecting with you.&lt;/p&gt;</description></item><item><title>Funky Si: The Next Generation</title><link>https://blog-test.funkysi1701.com/funky-si-the-next-generation/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/funky-si-the-next-generation/</guid><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/james5.jpg"/><description>&lt;p&gt;On 19th August at 9.39 pm James David Martin Foster arrived weighing 9 lb 12.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Newborn James David Martin Foster" src="https://blog-test.funkysi1701.com/images/james5.jpg" loading="lazy"
width="1080" height="810"
/&gt;
&lt;img class="img-fluid" alt="James as a baby" src="https://blog-test.funkysi1701.com/images/20150827_134624-e1442143961495.jpg" loading="lazy"
width="5312" height="2988"
/&gt;
&lt;img class="img-fluid" alt="Baby James" src="https://blog-test.funkysi1701.com/images/James.jpg" loading="lazy"
width="960" height="528"
/&gt;
&lt;img class="img-fluid" alt="James sleeping as a newborn" src="https://blog-test.funkysi1701.com/images/SAM_4939.jpg" loading="lazy"
width="4320" height="3240"
/&gt;
&lt;img class="img-fluid" alt="James as a baby, shared on social media" src="https://blog-test.funkysi1701.com/images/COogcqtXAAAzZ7A.jpg" loading="lazy"
width="600" height="600"
/&gt;
&lt;img class="img-fluid" alt="James as a baby" src="https://blog-test.funkysi1701.com/images/COZF5PjWUAAhcan.jpg" loading="lazy"
width="600" height="600"
/&gt;
&lt;/p&gt;
&lt;p&gt;My initial thoughts on fatherhood can be found &lt;a href="https://www.funkysi1701.com/posts/2015/baby-magic-and-becoming-a-father/" target="_blank" rel="noopener noreferrer"&gt;here&lt;/a&gt;
. More baby photos can also be found on my &lt;a href="https://www.instagram.com/funkysi1701/" target="_blank" rel="noopener noreferrer"&gt;instragram&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Baby James photo shared on Twitter" src="https://blog-test.funkysi1701.com/images/twitter.jpg" loading="lazy"
width="1500" height="500"
/&gt;
&lt;/p&gt;
&lt;p&gt;On 11th November 2017 at 22:58pm Edward Leonard Alan Foster arrived weighing 11 lb&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Newborn Edward Leonard Alan Foster" src="https://blog-test.funkysi1701.com/images/DSC_0376-e1510563039193.jpg" loading="lazy"
width="4140" height="5520"
/&gt;
&lt;/p&gt;</description></item><item><title>My Podcasts</title><link>https://blog-test.funkysi1701.com/podcasts/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/podcasts/</guid><description>&lt;p&gt;A list of podcasts I have recorded, mostly about Star Trek.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://trekranks.libsyn.com/trekranks-233-top-5-mediocre-episodes-ii" target="_blank" rel="noopener noreferrer"&gt;TrekRanks #233&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/trekranks/"&gt;TrekRanks #174&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2023/picard-season-three/"&gt;Picard Season 3&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2022/temporal-trek-podcast/"&gt;Temporal Trek Podcast&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2016/brothers-tng-s4-e3-review-battle-bridge/"&gt;Brothers, TNG S4 E3 Review, The Battle Bridge&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2015/star-trek-is-back-in-2017/"&gt;Star Trek is back (in 2017)&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2015/the-hunted-tng-s3-e11-the-battle-bridge/"&gt;The Hunted, TNG S3 E11, The Battle Bridge&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2015/upper-pylon-2-1-x-09-the-passenger/"&gt;Upper Pylon 2 – 1 x 09: The Passenger&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2015/ten-forward-episode-135-anti-firbob-is-back-or-simons-desert-island-trek/"&gt;Ten Forward Episode #135 – Anti Firbob is Back or Simon’s Desert Island Trek&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Newsletter</title><link>https://blog-test.funkysi1701.com/newsletter/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/newsletter/</guid><media:content medium="image" type="image/jpeg" url="https://blog-test.funkysi1701.com/images/1922276.jpg"/><description>&lt;h2 id="-join-my-newsletter"&gt;📬 Join My Newsletter&lt;a class="anchor ms-1" href="#-join-my-newsletter" aria-label="Permalink: 📬 Join My Newsletter"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Welcome! I send out a &lt;strong&gt;monthly newsletter&lt;/strong&gt; where I share:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🔧 &lt;strong&gt;Practical tutorials&lt;/strong&gt; and code examples (like my Semantic Kernel series)&lt;/li&gt;
&lt;li&gt;☁️ &lt;strong&gt;DevOps &amp;amp; Cloud insights&lt;/strong&gt; - Azure, AWS, Docker, Kubernetes tips&lt;/li&gt;
&lt;li&gt;📚 &lt;strong&gt;What I&amp;rsquo;m learning&lt;/strong&gt; - honest takes on new technologies and tools&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Curated resources&lt;/strong&gt; - the best articles, tools, and talks I&amp;rsquo;ve found&lt;/li&gt;
&lt;li&gt;💭 &lt;strong&gt;Behind-the-scenes&lt;/strong&gt; - lessons learned from real projects&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="what-makes-this-newsletter-different"&gt;What Makes This Newsletter Different?&lt;a class="anchor ms-1" href="#what-makes-this-newsletter-different" aria-label="Permalink: What Makes This Newsletter Different?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;No fluff.&lt;/strong&gt; I write about what I&amp;rsquo;m actually building and learning, not rehashing press releases. You&amp;rsquo;ll get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Honest opinions (including when things don&amp;rsquo;t work)&lt;/li&gt;
&lt;li&gt;Focus on practical value over hype&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="who-should-subscribe"&gt;Who Should Subscribe?&lt;a class="anchor ms-1" href="#who-should-subscribe" aria-label="Permalink: Who Should Subscribe?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This newsletter is perfect for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;.NET developers&lt;/strong&gt; exploring cloud-native development&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DevOps engineers&lt;/strong&gt; working with Azure or AWS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full-stack developers&lt;/strong&gt; interested in backend architecture&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anyone curious&lt;/strong&gt; about modern software engineering practices&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="recent-topics"&gt;Recent Topics&lt;a class="anchor ms-1" href="#recent-topics" aria-label="Permalink: Recent Topics"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s what I&amp;rsquo;ve been writing about lately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Building AI-powered applications with Semantic Kernel and .NET&lt;/li&gt;
&lt;li&gt;Azure cost optimization strategies&lt;/li&gt;
&lt;li&gt;CI/CD pipeline best practices&lt;/li&gt;
&lt;li&gt;Docker and Kubernetes deployment patterns&lt;/li&gt;
&lt;li&gt;Database performance tuning&lt;/li&gt;
&lt;li&gt;Open-source tools worth exploring&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="privacy-promise"&gt;Privacy Promise&lt;a class="anchor ms-1" href="#privacy-promise" aria-label="Permalink: Privacy Promise"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;📧 &lt;strong&gt;Your email stays private&lt;/strong&gt; - I never share or sell your information&lt;/li&gt;
&lt;li&gt;🚫 &lt;strong&gt;No spam&lt;/strong&gt; - One email per month, that&amp;rsquo;s it&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Unsubscribe anytime&lt;/strong&gt; - One click, no questions asked&lt;/li&gt;
&lt;li&gt;🎯 &lt;strong&gt;Relevant content only&lt;/strong&gt; - I respect your inbox&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="view-latest-newsletter"&gt;View Latest Newsletter&lt;a class="anchor ms-1" href="#view-latest-newsletter" aria-label="Permalink: View Latest Newsletter"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://us11.campaign-archive.com/?u=110e046407cf8a34c93d56a4c&amp;amp;id=f19213fe61" target="_blank" rel="noopener noreferrer"&gt;April 2026&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://us11.campaign-archive.com/?u=110e046407cf8a34c93d56a4c&amp;amp;id=b64f934e95" target="_blank" rel="noopener noreferrer"&gt;May 2026&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://us11.campaign-archive.com/?u=110e046407cf8a34c93d56a4c&amp;amp;id=33bd290164" target="_blank" rel="noopener noreferrer"&gt;June 2026&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="-ready-to-join"&gt;🎯 Ready to Join?&lt;a class="anchor ms-1" href="#-ready-to-join" aria-label="Permalink: 🎯 Ready to Join?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Get practical software development insights delivered to your inbox every month.&lt;/p&gt;
&lt;div style="text-align: center; margin: 40px 0;"&gt;
&lt;a href="https://funkysi1701.us11.list-manage.com/subscribe?u=110e046407cf8a34c93d56a4c&amp;id=024966b02e"
style="background-color: #0066cc; color: white; padding: 15px 30px; text-decoration: none; border-radius: 5px; font-size: 18px; font-weight: bold; display: inline-block;"&gt;
📬 Subscribe Now
&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Free forever.&lt;/strong&gt; Unsubscribe anytime.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="have-questions"&gt;Have Questions?&lt;a class="anchor ms-1" href="#have-questions" aria-label="Permalink: Have Questions?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Feel free to &lt;a href="https://blog-test.funkysi1701.com/contact/"&gt;contact me&lt;/a&gt;
if you have any questions about the newsletter or want to suggest topics you&amp;rsquo;d like to see covered!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Thank you for your interest in my newsletter. I&amp;rsquo;m excited to share my development journey with you!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;— Simon (Funky Si)&lt;/p&gt;</description></item><item><title>Privacy Policy</title><link>https://blog-test.funkysi1701.com/privacy-policy/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/privacy-policy/</guid><description>&lt;h2&gt;Privacy Policy&lt;/h2&gt;
&lt;p&gt;Last updated: March 31, 2022&lt;/p&gt;
&lt;p&gt;This Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your information when You use the Service and tells You about Your privacy rights and how the law protects You.&lt;/p&gt;
&lt;p&gt;We use Your Personal data to provide and improve the Service. By using the Service, You agree to the collection and use of information in accordance with this Privacy Policy. This Privacy Policy has been created with the help of the &lt;a href="https://www.freeprivacypolicy.com/blog/sample-privacy-policy-template/" target="_blank"&gt;Privacy Policy Template&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Interpretation and Definitions&lt;/h2&gt;
&lt;h3&gt;Interpretation&lt;/h3&gt;
&lt;p&gt;The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.&lt;/p&gt;
&lt;h3&gt;Definitions&lt;/h3&gt;
&lt;p&gt;For the purposes of this Privacy Policy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Account&lt;/strong&gt; means a unique account created for You to access our Service or parts of our Service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Company&lt;/strong&gt; (referred to as either &amp;quot;the Company&amp;quot;, &amp;quot;We&amp;quot;, &amp;quot;Us&amp;quot; or &amp;quot;Our&amp;quot; in this Agreement) refers to Funky Si's Blog.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cookies&lt;/strong&gt; are small files that are placed on Your computer, mobile device or any other device by a website, containing the details of Your browsing history on that website among its many uses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Country&lt;/strong&gt; refers to: United Kingdom&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Device&lt;/strong&gt; means any device that can access the Service such as a computer, a cellphone or a digital tablet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Personal Data&lt;/strong&gt; is any information that relates to an identified or identifiable individual.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Service&lt;/strong&gt; refers to the Website.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Service Provider&lt;/strong&gt; means any natural or legal person who processes the data on behalf of the Company. It refers to third-party companies or individuals employed by the Company to facilitate the Service, to provide the Service on behalf of the Company, to perform services related to the Service or to assist the Company in analyzing how the Service is used.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Usage Data&lt;/strong&gt; refers to data collected automatically, either generated by the use of the Service or from the Service infrastructure itself (for example, the duration of a page visit).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Website&lt;/strong&gt; refers to Funky Si's Blog, accessible from &lt;a href="https://www.funkysi1701.com" rel="external nofollow noopener" target="_blank"&gt;https://www.funkysi1701.com&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt; means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Collecting and Using Your Personal Data&lt;/h2&gt;
&lt;h3&gt;Types of Data Collected&lt;/h3&gt;
&lt;h4&gt;Personal Data&lt;/h4&gt;
&lt;p&gt;While using Our Service, We may ask You to provide Us with certain personally identifiable information that can be used to contact or identify You. Personally identifiable information may include, but is not limited to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Email address&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;First name and last name&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Usage Data&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Usage Data&lt;/h4&gt;
&lt;p&gt;Usage Data is collected automatically when using the Service.&lt;/p&gt;
&lt;p&gt;Usage Data may include information such as Your Device's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that You visit, the time and date of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data.&lt;/p&gt;
&lt;p&gt;When You access the Service by or through a mobile device, We may collect certain information automatically, including, but not limited to, the type of mobile device You use, Your mobile device unique ID, the IP address of Your mobile device, Your mobile operating system, the type of mobile Internet browser You use, unique device identifiers and other diagnostic data.&lt;/p&gt;
&lt;p&gt;We may also collect information that Your browser sends whenever You visit our Service or when You access the Service by or through a mobile device.&lt;/p&gt;
&lt;h4&gt;Tracking Technologies and Cookies&lt;/h4&gt;
&lt;p&gt;We use Cookies and similar tracking technologies to track the activity on Our Service and store certain information. Tracking technologies used are beacons, tags, and scripts to collect and track information and to improve and analyze Our Service. The technologies We use may include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cookies or Browser Cookies.&lt;/strong&gt; A cookie is a small file placed on Your Device. You can instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do not accept Cookies, You may not be able to use some parts of our Service. Unless you have adjusted Your browser setting so that it will refuse Cookies, our Service may use Cookies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flash Cookies.&lt;/strong&gt; Certain features of our Service may use local stored objects (or Flash Cookies) to collect and store information about Your preferences or Your activity on our Service. Flash Cookies are not managed by the same browser settings as those used for Browser Cookies. For more information on how You can delete Flash Cookies, please read &amp;quot;Where can I change the settings for disabling, or deleting local shared objects?&amp;quot; available at &lt;a href="https://helpx.adobe.com/flash-player/kb/disable-local-shared-objects-flash.html#main_Where_can_I_change_the_settings_for_disabling__or_deleting_local_shared_objects_" rel="external nofollow noopener" target="_blank"&gt;https://helpx.adobe.com/flash-player/kb/disable-local-shared-objects-flash.html#main_Where_can_I_change_the_settings_for_disabling__or_deleting_local_shared_objects_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web Beacons.&lt;/strong&gt; Certain sections of our Service and our emails may contain small electronic files known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that permit the Company, for example, to count users who have visited those pages or opened an email and for other related website statistics (for example, recording the popularity of a certain section and verifying system and server integrity).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cookies can be &amp;quot;Persistent&amp;quot; or &amp;quot;Session&amp;quot; Cookies. Persistent Cookies remain on Your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close Your web browser. Learn more about cookies: &lt;a href="https://www.freeprivacypolicy.com/blog/sample-privacy-policy-template/#Use_Of_Cookies_And_Tracking" target="_blank"&gt;Use of Cookies by Free Privacy Policy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We use both Session and Persistent Cookies for the purposes set out below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Necessary / Essential Cookies&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Type: Session Cookies&lt;/p&gt;
&lt;p&gt;Administered by: Us&lt;/p&gt;
&lt;p&gt;Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cookies Policy / Notice Acceptance Cookies&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Type: Persistent Cookies&lt;/p&gt;
&lt;p&gt;Administered by: Us&lt;/p&gt;
&lt;p&gt;Purpose: These Cookies identify if users have accepted the use of cookies on the Website.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Functionality Cookies&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Type: Persistent Cookies&lt;/p&gt;
&lt;p&gt;Administered by: Us&lt;/p&gt;
&lt;p&gt;Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more information about the cookies we use and your choices regarding cookies, please visit our Cookies Policy or the Cookies section of our Privacy Policy.&lt;/p&gt;
&lt;h3&gt;Use of Your Personal Data&lt;/h3&gt;
&lt;p&gt;The Company may use Personal Data for the following purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;To provide and maintain our Service&lt;/strong&gt;, including to monitor the usage of our Service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;To manage Your Account:&lt;/strong&gt; to manage Your registration as a user of the Service. The Personal Data You provide can give You access to different functionalities of the Service that are available to You as a registered user.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;For the performance of a contract:&lt;/strong&gt; the development, compliance and undertaking of the purchase contract for the products, items or services You have purchased or of any other contract with Us through the Service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;To contact You:&lt;/strong&gt; To contact You by email, telephone calls, SMS, or other equivalent forms of electronic communication, such as a mobile application's push notifications regarding updates or informative communications related to the functionalities, products or contracted services, including the security updates, when necessary or reasonable for their implementation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;To provide You&lt;/strong&gt; with news, special offers and general information about other goods, services and events which we offer that are similar to those that you have already purchased or enquired about unless You have opted not to receive such information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;To manage Your requests:&lt;/strong&gt; To attend and manage Your requests to Us.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;For business transfers:&lt;/strong&gt; We may use Your information to evaluate or conduct a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which Personal Data held by Us about our Service users is among the assets transferred.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;For other purposes&lt;/strong&gt;: We may use Your information for other purposes, such as data analysis, identifying usage trends, determining the effectiveness of our promotional campaigns and to evaluate and improve our Service, products, services, marketing and your experience.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We may share Your personal information in the following situations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;With Service Providers:&lt;/strong&gt; We may share Your personal information with Service Providers to monitor and analyze the use of our Service, to contact You.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For business transfers:&lt;/strong&gt; We may share or transfer Your personal information in connection with, or during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a portion of Our business to another company.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;With Affiliates:&lt;/strong&gt; We may share Your information with Our affiliates, in which case we will require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and any other subsidiaries, joint venture partners or other companies that We control or that are under common control with Us.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;With business partners:&lt;/strong&gt; We may share Your information with Our business partners to offer You certain products, services or promotions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;With other users:&lt;/strong&gt; when You share personal information or otherwise interact in the public areas with other users, such information may be viewed by all users and may be publicly distributed outside.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;With Your consent&lt;/strong&gt;: We may disclose Your personal information for any other purpose with Your consent.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Retention of Your Personal Data&lt;/h3&gt;
&lt;p&gt;The Company will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example, if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal agreements and policies.&lt;/p&gt;
&lt;p&gt;The Company will also retain Usage Data for internal analysis purposes. Usage Data is generally retained for a shorter period of time, except when this data is used to strengthen the security or to improve the functionality of Our Service, or We are legally obligated to retain this data for longer time periods.&lt;/p&gt;
&lt;h3&gt;Transfer of Your Personal Data&lt;/h3&gt;
&lt;p&gt;Your information, including Personal Data, is processed at the Company's operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction.&lt;/p&gt;
&lt;p&gt;Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to that transfer.&lt;/p&gt;
&lt;p&gt;The Company will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of Your data and other personal information.&lt;/p&gt;
&lt;h3&gt;Disclosure of Your Personal Data&lt;/h3&gt;
&lt;h4&gt;Business Transactions&lt;/h4&gt;
&lt;p&gt;If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be transferred. We will provide notice before Your Personal Data is transferred and becomes subject to a different Privacy Policy.&lt;/p&gt;
&lt;h4&gt;Law enforcement&lt;/h4&gt;
&lt;p&gt;Under certain circumstances, the Company may be required to disclose Your Personal Data if required to do so by law or in response to valid requests by public authorities (e.g. a court or a government agency).&lt;/p&gt;
&lt;h4&gt;Other legal requirements&lt;/h4&gt;
&lt;p&gt;The Company may disclose Your Personal Data in the good faith belief that such action is necessary to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comply with a legal obligation&lt;/li&gt;
&lt;li&gt;Protect and defend the rights or property of the Company&lt;/li&gt;
&lt;li&gt;Prevent or investigate possible wrongdoing in connection with the Service&lt;/li&gt;
&lt;li&gt;Protect the personal safety of Users of the Service or the public&lt;/li&gt;
&lt;li&gt;Protect against legal liability&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Security of Your Personal Data&lt;/h3&gt;
&lt;p&gt;The security of Your Personal Data is important to Us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While We strive to use commercially acceptable means to protect Your Personal Data, We cannot guarantee its absolute security.&lt;/p&gt;
&lt;h2&gt;Children's Privacy&lt;/h2&gt;
&lt;p&gt;Our Service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from anyone under the age of 13. If You are a parent or guardian and You are aware that Your child has provided Us with Personal Data, please contact Us. If We become aware that We have collected Personal Data from anyone under the age of 13 without verification of parental consent, We take steps to remove that information from Our servers.&lt;/p&gt;
&lt;p&gt;If We need to rely on consent as a legal basis for processing Your information and Your country requires consent from a parent, We may require Your parent's consent before We collect and use that information.&lt;/p&gt;
&lt;h2&gt;Links to Other Websites&lt;/h2&gt;
&lt;p&gt;Our Service may contain links to other websites that are not operated by Us. If You click on a third party link, You will be directed to that third party's site. We strongly advise You to review the Privacy Policy of every site You visit.&lt;/p&gt;
&lt;p&gt;We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services.&lt;/p&gt;
&lt;h2&gt;Changes to this Privacy Policy&lt;/h2&gt;
&lt;p&gt;We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy Policy on this page.&lt;/p&gt;
&lt;p&gt;We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and update the &amp;quot;Last updated&amp;quot; date at the top of this Privacy Policy.&lt;/p&gt;
&lt;p&gt;You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page.&lt;/p&gt;
&lt;h2&gt;Contact Us&lt;/h2&gt;
&lt;p&gt;If you have any questions about this Privacy Policy, You can contact us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By email: funkysi1701@gmail.com&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Start Here</title><link>https://blog-test.funkysi1701.com/start-here/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/start-here/</guid><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2026/start-here.png"/><description>&lt;h2 id="new-here-start-with-these-posts"&gt;New here? Start with these posts&lt;a class="anchor ms-1" href="#new-here-start-with-these-posts" aria-label="Permalink: New here? Start with these posts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Welcome! If you are new to my blog, these are current pillars and popular evergreen articles to help you get started:&lt;/p&gt;
&lt;h3 id="cloud--modern-development"&gt;Cloud &amp; modern development&lt;a class="anchor ms-1" href="#cloud--modern-development" aria-label="Permalink: Cloud &amp;amp; modern development"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/aspire/"&gt;Getting started with Aspire&lt;/a&gt;
&lt;/strong&gt; — Microsoft&amp;rsquo;s opinionated stack for cloud-native .NET with built-in observability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/adding-elasticsearch-with-aspire/"&gt;Adding Elasticsearch with Aspire&lt;/a&gt;
&lt;/strong&gt; — Integrate search into .NET Aspire applications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/learning-kubernetes/"&gt;Learning Kubernetes&lt;/a&gt;
&lt;/strong&gt; — Container orchestration and deploying apps to clusters.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="net--development"&gt;.NET &amp; development&lt;a class="anchor ms-1" href="#net--development" aria-label="Permalink: .NET &amp;amp; development"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2026/dotnet-5-to-10-features/"&gt;.NET 5 to 10 features&lt;/a&gt;
&lt;/strong&gt; — A tour of the platform from .NET 5 through .NET 10 LTS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/whats-new-csharp/"&gt;What&amp;rsquo;s new with C#&lt;/a&gt;
&lt;/strong&gt; — Language features that shipped alongside recent runtimes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/blazor-and-dotnet10/"&gt;Blazor and .NET 10&lt;/a&gt;
&lt;/strong&gt; — Practical Blazor notes on the current LTS stack.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="devops-automation--visibility"&gt;DevOps, automation &amp; visibility&lt;a class="anchor ms-1" href="#devops-automation--visibility" aria-label="Permalink: DevOps, automation &amp;amp; visibility"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/merge-two-projects-into-one/"&gt;Merge two projects into one&lt;/a&gt;
&lt;/strong&gt; — Combine Git repositories without throwing away history.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2025/setting-up-grafana/"&gt;Setting up Grafana&lt;/a&gt;
&lt;/strong&gt; — Prometheus and dashboards for .NET metrics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2024/automatic-pull-requests/"&gt;Automatic pull requests&lt;/a&gt;
&lt;/strong&gt; — Promote branches with GitHub Actions or Azure DevOps.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/2026/stay-visible-as-a-developer-when-you-are-made-redundant/"&gt;Stay visible as a developer&lt;/a&gt;
&lt;/strong&gt; — Community, blogging, and side projects when the ground shifts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="explore-more"&gt;Explore more&lt;a class="anchor ms-1" href="#explore-more" aria-label="Permalink: Explore more"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/posts/"&gt;All Posts&lt;/a&gt;
— Complete archive of articles&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/tools-and-resources/"&gt;Tools &amp;amp; Resources&lt;/a&gt;
— Recommended development tools&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/projects/"&gt;Projects&lt;/a&gt;
— Side projects I have shipped&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/about/"&gt;About Me&lt;/a&gt;
— Background and experience&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog-test.funkysi1701.com/newsletter/"&gt;Newsletter&lt;/a&gt;
— Monthly updates by email&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stay-connected"&gt;Stay connected&lt;a class="anchor ms-1" href="#stay-connected" aria-label="Permalink: Stay connected"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Subscribe to my &lt;a href="https://blog-test.funkysi1701.com/newsletter/"&gt;newsletter&lt;/a&gt;
for updates&lt;/li&gt;
&lt;li&gt;Follow me on &lt;a href="https://twitter.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Check out my &lt;a href="https://github.com/funkysi1701" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Terms of Service &amp; Disclaimer</title><link>https://blog-test.funkysi1701.com/terms/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/terms/</guid><description>&lt;p&gt;&lt;strong&gt;Last Updated&lt;/strong&gt;: July 31, 2026&lt;/p&gt;
&lt;h2 id="terms-of-service"&gt;Terms of Service&lt;a class="anchor ms-1" href="#terms-of-service" aria-label="Permalink: Terms of Service"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Welcome to Funky Si&amp;rsquo;s Blog (&lt;a href="https://www.funkysi1701.com" target="_blank" rel="noopener noreferrer"&gt;www.funkysi1701.com&lt;/a&gt;
). By accessing and using this website, you accept and agree to be bound by the terms and provision of this agreement.&lt;/p&gt;
&lt;h3 id="use-of-website"&gt;Use of Website&lt;a class="anchor ms-1" href="#use-of-website" aria-label="Permalink: Use of Website"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This website and its content are provided for informational and educational purposes only. You may:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read and share blog posts&lt;/li&gt;
&lt;li&gt;Comment on posts (subject to moderation)&lt;/li&gt;
&lt;li&gt;Subscribe to the newsletter&lt;/li&gt;
&lt;li&gt;Use code examples in accordance with their specified licenses&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may not:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy or republish content without attribution&lt;/li&gt;
&lt;li&gt;Use automated tools to scrape content&lt;/li&gt;
&lt;li&gt;Post spam, malicious code, or inappropriate content in comments&lt;/li&gt;
&lt;li&gt;Impersonate the author or others&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="intellectual-property"&gt;Intellectual Property&lt;a class="anchor ms-1" href="#intellectual-property" aria-label="Permalink: Intellectual Property"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unless otherwise stated, all content on this website, including text, graphics, logos, and code examples, is the property of Simon Foster (Funky Si) and is protected by copyright laws.&lt;/p&gt;
&lt;p&gt;Code snippets and examples are generally provided for educational use. Where specific open-source licenses apply, they will be clearly stated.&lt;/p&gt;
&lt;h3 id="user-comments"&gt;User Comments&lt;a class="anchor ms-1" href="#user-comments" aria-label="Permalink: User Comments"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Comments on blog posts are welcome and encouraged. However, I reserve the right to moderate, edit, or delete comments that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Contain spam or promotional content&lt;/li&gt;
&lt;li&gt;Are abusive, threatening, or discriminatory&lt;/li&gt;
&lt;li&gt;Violate privacy or contain personal information&lt;/li&gt;
&lt;li&gt;Are off-topic or disruptive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By posting a comment, you grant me the right to use, modify, or remove that comment.&lt;/p&gt;
&lt;h3 id="changes-to-terms"&gt;Changes to Terms&lt;a class="anchor ms-1" href="#changes-to-terms" aria-label="Permalink: Changes to Terms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I reserve the right to update these terms at any time. Changes will be effective immediately upon posting to this page. Continued use of the website constitutes acceptance of updated terms.&lt;/p&gt;
&lt;h2 id="disclaimer"&gt;Disclaimer&lt;a class="anchor ms-1" href="#disclaimer" aria-label="Permalink: Disclaimer"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="no-professional-advice"&gt;No Professional Advice&lt;a class="anchor ms-1" href="#no-professional-advice" aria-label="Permalink: No Professional Advice"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The content on this blog represents my personal opinions and experiences. It is not intended as professional advice for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Legal matters&lt;/li&gt;
&lt;li&gt;Financial decisions&lt;/li&gt;
&lt;li&gt;Security implementations&lt;/li&gt;
&lt;li&gt;Production system deployments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Always consult qualified professionals for specific advice related to your situation.&lt;/p&gt;
&lt;h3 id="technical-content-accuracy"&gt;Technical Content Accuracy&lt;a class="anchor ms-1" href="#technical-content-accuracy" aria-label="Permalink: Technical Content Accuracy"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While I strive for accuracy in all technical posts and tutorials:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No Warranties&lt;/strong&gt;: Content is provided &amp;ldquo;as is&amp;rdquo; without warranties of any kind&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use at Your Own Risk&lt;/strong&gt;: Implementing code or configurations from this blog is done at your own risk&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test First&lt;/strong&gt;: Always test code and configurations in non-production environments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your Responsibility&lt;/strong&gt;: You are responsible for understanding and validating any code before use&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="external-links"&gt;External Links&lt;a class="anchor ms-1" href="#external-links" aria-label="Permalink: External Links"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This website contains links to external websites and resources. I am not responsible for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The content or privacy practices of external sites&lt;/li&gt;
&lt;li&gt;The availability or accuracy of external resources&lt;/li&gt;
&lt;li&gt;Any damages resulting from use of external links&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;External links are provided for convenience and do not constitute endorsement.&lt;/p&gt;
&lt;h3 id="affiliate-links--referrals"&gt;Affiliate Links &amp; Referrals&lt;a class="anchor ms-1" href="#affiliate-links--referrals" aria-label="Permalink: Affiliate Links &amp;amp; Referrals"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This website contains affiliate links and referral codes. This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I may receive compensation when you purchase through these links&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Extra Cost&lt;/strong&gt;: You pay the same price (or sometimes receive a discount)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Honest Recommendations&lt;/strong&gt;: I only recommend products and services I genuinely use or believe in&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transparency&lt;/strong&gt;: Affiliate relationships are disclosed where applicable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Current affiliate/referral programs include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Octopus Energy&lt;/li&gt;
&lt;li&gt;Monzo Bank&lt;/li&gt;
&lt;li&gt;Connect Fibre&lt;/li&gt;
&lt;li&gt;Mindful Chef&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="advertising"&gt;Advertising&lt;a class="anchor ms-1" href="#advertising" aria-label="Permalink: Advertising"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This website displays advertisements through Google AdSense and other advertising networks. Advertisers may use cookies and tracking technologies. See our &lt;a href="https://blog-test.funkysi1701.com/privacy-policy/"&gt;Privacy Policy&lt;/a&gt;
for more information.&lt;/p&gt;
&lt;h3 id="third-party-services"&gt;Third-Party Services&lt;a class="anchor ms-1" href="#third-party-services" aria-label="Permalink: Third-Party Services"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This website uses third-party services including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Giscus&lt;/strong&gt; for comments (hosted on GitHub)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lite Analytics&lt;/strong&gt; (via Cloudflare Zaraz) for engagement metrics such as bounce and page depth&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ahrefs Analytics&lt;/strong&gt; (via Cloudflare Zaraz) for SEO and referral insights&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare&lt;/strong&gt; for CDN, security, and Web Analytics (RUM)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Static Web Apps&lt;/strong&gt; for hosting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MailChimp&lt;/strong&gt; for newsletter management&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each service has its own terms and privacy policies.&lt;/p&gt;
&lt;h3 id="limitation-of-liability"&gt;Limitation of Liability&lt;a class="anchor ms-1" href="#limitation-of-liability" aria-label="Permalink: Limitation of Liability"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To the maximum extent permitted by law:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I am not liable for any direct, indirect, incidental, or consequential damages&lt;/li&gt;
&lt;li&gt;This includes damages from use of content, inability to use the website, or errors in content&lt;/li&gt;
&lt;li&gt;This limitation applies even if advised of the possibility of such damages&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="technical-issues"&gt;Technical Issues&lt;a class="anchor ms-1" href="#technical-issues" aria-label="Permalink: Technical Issues"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While I maintain this website to the best of my ability:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No Uptime Guarantee&lt;/strong&gt;: The website may be unavailable due to maintenance or technical issues&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content Changes&lt;/strong&gt;: Content may be updated, corrected, or removed without notice&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Data Loss Guarantee&lt;/strong&gt;: Comments or user-submitted content may be lost&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="governing-law"&gt;Governing Law&lt;a class="anchor ms-1" href="#governing-law" aria-label="Permalink: Governing Law"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These terms are governed by the laws of the United Kingdom. Any disputes will be subject to the exclusive jurisdiction of the courts of England and Wales.&lt;/p&gt;
&lt;h2 id="copyright-notice"&gt;Copyright Notice&lt;a class="anchor ms-1" href="#copyright-notice" aria-label="Permalink: Copyright Notice"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;© 2014-2025 Simon Foster (Funky Si). All rights reserved unless otherwise stated.&lt;/p&gt;
&lt;p&gt;Content may be shared with attribution and a link back to the original post. For republication requests, please &lt;a href="https://blog-test.funkysi1701.com/contact/"&gt;contact me&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="contact"&gt;Contact&lt;a class="anchor ms-1" href="#contact" aria-label="Permalink: Contact"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have questions about these terms, please &lt;a href="https://blog-test.funkysi1701.com/contact/"&gt;contact me&lt;/a&gt;
at &lt;a href="mailto:funkysi1701@gmail.com"&gt;funkysi1701@gmail.com&lt;/a&gt;
.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Fair Use Statement&lt;/strong&gt;: I believe in fair use, open knowledge sharing, and the developer community. If you want to reference, quote, or build upon my content, please do so respectfully with proper attribution.&lt;/p&gt;</description></item><item><title>Tools &amp; Resources</title><link>https://blog-test.funkysi1701.com/tools-and-resources/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/tools-and-resources/</guid><description>&lt;p&gt;I&amp;rsquo;m passionate about finding and using tools that improve my productivity and help me deliver better solutions. This page showcases products and resources I genuinely use and recommend. Some links below are Amazon affiliate links, which means I earn a small commission if you purchase through them at no extra cost to you.&lt;/p&gt;
&lt;h2 id="development--programming"&gt;Development &amp; Programming&lt;a class="anchor ms-1" href="#development--programming" aria-label="Permalink: Development &amp;amp; Programming"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Books and resources that have shaped my development practice:&lt;/p&gt;
&lt;h3 id="books"&gt;Books&lt;a class="anchor ms-1" href="#books" aria-label="Permalink: Books"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://amzn.to/4pihrvh" target="_blank" rel="noopener noreferrer"&gt;The Pragmatic Programmer: Your Journey to Mastery&lt;/a&gt;
&lt;/strong&gt; - Essential reading for any developer wanting to improve their craft and adopt best practices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://amzn.to/3MbtlbD" target="_blank" rel="noopener noreferrer"&gt;Clean Code: A Handbook of Agile Software Craftsmanship&lt;/a&gt;
&lt;/strong&gt; - Robert C. Martin&amp;rsquo;s guide to writing maintainable, professional code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://amzn.to/4pcQ2dU" target="_blank" rel="noopener noreferrer"&gt;The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win&lt;/a&gt;
&lt;/strong&gt; - Learn DevOps principles through an engaging narrative&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://amzn.to/4pdV6Pd" target="_blank" rel="noopener noreferrer"&gt;The DevOps Handbook&lt;/a&gt;
&lt;/strong&gt; - Comprehensive guide to implementing DevOps practices in your organization&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tools--ides"&gt;Tools &amp; IDEs&lt;a class="anchor ms-1" href="#tools--ides" aria-label="Permalink: Tools &amp;amp; IDEs"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visual Studio Professional&lt;/strong&gt; - Comprehensive IDE for .NET development&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Studio Code&lt;/strong&gt; - Lightweight, extensible code editor I use for web development and scripts&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cloud-platforms"&gt;Cloud Platforms&lt;a class="anchor ms-1" href="#cloud-platforms" aria-label="Permalink: Cloud Platforms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Azure&lt;/strong&gt; - My primary cloud platform for hosting and infrastructure&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Amazon Web Services (AWS)&lt;/strong&gt; - Secondary cloud platform for multi-cloud strategies&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="monitoring--observability"&gt;Monitoring &amp; Observability&lt;a class="anchor ms-1" href="#monitoring--observability" aria-label="Permalink: Monitoring &amp;amp; Observability"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Grafana&lt;/strong&gt; - Visualization and monitoring platform&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prometheus&lt;/strong&gt; - Metrics collection and alerting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt; - Standardized approach to observability&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="professional-development"&gt;Professional Development&lt;a class="anchor ms-1" href="#professional-development" aria-label="Permalink: Professional Development"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Resources for continuous learning and career growth:&lt;/p&gt;
&lt;h3 id="conferences"&gt;Conferences&lt;a class="anchor ms-1" href="#conferences" aria-label="Permalink: Conferences"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://ndclondon.com/" target="_blank" rel="noopener noreferrer"&gt;NDC London&lt;/a&gt;
&lt;/strong&gt; - Europe&amp;rsquo;s premier software development conference with world-class speakers and diverse tracks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.dddnorth.co.uk/" target="_blank" rel="noopener noreferrer"&gt;DDD North&lt;/a&gt;
&lt;/strong&gt; - My local DDD meetup hosted in Hull every year&lt;/li&gt;
&lt;li&gt;Local tech meetups and community events - Connect with fellow developers and stay current with trends&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="learning-platforms"&gt;Learning Platforms&lt;a class="anchor ms-1" href="#learning-platforms" aria-label="Permalink: Learning Platforms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pluralsight&lt;/strong&gt; - Comprehensive video courses for developers and IT professionals&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="affiliate--referral-programs"&gt;Affiliate &amp; Referral Programs&lt;a class="anchor ms-1" href="#affiliate--referral-programs" aria-label="Permalink: Affiliate &amp;amp; Referral Programs"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I also recommend several services I personally use.&lt;/p&gt;
&lt;h2 id="octopus-energy"&gt;Octopus Energy&lt;a class="anchor ms-1" href="#octopus-energy" aria-label="Permalink: Octopus Energy"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have been with Octopus Energy for a few years now and have been very happy with the service. They have a range of tariffs to suit your needs and are very competitive on price. If you sign up using my referral link we both get £50 credit on our accounts.&lt;/p&gt;
&lt;p&gt;I have also blogged about my experience with Octopus Energy &lt;a href="https://blog-test.funkysi1701.com/posts/2021/charting-my-energy-usage-with-the-octopus-energy-api/"&gt;here&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://share.octopus.energy/amber-eel-810" target="_blank" rel="noopener noreferrer"&gt;https://share.octopus.energy/amber-eel-810&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="monzo-bank"&gt;Monzo Bank&lt;a class="anchor ms-1" href="#monzo-bank" aria-label="Permalink: Monzo Bank"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have been using Monzo as my main bank account for a few years now and have been very happy with the service. They have a great app and are very competitive on price. If you sign up using my referral link we both get £5 credit on our accounts.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://join.monzo.com/c/74pdts4" target="_blank" rel="noopener noreferrer"&gt;https://join.monzo.com/c/74pdts4&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="connect-fibre"&gt;Connect Fibre&lt;a class="anchor ms-1" href="#connect-fibre" aria-label="Permalink: Connect Fibre"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I struggled with slow internet for a while, so as soon as Fibre was available in my area I signed up. I have been very happy with the service and the speed. If you sign up using my referral link we both get £60 credit on our accounts.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.connectfibre.co.uk/referral?referrer=11505401" target="_blank" rel="noopener noreferrer"&gt;https://www.connectfibre.co.uk/referral?referrer=11505401&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="mindful-chef"&gt;Mindful Chef&lt;a class="anchor ms-1" href="#mindful-chef" aria-label="Permalink: Mindful Chef"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My diet is not great, so I signed up to Mindful Chef to get healthy meals delivered to my door. At first glance it looks expensive, but if you compare it to a takeaway, it is a similar price and with Mindful Chef you get a few healthy meals to cook, and no guilt that you have been naughty again! If you sign up using my referral link you will get 25% off your first four boxes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.mindfulchef.com/ref-F1E4A7" target="_blank" rel="noopener noreferrer"&gt;https://www.mindfulchef.com/ref-F1E4A7&lt;/a&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Disclosure&lt;/strong&gt;: This page contains affiliate links. When you purchase through these links, I earn a small commission at no additional cost to you. I only recommend products and services I genuinely use and believe in. Your support through these links helps me continue writing and sharing knowledge with the tech community.&lt;/p&gt;</description></item></channel></rss>