<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Blog — Bojan Delić</title><link>https://bojan.delic.rs/blog/</link><description>Thoughts on programming, technology, and other things.</description><generator>Hugo 0.155.3</generator><language>en</language><lastBuildDate>Mon, 16 Mar 2026 07:10:49 +0000</lastBuildDate><atom:link href="https://bojan.delic.rs/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Preparing for the Interview</title><link>https://bojan.delic.rs/blog/2026/02/preparing-for-the-interview/</link><pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate><guid>https://bojan.delic.rs/blog/2026/02/preparing-for-the-interview/</guid><description>How I approached interview preparation after a layoff, from deciding what I wanted to brushing up on system design and learning TypeScript.</description><content:encoded>&lt;p&gt;I got laid off recently. The product line was shut down, which is one of those things that just
happens. The silver lining was a transition period of a couple of months to keep the lights on and
handle knowledge transfer. That bought me time to job search without the pressure of an empty bank
account ticking down.&lt;/p&gt;
&lt;h2 id="figuring-out-what-i-wanted"&gt;Figuring Out What I Wanted&lt;a href="#figuring-out-what-i-wanted" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before opening any job board, I sat down and decided what I was actually looking for. Over the years
I&amp;rsquo;ve held both technical and managerial positions (the full history is on my &lt;a href="https://bojan.delic.rs/resume/"&gt;resume&lt;/a&gt;).
This time I wanted to go back to a purely technical IC role. Partially because that&amp;rsquo;s the kind of
work I enjoy the most, but also because I believe the most effective engineering leaders keep their
hands in the code and have a deep understanding of the problems being solved. So, I was looking for
Principal/Staff Engineer roles, or even Senior Engineer, since titles often do not reflect actual
work being done.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been fully remote since Covid and had no intention of changing that. Since I was already
location-independent, looking at international remote positions was the obvious move.&lt;/p&gt;
&lt;p&gt;Beyond that, I had a short list of criteria: strong engineering culture, a product company rather
than an outsourcing shop, systems operating at meaningful scale, healthy finances, and no situation
where a single large customer dictates the roadmap. That last one is easy to underestimate until
you&amp;rsquo;ve lived it.&lt;/p&gt;
&lt;h2 id="brushing-up"&gt;Brushing Up&lt;a href="#brushing-up" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I hadn&amp;rsquo;t interviewed in a long time. Some of the companies I found interesting used TypeScript,
which I&amp;rsquo;d never worked with. My background is Python and Go, so this was new territory. I picked up
TypeScript by building a small hobby project, leaning on the official docs and AI to accelerate the
learning curve. Both of those deserve their own posts. Picking up a new language is the easy part.
The time-consuming bit is figuring out the ecosystem and best practices.&lt;/p&gt;
&lt;h2 id="leetcode-no-thanks"&gt;LeetCode? No Thanks&lt;a href="#leetcode-no-thanks" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I made a deliberate choice to skip LeetCode preparation entirely.&lt;/p&gt;
&lt;p&gt;These kinds of interviews feel obsolete to me. They&amp;rsquo;re a skill you practice, much like cramming for
a math exam in college. You get good at the format, not necessarily at the job. The day-to-day
utility of inverting a binary tree on a whiteboard was already questionable before LLMs, and it&amp;rsquo;s
even harder to justify now.&lt;/p&gt;
&lt;p&gt;More importantly, I wanted to work somewhere that shares this view and reflects it in their
interview process. If a company&amp;rsquo;s primary signal for engineering ability is algorithmic puzzles, we
probably disagree on enough other things that it wouldn&amp;rsquo;t be a great fit anyway.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m fine with live coding as a sanity check, making sure a candidate can actually write code and
reason about a problem in real time. That&amp;rsquo;s different from expecting someone to produce an optimal
dynamic programming solution in 20 minutes.&lt;/p&gt;
&lt;h2 id="system-design"&gt;System Design&lt;a href="#system-design" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;System design was where I needed the most structured preparation. I&amp;rsquo;d never had a formal system
design interview before. Working on production systems for over a decade teaches you a lot of what&amp;rsquo;s
relevant, but knowing the material and presenting it well within an hour-long interview are
different skills.&lt;/p&gt;
&lt;p&gt;I needed to practice the format: how to scope a problem, what to focus on first, how to navigate
trade-offs out loud. I also wanted to run through common problem types, because coming up with a
solid solution under time pressure is harder when you&amp;rsquo;ve never thought about the problem before.
Take something like designing a timeline feed, the problem Twitter made famous. I&amp;rsquo;m confident I&amp;rsquo;d
get there eventually, but &amp;ldquo;eventually&amp;rdquo; doesn&amp;rsquo;t fit in a 45-minute slot. Seeing the problem space
beforehand means you spend the interview demonstrating judgment instead of fumbling toward a first
draft.&lt;/p&gt;
&lt;p&gt;I also had specific gaps I wanted to fill. Real-time systems, for instance. I understood the
principles but hadn&amp;rsquo;t worked with the concrete technologies. I looked at some free resources but
ultimately paid for a &lt;a href="https://www.hellointerview.com/" target="_blank" rel="noopener noreferrer"&gt;HelloInterview&lt;/a&gt;&lt;span class="external-link-icon" aria-hidden="true"&gt;&lt;span class="icon-inline" aria-hidden="true"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt; subscription, which turned
out to be worth it for the structure alone.&lt;/p&gt;
&lt;p&gt;In total, I spent about two weeks preparing. Not full-time. A couple of hours a day. A friend and I
ran mock system design sessions using &lt;a href="https://excalidraw.com/" target="_blank" rel="noopener noreferrer"&gt;Excalidraw&lt;/a&gt;&lt;span class="external-link-icon" aria-hidden="true"&gt;&lt;span class="icon-inline" aria-hidden="true"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt;, which ended up being
the same tool I used in the actual interviews.&lt;/p&gt;
&lt;p&gt;Beyond interview prep, I genuinely learned patterns I hadn&amp;rsquo;t encountered before. Time well invested.
The knowledge doesn&amp;rsquo;t expire after the interview. It&amp;rsquo;s there for whenever a real-world problem calls
for it.&lt;/p&gt;
&lt;h2 id="the-initial-calls"&gt;The Initial Calls&lt;a href="#the-initial-calls" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every process started with one or more calls with a recruiter or hiring manager. A walk through my
experience, what the team looks like, why they&amp;rsquo;re hiring, how they work. These weren&amp;rsquo;t formalities.
They felt like real gates, and they were also where I learned the most about the company: team size,
financial health, level of maturity. Salary expectations usually came up here too. Some companies
asked for a number, some offered a range upfront. I appreciated the latter.&lt;/p&gt;
&lt;h2 id="live-coding"&gt;Live Coding&lt;a href="#live-coding" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was the part I was most nervous about. Not because I can&amp;rsquo;t code, but because I can&amp;rsquo;t even type
properly when someone is watching over my shoulder. Two of the interviews had live coding in
TypeScript, a language I wasn&amp;rsquo;t fluent in, which didn&amp;rsquo;t help. That turned out to be less of a
problem than I expected. The interviewers were great about it and didn&amp;rsquo;t fixate on syntax, helping
me out on small things that would have taken ten seconds to search.&lt;/p&gt;
&lt;p&gt;All three live coding sessions were different, which was interesting in itself.&lt;/p&gt;
&lt;h3 id="the-take-home-with-a-twist"&gt;The Take-Home with a Twist&lt;a href="#the-take-home-with-a-twist" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I got the task upfront and was told to use whatever resources I wanted to prepare, AI explicitly
included. The problem was engaging and deceptively simple on the surface, with plenty of room to
expand into. I spent nearly a full day implementing, reimplementing, and refining my solution.&lt;/p&gt;
&lt;p&gt;During the actual interview, the coding part lasted maybe ten minutes. I walked through my thinking,
which approaches I considered, which one I chose, and why. Partway through the code, they stopped
me: they could see I&amp;rsquo;d thought about it and could code, so we shifted to discussing potential
expansions. The interview turned into a verbal system design session. I liked this format the most.
It removed the usual edge by giving you time to think beforehand, it was genuinely fun, and I think
it gives interviewers a richer signal than watching someone sweat through syntax under a timer.&lt;/p&gt;
&lt;h3 id="the-two-hour-work-simulation"&gt;The Two-Hour Work Simulation&lt;a href="#the-two-hour-work-simulation" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The task was deliberately vague, a couple of lines describing a problem from the company&amp;rsquo;s domain.
It was up to me to use any resource available (Google, AI, and the interviewers themselves) to fill
in the gaps, learn the terminology, and figure out what to build. I asked a lot of questions, and
they answered. The point was asking the right ones. Sometimes they&amp;rsquo;d steer me by asking questions
back, not always expecting an answer, but nudging me toward discovering something on my own.&lt;/p&gt;
&lt;p&gt;The first fifteen minutes were intense. The problem was unfamiliar and someone was watching me
fumble through it. After that initial stretch, I settled in and actually enjoyed it. It felt like a
realistic preview of what the first weeks on the job would be like.&lt;/p&gt;
&lt;h3 id="the-straightforward-modeling-exercise"&gt;The Straightforward Modeling Exercise&lt;a href="#the-straightforward-modeling-exercise" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The simplest of the three, modeling a small system that was a subset of the company&amp;rsquo;s actual
product. No AI, no Googling, TypeScript required. I knew enough to solve it, but didn&amp;rsquo;t have every
generics syntax detail memorized. I explained what I was trying to do, and the interviewer helped
with the specifics. Since I&amp;rsquo;d been upfront about TypeScript not being my primary stack, this wasn&amp;rsquo;t
held against me. The coding itself was more of a sanity check, because it was paired with a system
design interview the same day, and if both went well, the next step was a paid trial, which carried
the most weight in their process.&lt;/p&gt;
&lt;h2 id="interviewing-the-company"&gt;Interviewing the Company&lt;a href="#interviewing-the-company" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Throughout all of this, I was evaluating the companies as much as they were evaluating me. The
interview process itself was the clearest signal. What skills did they test for? Did the tasks
reflect actual work, or were they performative? How fast did they respond after each round? A
company that takes two weeks to schedule a follow-up is telling you something about how they
operate.&lt;/p&gt;
&lt;p&gt;The type of coding challenge said a lot too. The ones that gave me room to ask questions, explore
the problem, and show judgment felt like places where engineers are trusted to think. The ones that
locked everything down and measured speed felt like places where output is measured in lines of
code.&lt;/p&gt;
&lt;h2 id="how-it-landed"&gt;How It Landed&lt;a href="#how-it-landed" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I ended up with three offers. The one I accepted was from the first company I applied to, and the
only one I had specifically targeted. The other two came through LinkedIn outreach and my
professional network.&lt;/p&gt;
&lt;p&gt;Those weren&amp;rsquo;t the only companies I pursued. A few others I&amp;rsquo;d specifically targeted never went
anywhere. Some rejected my CV outright, others weren&amp;rsquo;t hiring in my timezone. Getting past that
initial barrier is harder than it sounds. Having a referral from someone inside the company makes a
real difference at that stage, often the difference between a silent rejection and an actual
screening call. After that first conversation, though, it stops mattering. You&amp;rsquo;re on your own.&lt;/p&gt;
&lt;p&gt;Looking back, the preparation mattered more than I expected, but not just for the reasons I assumed
going in. The system design practice filled real gaps in my knowledge. The live coding sessions
turned out to be the most enjoyable interviews I&amp;rsquo;ve ever had. And going through different interview
formats gave me a surprisingly clear signal about which companies I&amp;rsquo;d actually want to work at. The
ones with thoughtful processes tended to be thoughtful about other things too.&lt;/p&gt;
&lt;p&gt;The layoff forced a reset I wouldn&amp;rsquo;t have chosen on my own, at least at that point in time. But
having that transition period, time to decide what I wanted, learn a new language, practice system
design without rushing, meant I could be genuinely selective instead of just grateful for the first
yes. I knew what I was looking for before I started.&lt;/p&gt;</content:encoded><enclosure url="https://bojan.delic.rs/blog/2026/02/preparing-for-the-interview/cover_hu_9e7f868be36350d8.png" length="1299083" type="image/png"/></item><item><title>Building This Website</title><link>https://bojan.delic.rs/blog/2026/02/building-this-website/</link><pubDate>Thu, 12 Feb 2026 00:00:00 +0000</pubDate><guid>https://bojan.delic.rs/blog/2026/02/building-this-website/</guid><description>Rebuilding my personal site from scratch with Hugo and a custom theme, using Pi coding agent to do the heavy lifting.</description><content:encoded>&lt;p&gt;My previous personal website was a Hugo site with a stock theme that I set up once and never really
touched again. It worked, but it felt like it belonged to someone else. I wanted to rebuild it from
scratch with a custom theme and proper modern web practices. Instead of writing all the code myself,
I&amp;rsquo;d use &lt;a href="https://github.com/mariozechner/pi-coding-agent" target="_blank" rel="noopener noreferrer"&gt;Pi&lt;/a&gt;&lt;span class="external-link-icon" aria-hidden="true"&gt;&lt;span class="icon-inline" aria-hidden="true"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt; — an AI coding agent for the terminal
— and see how far I could get by just describing what I want and steering the implementation.&lt;/p&gt;
&lt;h2 id="the-stack"&gt;The Stack&lt;a href="#the-stack" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I already had a Hugo site, so staying with &lt;a href="https://gohugo.io" target="_blank" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt;&lt;span class="external-link-icon" aria-hidden="true"&gt;&lt;span class="icon-inline" aria-hidden="true"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt; was a non-decision. It&amp;rsquo;s fast,
it&amp;rsquo;s a single binary, and the templating is straightforward enough. The goal was a personal site
with four sections: blog, projects, resume, and quotes. No JavaScript frameworks. No build tools
beyond Hugo itself. Deploys to &lt;a href="https://pages.cloudflare.com/" target="_blank" rel="noopener noreferrer"&gt;Cloudflare Pages&lt;/a&gt;&lt;span class="external-link-icon" aria-hidden="true"&gt;&lt;span class="icon-inline" aria-hidden="true"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt; via GitHub Actions.&lt;/p&gt;
&lt;p&gt;The whole thing took two evening sessions. Most of my time went into reviewing output and making
decisions — the agent did the actual coding.&lt;/p&gt;
&lt;h2 id="custom-theme-from-scratch"&gt;Custom Theme from Scratch&lt;a href="#custom-theme-from-scratch" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The stock theme had to go. The agent built a custom one under &lt;code&gt;themes/minimal/&lt;/code&gt;. The CSS landed in
six focused files (&lt;code&gt;base.css&lt;/code&gt;, &lt;code&gt;layout.css&lt;/code&gt;, &lt;code&gt;article.css&lt;/code&gt;, &lt;code&gt;sections.css&lt;/code&gt;, &lt;code&gt;responsive.css&lt;/code&gt;,
&lt;code&gt;syntax.css&lt;/code&gt;) that Hugo Pipes concatenates and fingerprints into a single output file at build time.&lt;/p&gt;
&lt;p&gt;Design tokens live as CSS custom properties in &lt;code&gt;base.css&lt;/code&gt;. The entire color scheme, spacing, and
typography can be adjusted by tweaking a handful of variables. Light and dark mode is just swapping
those properties, with the toggle being the only JavaScript on the site. It reads the OS preference
on first visit, allows manual override, and persists the choice in localStorage.&lt;/p&gt;
&lt;h2 id="data-driven-sections"&gt;Data-Driven Sections&lt;a href="#data-driven-sections" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rather than creating individual content pages for projects, resume, and quotes, these sections are
driven by YAML files in &lt;code&gt;data/&lt;/code&gt;. The projects page reads from &lt;code&gt;data/projects.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-lang="yaml" data-titled&gt;
&lt;div class="code-title"&gt;data/projects.yaml&lt;/div&gt;
&lt;button class="copy-btn" aria-label="Copy code" title="Copy code"&gt;
&lt;span class="copy-icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M384 336l-192 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l140.1 0L400 115.9 400 320c0 8.8-7.2 16-16 16zM192 384l192 0c35.3 0 64-28.7 64-64l0-204.1c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1L192 0c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l192 0c35.3 0 64-28.7 64-64l0-32-48 0 0 32c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l32 0 0-48-32 0z"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;span class="check-icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;/button&gt;
&lt;div class="highlight" title="data/projects.yaml"&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;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ligno&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/delicb/ligno&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;description&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Logging library for Go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tech&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;Go]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;featured&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:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;slogbuffer&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/delicb/slogbuffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;description&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Buffer handler for slog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tech&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;Go]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Projects marked &lt;code&gt;featured: true&lt;/code&gt; render as larger cards in a responsive grid at the top of the page.
Everything else shows up as a compact list below. Promoting or demoting a project is a one-line YAML
change.&lt;/p&gt;
&lt;p&gt;Resume and quotes work the same way — templates iterate over data files, nothing is hardcoded twice.&lt;/p&gt;
&lt;h2 id="blog-features"&gt;Blog Features&lt;a href="#blog-features" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The blog picked up a few features along the way:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pagination&lt;/strong&gt; uses Hugo&amp;rsquo;s built-in &lt;code&gt;.Paginate&lt;/code&gt; with 10 posts per page. The list layout went through
a revision after the first version placed the date awkwardly in the middle of each row. In the final
version, the title and reading time are stacked on the left, with the date pushed to the right.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reading time&lt;/strong&gt; uses Hugo&amp;rsquo;s &lt;code&gt;.ReadingTime&lt;/code&gt; variable. It shows up on both single posts and the list
page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cover images&lt;/strong&gt; are convention-based. Drop a &lt;code&gt;cover.*&lt;/code&gt; file into a post&amp;rsquo;s page bundle directory and
the template picks it up automatically via &lt;code&gt;.Resources.GetMatch &amp;quot;cover.*&amp;quot;&lt;/code&gt;. No front matter
configuration needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The include shortcode&lt;/strong&gt; was the most interesting piece. I wanted to embed code from actual files
in a post&amp;rsquo;s directory, not just inline code blocks. The agent built
&lt;code&gt;themes/minimal/layouts/shortcodes/include.html&lt;/code&gt; with support for line ranges, line numbers, and
line highlighting:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-lang="text"&gt;
&lt;button class="copy-btn" aria-label="Copy code" title="Copy code"&gt;
&lt;span class="copy-icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M384 336l-192 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l140.1 0L400 115.9 400 320c0 8.8-7.2 16-16 16zM192 384l192 0c35.3 0 64-28.7 64-64l0-204.1c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1L192 0c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l192 0c35.3 0 64-28.7 64-64l0-32-48 0 0 32c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l32 0 0-48-32 0z"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;span class="check-icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;/button&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;{{&amp;lt; include file=&amp;#34;setup.py&amp;#34; lines=&amp;#34;11-27&amp;#34; linenos=&amp;#34;table&amp;#34; hl=&amp;#34;19-20&amp;#34; &amp;gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The tricky part was line highlighting. The &lt;code&gt;hl&lt;/code&gt; parameter takes original file line numbers, but
Hugo&amp;rsquo;s &lt;code&gt;highlight&lt;/code&gt; function expects line numbers relative to the displayed block. So if you&amp;rsquo;re
showing lines 11-27 and want to highlight line 19, the shortcode translates that to line 9
internally. This took a few iterations to get right. The agent&amp;rsquo;s first implementation didn&amp;rsquo;t account
for the offset, and the highlighted lines were wrong. After I pointed it out, it fixed the
translation logic and it&amp;rsquo;s worked since.&lt;/p&gt;
&lt;p&gt;Language detection is automatic from the file extension, with an optional &lt;code&gt;lang&lt;/code&gt; parameter for
overrides.&lt;/p&gt;
&lt;h2 id="seo-and-meta"&gt;SEO and Meta&lt;a href="#seo-and-meta" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I asked the agent to fetch the old live site and compare. It came back with a list: no favicons, no
Open Graph tags, no RSS feed, no canonical URLs, no sitemap, no structured data.&lt;/p&gt;
&lt;p&gt;I pointed the agent at a photo in my Downloads folder and it generated favicons in all standard
sizes (16, 32, 180, 192, 512px, plus &lt;code&gt;.ico&lt;/code&gt;) using &lt;code&gt;sips&lt;/code&gt; and ImageMagick. The same photo became the
default Open Graph image.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; partial now includes Open Graph and Twitter Card tags generated from each page&amp;rsquo;s front
matter, with blog posts using their cover image when available. There&amp;rsquo;s JSON-LD structured data as
well. The homepage gets a &lt;code&gt;Person&lt;/code&gt; schema with &lt;code&gt;sameAs&lt;/code&gt; links to GitHub, LinkedIn, and X, while
articles get a &lt;code&gt;BlogPosting&lt;/code&gt; schema. Canonical URLs are on every page. RSS is enabled for the blog
section with auto-discovery via &lt;code&gt;&amp;lt;link rel=&amp;quot;alternate&amp;quot;&amp;gt;&lt;/code&gt;, and the sitemap is auto-generated by Hugo.&lt;/p&gt;
&lt;h2 id="security-and-headers"&gt;Security and Headers&lt;a href="#security-and-headers" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cloudflare Pages supports a &lt;code&gt;_headers&lt;/code&gt; file for setting HTTP response headers. The agent created
&lt;code&gt;static/_headers&lt;/code&gt; with some basic security hardening.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-lang="text"&gt;
&lt;button class="copy-btn" aria-label="Copy code" title="Copy code"&gt;
&lt;span class="copy-icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M384 336l-192 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l140.1 0L400 115.9 400 320c0 8.8-7.2 16-16 16zM192 384l192 0c35.3 0 64-28.7 64-64l0-204.1c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1L192 0c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l192 0c35.3 0 64-28.7 64-64l0-32-48 0 0 32c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l32 0 0-48-32 0z"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;span class="check-icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;/button&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;/*
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; X-Content-Type-Options: nosniff
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; X-Frame-Options: DENY
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Referrer-Policy: strict-origin-when-cross-origin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Permissions-Policy: camera=(), microphone=(), geolocation=()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;A &lt;code&gt;security.txt&lt;/code&gt; file went into &lt;code&gt;static/.well-known/&lt;/code&gt; following RFC 9116, with contact email and an
expiry date that needs annual renewal.&lt;/p&gt;
&lt;p&gt;For analytics, I went with Cloudflare Web Analytics over Google Analytics. It&amp;rsquo;s free, doesn&amp;rsquo;t
require cookies, and since the site is already on Cloudflare, enabling it is just a toggle in the
dashboard. No code changes, no tracking scripts.&lt;/p&gt;
&lt;h2 id="deployment"&gt;Deployment&lt;a href="#deployment" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The CI pipeline is a straightforward GitHub Actions workflow. Checkout, build with &lt;code&gt;hugo --minify&lt;/code&gt;,
deploy to Cloudflare Pages via Wrangler. Maybe ~50 lines of YAML total.&lt;/p&gt;
&lt;p&gt;The Cloudflare API token only needs the &lt;code&gt;Account &amp;gt; Cloudflare Pages &amp;gt; Edit&lt;/code&gt; permission. The agent
initially suggested using the &amp;ldquo;Edit Cloudflare Workers&amp;rdquo; template, which bundles a bunch of
unnecessary permissions. When I questioned it while setting up the token, it confirmed the minimal
scope was sufficient. Small thing, but this is exactly the kind of detail where having a human in
the loop matters.&lt;/p&gt;
&lt;h2 id="contact-form"&gt;Contact Form&lt;a href="#contact-form" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The contact page turned out to be the most frustrating feature to ship. The idea was simple: a form
that sends me an email, protected from bots. Cloudflare Pages Functions handle the backend, so the
form submits to a TypeScript function at &lt;code&gt;/api/contact&lt;/code&gt; that forwards the message via Resend&amp;rsquo;s API.
A honeypot field catches dumb bots, and Cloudflare Turnstile handles the rest.&lt;/p&gt;
&lt;p&gt;Except Turnstile didn&amp;rsquo;t work. For hours. The widget rendered fine, tokens were generated, but every
single verification request came back with &lt;code&gt;invalid-input-response&lt;/code&gt;. I rotated keys, recreated the
widget, triple-checked the secret, logged everything. The agent and I went through every possible
cause: wrong secret, wrong domain, Bot Fight Mode, token encoding issues. We rewrote the
verification logic from scratch, tried inlining it instead of using the middleware, compared headers
and payloads. Nothing worked. Eventually, in desperation, we switched to the official
&lt;code&gt;@cloudflare/pages-plugin-turnstile&lt;/code&gt; package, which handles verification as middleware before the
request even hits the function. That worked. We tried reverting to the manual approach to isolate
the root cause, and it broke again. So the plugin stayed.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m still not entirely sure what was wrong with the manual implementation. The plugin does
essentially the same thing, just packaged differently. It might have been a subtle issue with how
the form data was being consumed before the token could be verified, or some Cloudflare-internal
behavior the plugin accounts for. Either way, it works now, and I&amp;rsquo;ve accepted that some debugging
sessions end with &amp;ldquo;it works, don&amp;rsquo;t touch it&amp;rdquo; rather than a satisfying root cause.&lt;/p&gt;
&lt;h2 id="working-with-a-coding-agent"&gt;Working with a Coding Agent&lt;a href="#working-with-a-coding-agent" class="heading-anchor" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The entire site was built through Pi, a terminal-based coding agent, using Opus 4.6. Pi is turning
out to be way more enjoyable than Claude Code. I really dig the minimalism — and the fact that you
can ask it to create its own extensions and skills, then use them in future sessions. For this site
I had it generate four skills: blog post review, Hugo dev server management, Lighthouse auditing,
and new post scaffolding. Now when I say &amp;ldquo;run a Lighthouse audit&amp;rdquo; or &amp;ldquo;create a new blog post,&amp;rdquo; it
already knows the project structure, the right commands, and where everything lives.&lt;/p&gt;
&lt;p&gt;Some things landed on the first try — data-driven sections, the deployment pipeline, security
headers.&lt;/p&gt;
&lt;p&gt;Other things needed iteration. The include shortcode&amp;rsquo;s line highlighting was wrong on the first
pass. The blog list layout needed a redesign after the initial version didn&amp;rsquo;t look right. The
&lt;code&gt;_headers&lt;/code&gt; file syntax confused me because &lt;code&gt;/*&lt;/code&gt; looks like an unclosed comment, and the agent
explained it&amp;rsquo;s actually a URL wildcard pattern in Cloudflare&amp;rsquo;s config format. I never used
&lt;code&gt;_headers&lt;/code&gt; so this is something I learned along the way.&lt;/p&gt;
&lt;p&gt;There were also moments where the agent proactively caught things I hadn&amp;rsquo;t thought about. When it
fetched the old site to compare, it identified six missing features I would have shipped without.
When I asked about adding a homepage photo, it laid out pros and cons and I decided against it. When
it suggested Google Analytics, I asked about alternatives and it pointed me to Cloudflare&amp;rsquo;s built-in
analytics.&lt;/p&gt;
&lt;p&gt;The division of labor was simple: I decide, it builds. I&amp;rsquo;m not reviewing every line of CSS it
generates, and honestly I could not even if I wanted to since I never bothered to learn CSS
properly. But I am deciding what the site should have, how it should behave, and when something
doesn&amp;rsquo;t look right. The tedious parts — six favicon sizes, JSON-LD schemas, pagination edge cases —
would have slowly drained my motivation. The agent knocked them out in seconds.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think I would have shipped a site with this level of polish in two evenings on my own. Not
because any individual feature is complex, but because the number of small tasks adds up fast.
Having an agent that can knock out each one in seconds while I focus on the bigger picture made the
whole process genuinely enjoyable.&lt;/p&gt;
&lt;p&gt;The source is &lt;a href="https://github.com/delicb/bojan.delic.rs" target="_blank" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;&lt;span class="external-link-icon" aria-hidden="true"&gt;&lt;span class="icon-inline" aria-hidden="true"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt; if you want to look at the
result.&lt;/p&gt;</content:encoded><enclosure url="https://bojan.delic.rs/blog/2026/02/building-this-website/cover_hu_6ee5c6f6c6de4b0b.png" length="1274885" type="image/png"/></item><item><title>Hello world</title><link>https://bojan.delic.rs/blog/2026/02/hello-world/</link><pubDate>Wed, 11 Feb 2026 00:00:00 +0000</pubDate><guid>https://bojan.delic.rs/blog/2026/02/hello-world/</guid><description>First blog post</description><content:encoded>&lt;div class="code-block-wrapper" data-lang="py" data-titled&gt;
&lt;div class="code-title"&gt;hello_world.py&lt;/div&gt;
&lt;button class="copy-btn" aria-label="Copy code" title="Copy code"&gt;
&lt;span class="copy-icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M384 336l-192 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l140.1 0L400 115.9 400 320c0 8.8-7.2 16-16 16zM192 384l192 0c35.3 0 64-28.7 64-64l0-204.1c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1L192 0c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l192 0c35.3 0 64-28.7 64-64l0-32-48 0 0 32c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l32 0 0-48-32 0z"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;span class="check-icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"&gt;&lt;!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --&gt;&lt;path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;/button&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-py" data-lang="py"&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;Greeting&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self, target&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;World&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target &lt;span style="color:#f92672"&gt;=&lt;/span&gt; target
&lt;/span&gt;&lt;/span&gt;&lt;span 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;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__str__&lt;/span&gt;(self):
&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;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Hello, &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target&lt;span style="color:#e6db74"&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;
&lt;/span&gt;&lt;/span&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;EnthusiasticGreeting&lt;/span&gt;(Greeting):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__str__&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; super()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__str__&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; base&lt;span style="color:#f92672"&gt;.&lt;/span&gt;upper() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;!!&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; 🎉&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&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;
&lt;/span&gt;&lt;/span&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;ShyGreeting&lt;/span&gt;(Greeting):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__str__&lt;/span&gt;(self):
&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;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;oh... um... hi, &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;... i guess&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;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&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; cls &lt;span style="color:#f92672"&gt;in&lt;/span&gt; [Greeting, EnthusiasticGreeting, ShyGreeting]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(cls())
&lt;/span&gt;&lt;/span&gt;&lt;span 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; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content:encoded><enclosure url="https://bojan.delic.rs/blog/2026/02/hello-world/cover_hu_9e1d69f88d17bd69.jpg" length="64805" type="image/jpeg"/></item></channel></rss>