<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta name="description" content="Personal blog about frontend web development and some other thoughts.">
		<meta name="generator" content="Eleventy v3.1.6">
		<link rel="icon" type="image/x-icon" href="/assets/favicon.ico">
		<link rel="preload" href="/assets/fonts/source-serif-4-variable.woff2" as="font" type="font/woff2" crossorigin>

		<link rel="alternate" type="application/atom+xml" href="/feed.xml" title="F. Knüssel">
		<link rel="canonical" href="https://fedknu.com/sitemap.xml">
		<meta property="og:title" content="F. Knüssel">
		<meta property="og:description" content="Personal blog about frontend web development and some other thoughts.">
		<meta property="og:url" content="https://fedknu.com/sitemap.xml">
		<meta property="og:type" content="website">
		<meta property="og:image" content="https://fedknu.com/og-images/1a40155c.png">
		<meta name="twitter:card" content="summary_large_image">

		<title>
			F. Knüssel
		</title>

		<script>
			(function () {
	function readSavedTheme() {
		try {
			return localStorage.getItem("theme");
		} catch {
			return null;
		}
	}

	function saveTheme(theme) {
		try {
			localStorage.setItem("theme", theme);
		} catch {}
	}

	function applyTheme(theme) {
		document.documentElement.style.setProperty("color-scheme", theme);
		document.documentElement.setAttribute("data-theme", theme);
	}

	window.siteTheme = { readSavedTheme, saveTheme, applyTheme };

	const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
	applyTheme(readSavedTheme() || systemTheme);
})();

		</script>
		<noscript>
			<style>
				#search-button,
				#theme-toggle {
					display: none;
				}
			</style>
		</noscript>

		
		
		<style>
			:where(html){-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;line-height:1.15}:where(h1){margin-block:.67em;font-size:2em}:where(dl,ol,ul) :where(dl,ol,ul){margin-block:0}:where(hr){box-sizing:content-box;color:inherit;height:0}:where(abbr[title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}:where(b,strong){font-weight:bolder}:where(code,kbd,pre,samp){font-family:monospace;font-size:1em}:where(small){font-size:80%}:where(table){text-indent:0;border-color:currentColor}:where(button,input,select){margin:0}:where(button){text-transform:none}:where(button,input:is([type=button i],[type=reset i],[type=submit i])){-webkit-appearance:button}:where(progress){vertical-align:baseline}:where(select){text-transform:none}:where(textarea){margin:0}:where(input[type=search i]){-webkit-appearance:textfield;outline-offset:-2px}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}:where(button,input:is([type=button i],[type=color i],[type=reset i],[type=submit i]))::-moz-focus-inner{border-style:none;padding:0}:where(button,input:is([type=button i],[type=color i],[type=reset i],[type=submit i]))::-moz-focusring{outline:1px dotted buttontext}:where(:-moz-ui-invalid){box-shadow:none}:where(dialog){color:#000;background-color:#fff;border:solid;width:fit-content;height:fit-content;margin:auto;padding:1em;position:absolute;left:0;right:0}:where(dialog:not([open])){display:none}:where(summary){display:list-item}@font-face{font-family:"Source Serif 4";font-style:normal;font-weight:400 600;font-display:swap;src:url(/assets/fonts/source-serif-4-variable.woff2)format("woff2")}@font-face{font-family:"Source Serif 4";font-style:italic;font-weight:400;font-display:swap;src:url(/assets/fonts/source-serif-4-italic.woff2)format("woff2")}:root{--token-font-family-sans-serif:system-ui, sans-serif;--token-font-family-monospace:ui-monospace, Consolas, monospace;--token-font-family-serif:"Source Serif 4", Georgia, serif;--token-color-navy:#172b4d;--token-color-gray-dark:#344563;--token-color-gray-light:#e1e1e1;--token-color-gray-extra-light:#f7f7f7;--token-color-gray-warm:#f0eee6;--token-color-white:#fff;--token-color-ivory:#faf7f1;--token-color-yellow:#f9ca5e;--token-color-orange:#ffa066;--token-color-crimson:#d14;--token-color-blue:#0572e6;--token-color-midnight:#292a44;--token-color-midnight-dark:#212136;--token-color-midnight-light:#333454;--token-color-graphite:#161b22;--token-color-dusk:#4f528a;--token-color-lavender:#f1eff7;--token-color-slate:#9da5b4;--token-color-mint:#6dfdc4;--token-color-jade:#2de0a7;--token-color-periwinkle:#7aa5ff;--token-color-apricot:#ffbc69;--token-color-rose:#ed4781;--token-color-forest:#2e6f40;color-scheme:light dark;--color-bg:light-dark(var(--token-color-ivory),var(--token-color-midnight));--color-bg-alt:light-dark(var(--token-color-gray-extra-light),var(--token-color-midnight-dark));--color-text:light-dark(var(--token-color-navy),var(--token-color-lavender));--color-text-muted:light-dark(var(--token-color-gray-dark),var(--token-color-slate));--color-heading:light-dark(var(--token-color-navy),var(--token-color-white));--color-border:light-dark(var(--token-color-gray-light),var(--token-color-dusk));--color-accent:light-dark(var(--token-color-forest),var(--token-color-mint));--color-accent-text:light-dark(var(--token-color-white),var(--token-color-midnight));--color-focus:var(--color-accent);--color-selection:light-dark(Highlight,var(--token-color-dusk));--color-code-bg:light-dark(var(--token-color-gray-warm),var(--token-color-graphite));--token-spacing-xxs:.25rem;--token-spacing-xs:.5rem;--token-spacing-sm:1rem;--token-spacing-md:1.5rem;--token-spacing-lg:2rem;--token-spacing-xl:3rem;--token-spacing-xxl:4rem;--token-font-size-xs:.875rem;--token-font-size-sm:1.125rem;--token-font-size-md:clamp(1.125rem, .9rem + 1vw, 1.375rem);--token-font-size-lg:clamp(1.5rem, 1.1rem + 1.5vw, 1.875rem);--token-font-size-xl:clamp(2.25rem, 1.25rem + 5vw, 3.875rem);--token-font-weight-extra-light:200;--token-font-weight-light:300;--token-font-weight-normal:400;--token-font-weight-semibold:600;--token-line-height-sm:1.15;--token-line-height-md:1.5;--token-line-height-lg:2;--token-letter-spacing-caps:.05em;--token-layout-max-width:1024px;--token-border-radius-default:3px;--token-border-radius-lg:6px;--token-focus-ring-width:3px;--token-focus-ring-offset:2px}*,:before,:after{box-sizing:border-box}::selection{background-color:var(--color-selection)}body{background-color:var(--color-bg);color:var(--color-text);font-family:var(--token-font-family-serif);margin:0}.common-main-title{font-size:var(--token-font-size-xl);line-height:var(--token-line-height-sm);margin:0 0 var(--token-spacing-md)}.common-main-content p,.common-main-content ul,.common-main-content ol,.common-main-content td,.common-main-content th{font-size:var(--token-font-size-md);line-height:var(--token-line-height-lg)}.common-main-content b,.common-main-content strong{font-weight:var(--token-font-weight-semibold)}.common-main-content a{color:var(--color-accent);text-underline-offset:4px;overflow-wrap:anywhere;text-decoration-thickness:2px;transition:text-decoration-thickness .1s ease-in-out}.common-main-content a:hover{text-decoration-thickness:4px}.common-focus-ring:focus-visible,.common-main-content a:focus-visible{outline:var(--token-focus-ring-width) solid var(--color-focus);outline-offset:var(--token-focus-ring-offset)}.common-main-content a:focus-visible{border-radius:1px}h1,h2,h3,h4,h5,h6{color:var(--color-heading);font-weight:var(--token-font-weight-semibold)}.common-main-content .heading-wrapper:has(>h2){font-size:var(--token-font-size-lg);margin:var(--token-spacing-xl) 0 0}.common-main-content .heading-wrapper:has(>h3){font-size:var(--token-font-size-md);margin:var(--token-spacing-xl) 0 0}.common-main-content .heading-wrapper>:is(h2,h3,h4,h5,h6){font-size:inherit;display:inline}.common-main-content .header-anchor{margin-left:var(--token-spacing-xs);color:var(--color-text-muted);font-family:var(--token-font-family-sans-serif);font-size:.85em;font-weight:var(--token-font-weight-extra-light);text-decoration:none}.common-main-content .header-anchor:hover{color:var(--color-accent)}.common-main-content picture{text-align:center;margin:var(--token-spacing-xxl) 0;display:block}.common-main-content iframe{aspect-ratio:16/9;max-width:100%;height:auto}.common-main-content td,.common-main-content th{padding:var(--token-spacing-xs);text-align:center}.common-main-content th{background-color:var(--color-code-bg);font-weight:var(--token-font-weight-semibold)}.common-main-content table{border-collapse:collapse}.common-main-content table,.common-main-content th,.common-main-content td{border:1px solid var(--color-border)}.common-main-content .admonition{--admonition-color:var(--color-text-muted);border:1px solid var(--color-border);border-left:var(--token-spacing-xs) solid var(--admonition-color);border-radius:var(--token-border-radius-default);background-color:color-mix(in srgb, var(--admonition-color) 10%, transparent);padding:var(--token-spacing-sm) var(--token-spacing-md);margin:var(--token-spacing-lg) 0}.common-main-content .admonition--tip{--admonition-color:light-dark(var(--token-color-forest),var(--token-color-jade))}.common-main-content .admonition--info{--admonition-color:light-dark(var(--token-color-blue),var(--token-color-periwinkle))}.common-main-content .admonition--warning{--admonition-color:light-dark(var(--token-color-orange),var(--token-color-apricot))}.common-main-content .admonition--danger{--admonition-color:light-dark(var(--token-color-crimson),var(--token-color-rose))}.common-main-content .admonition__title{font-family:var(--token-font-family-sans-serif);font-size:var(--token-font-size-xs);font-weight:var(--token-font-weight-semibold);line-height:var(--token-line-height-md);text-transform:uppercase;letter-spacing:var(--token-letter-spacing-caps);margin:0}.common-main-content .admonition__title+*{margin-top:0}.common-main-content .admonition>:last-child{margin-bottom:0}.common-main-content hr{border:none;border-top:1px solid color-mix(in srgb, var(--color-border) 65%, var(--color-text-muted) 35%);margin:var(--token-spacing-xl) 0}.common-main-content code:not(:where(pre code)){background-color:var(--color-code-bg);border-radius:var(--token-border-radius-default);padding:var(--token-spacing-xxs) var(--token-spacing-xs);font-size:.85em;font-weight:var(--token-font-weight-normal);white-space:nowrap}.common-visually-hidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.layout-skip-link{--skip-link-height:var(--token-spacing-xl);--skip-link-margin:var(--token-spacing-xs);background-color:var(--color-accent);border-radius:var(--token-border-radius-default);color:var(--color-accent-text);font-family:var(--token-font-family-sans-serif);font-size:var(--token-font-size-sm);font-weight:var(--token-font-weight-light);height:var(--skip-link-height);margin:var(--skip-link-margin);outline-offset:var(--token-spacing-xxs);padding:0 var(--token-spacing-sm);transform:translateY(calc(-1 * (var(--skip-link-height) + var(--skip-link-margin))));z-index:10;align-items:center;display:inline-flex;position:fixed;top:0;left:0}.layout-skip-link:focus-visible{transform:translateY(0)}.layout-header{--layout-header-icon-size:20px;--layout-header-control-size:calc(var(--layout-header-icon-size) + 2 * var(--token-spacing-xs));margin:var(--token-spacing-md) 0}.layout-header__logo{z-index:2;background-color:var(--color-accent);color:var(--color-accent-text);font-family:var(--token-font-family-monospace);font-size:var(--token-font-size-sm);height:var(--layout-header-control-size);margin-right:var(--token-spacing-xl);justify-content:center;align-items:center;min-width:54px;text-decoration:none;display:inline-flex;position:relative}.layout-header__actions{align-items:center;gap:var(--token-spacing-xxs);display:flex}.layout-header__icon-button{z-index:2;cursor:pointer;padding:var(--token-spacing-xs);border-radius:var(--token-border-radius-default);color:var(--color-text);background:0 0;border:none;justify-content:center;align-items:center;display:flex;position:relative}.layout-header__theme-icon--light,:root[data-theme=dark] .layout-header__theme-icon--dark{display:none}:root[data-theme=dark] .layout-header__theme-icon--light{display:block}.layout-header__icon-button svg,.layout-header__menu-toggle svg{width:var(--layout-header-icon-size);height:var(--layout-header-icon-size);display:block}.layout-header__nav{align-items:center;gap:var(--token-spacing-xs);font-size:var(--token-font-size-sm);line-height:var(--token-line-height-sm);padding:var(--token-spacing-sm) var(--token-spacing-md);display:flex}.layout-header__menu{margin-left:auto}.layout-header__menu-toggle{z-index:2;cursor:pointer;padding:var(--token-spacing-xs);border-radius:var(--token-border-radius-default);color:var(--color-text);justify-content:center;align-items:center;list-style:none;display:flex;position:relative}.layout-header__menu-toggle::-webkit-details-marker{display:none}.layout-header__menu-toggle-icon--open,.layout-header__menu[open] .layout-header__menu-toggle-icon--closed{display:none}.layout-header__menu[open] .layout-header__menu-toggle-icon--open{display:block}.layout-header__menu[open] .layout-header__nav-list{display:flex}.layout-header__nav-list{align-items:flex-start;gap:var(--token-spacing-lg);z-index:1;padding:calc(var(--token-spacing-xxl) * 2) var(--token-spacing-lg) var(--token-spacing-lg);background-color:var(--color-bg);flex-direction:column;margin:0;display:none;position:fixed;inset:0;overflow-y:auto}@media screen and (width<768px){.layout-header__menu{order:1;margin-left:0}.layout-header__actions{margin-left:auto}body:has(.layout-header__menu[open]){overflow:hidden}}.layout-header__nav-item{list-style-type:none}.layout-header__menu .layout-header__nav-link{padding-block:var(--token-spacing-xs);font-size:var(--token-font-size-lg);display:block}@media screen and (width>=768px){.layout-header__nav{max-width:var(--token-layout-max-width);gap:var(--token-spacing-lg);margin:0 auto}.layout-header__menu-toggle{display:none}.layout-header__nav-list{background:0 0;flex-direction:row;align-items:center;padding:0;position:static;overflow-y:visible}.layout-header__menu .layout-header__nav-link{font-size:inherit;padding:var(--token-spacing-xxs) 0;display:inline}}.layout-header__nav-link{color:var(--color-text);font-family:var(--token-font-family-sans-serif);text-decoration:none}.layout-header__nav-link[aria-current=page]{text-underline-offset:6px;text-decoration:underline;text-decoration-thickness:2px}.layout-content{max-width:var(--token-layout-max-width);padding:var(--token-spacing-lg) var(--token-spacing-md) var(--token-spacing-xl);margin:0 auto}pagefind-modal{--pf-text:var(--color-text);--pf-text-secondary:var(--color-text-muted);--pf-text-muted:var(--color-text-muted);--pf-background:light-dark(var(--token-color-ivory),var(--token-color-midnight-dark));--pf-border:var(--color-border);--pf-border-focus:var(--color-accent);--pf-hover:light-dark(var(--token-color-gray-extra-light),var(--token-color-midnight-light));--pf-mark:var(--color-heading);--pf-skeleton:var(--pf-hover);--pf-skeleton-shine:var(--color-border);--pf-outline-focus:var(--color-focus);--pf-font:var(--token-font-family-sans-serif);--pf-modal-backdrop:light-dark(#00000080,#000000b3);--pf-shadow-lg:0 0 0 1px light-dark(transparent,var(--color-border)), 0 16px 48px #0003}html pagefind-modal,html pagefind-modal *{color-scheme:inherit}pagefind-modal-body:has(.pf-summary:empty):not(:has(.pf-result)){display:none!important}pagefind-modal-body:has(.pf-summary:empty):not(:has(.pf-result))+pagefind-modal-footer{border-top:none!important}
		</style>
	</head>
	<body>

		<a href="#main" class="layout-skip-link">
        	Skip to main content
      	</a>

		<header class="layout-header">
			<nav class="layout-header__nav" aria-label="Site">
				<a href="/" class="layout-header__logo common-focus-ring">fk</a>

				<details class="layout-header__menu" open>
					<summary class="layout-header__menu-toggle common-focus-ring" aria-label="Menu">
						<span class="layout-header__menu-toggle-icon layout-header__menu-toggle-icon--closed" aria-hidden="true">
							<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
	<line x1="3" y1="6" x2="21" y2="6"/>
	<line x1="3" y1="12" x2="21" y2="12"/>
	<line x1="3" y1="18" x2="21" y2="18"/>
</svg>

						</span>
						<span class="layout-header__menu-toggle-icon layout-header__menu-toggle-icon--open" aria-hidden="true">
							<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
	<line x1="5" y1="5" x2="19" y2="19"/>
	<line x1="19" y1="5" x2="5" y2="19"/>
</svg>

						</span>
					</summary>

					<ul class="layout-header__nav-list">
							<li class="layout-header__nav-item">
								<a href="/about/"
								   class="layout-header__nav-link common-focus-ring"
								   >
									About
								</a>
							</li>
							<li class="layout-header__nav-item">
								<a href="/"
								   class="layout-header__nav-link common-focus-ring"
								   >
									Blog
								</a>
							</li>
							<li class="layout-header__nav-item">
								<a href="/uses/"
								   class="layout-header__nav-link common-focus-ring"
								   >
									Uses
								</a>
							</li>
							<li class="layout-header__nav-item">
								<a href="/now/"
								   class="layout-header__nav-link common-focus-ring"
								   >
									Now
								</a>
							</li>
							<li class="layout-header__nav-item">
								<a href="/feed.xml"
								   class="layout-header__nav-link common-focus-ring"
								   >
									Feed
								</a>
							</li>
					</ul>
				</details>

				<div class="layout-header__actions">
					<a href="https://github.com/fed" class="layout-header__icon-button common-focus-ring" aria-label="GitHub (external link)" target="_blank" rel="noreferrer">
						<span aria-hidden="true">
							<svg fill="currentColor" viewBox="0 0 16 16">
    <path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"></path>
</svg>

						</span>
					</a>

					<button id="search-button" class="layout-header__icon-button common-focus-ring" type="button" aria-label="Search" aria-haspopup="dialog">
						<span aria-hidden="true">
							<svg fill="none" viewBox="0 0 24 24">
    <circle cx="10.5" cy="10.5" r="6.5" stroke="currentColor" stroke-width="2"></circle>
    <path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="m15.5 15.5 5 5"></path>
</svg>

						</span>
					</button>

					<button id="theme-toggle" class="layout-header__icon-button common-focus-ring" role="switch" aria-label="Dark mode" aria-checked="false">
						<span class="layout-header__theme-icon layout-header__theme-icon--dark" aria-hidden="true">
							<svg fill="currentColor" viewBox="0 0 24 24">
    <path fill-rule="evenodd" d="M8.009 4.549C8.003 4.699 8 4.849 8 5c0 6.075 4.925 11 11 11 .151 0 .302-.004.451-.01l1.962-.078-1.09 1.633A9.993 9.993 0 0 1 12 22C6.477 22 2 17.523 2 12a9.993 9.993 0 0 1 4.455-8.323l1.633-1.09-.08 1.962Zm-1.911 2.05A7.97 7.97 0 0 0 4 12a8 8 0 0 0 13.4 5.901C11.5 17.177 6.821 12.5 6.098 6.6Z" clip-rule="evenodd"></path>
    <path d="m17 4 1 2 2 1-2 1-1 2-1-2-2-1 2-1 1-2Z"></path>
</svg>

						</span>
						<span class="layout-header__theme-icon layout-header__theme-icon--light" aria-hidden="true">
							<svg fill="currentColor" viewBox="0 0 24 24">
	<path d="M13 22h-2v-3h2v3Z"></path>
	<path d="m6.343 16.242.707.708.708.707-2.122 2.121-1.414-1.414 2.12-2.122Z"></path>
	<path d="m17.657 16.242 2.121 2.122-1.414 1.414-2.122-2.12.708-.708.707-.708Z"></path>
	<path fill-rule="evenodd" d="M12 7a5 5 0 1 1 0 10 5 5 0 0 1 0-10Zm0 2a3 3 0 1 0 0 6 3 3 0 0 0 0-6Z" clip-rule="evenodd"></path>
	<path d="M5 13H2v-2h3v2Z"></path>
	<path d="M22 13h-3v-2h3v2Z"></path>
	<path d="m5.636 4.222 2.122 2.12-.708.708-.707.708-2.121-2.122 1.414-1.414Z"></path>
	<path d="m18.364 4.222 1.414 1.414-2.12 2.122-.708-.708-.708-.707 2.122-2.121Z"></path>
	<path d="M13 5h-2V2h2v3Z"></path>
</svg>
						</span>
					</button>
				</div>

				<script>
					(function () {
	const menu = document.querySelector(".layout-header__menu");
	const toggle = menu.querySelector(".layout-header__menu-toggle");
	const mobileQuery = window.matchMedia("(max-width: 767px)");

	function syncOpenState(matchesMobile) {
		menu.open = !matchesMobile;
	}

	function syncMainInert() {
		document.getElementById("main")?.toggleAttribute("inert", menu.open && mobileQuery.matches);
	}

	syncOpenState(mobileQuery.matches);

	mobileQuery.addEventListener("change", (event) => {
		syncOpenState(event.matches);
		syncMainInert();
	});

	menu.addEventListener("toggle", syncMainInert);
	menu.addEventListener("keydown", (event) => {
		if (event.key === "Escape" && menu.open && mobileQuery.matches) {
			menu.open = false;
			toggle.focus();
		}
	});
})();

				</script>
			</nav>
		</header>

		<main class="layout-content" id="main" data-pagefind-body>
			
<h1 class="common-main-title">
	
</h1>

<div class="common-main-content">
	<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
	<url>
		<loc>https://fedknu.com/blog/web-frontend-resources/</loc>
		<lastmod>2016-08-03</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/wrapping-things-in-bacon/</loc>
		<lastmod>2016-09-17</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/event-streams-vs-properties/</loc>
		<lastmod>2016-09-21</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/manipulating-event-streams/</loc>
		<lastmod>2016-12-27</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/making-sense-out-of-context/</loc>
		<lastmod>2016-12-30</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/inner-workings-of-redux/</loc>
		<lastmod>2017-02-01</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/arrays-objects-and-mutations/</loc>
		<lastmod>2017-03-06</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/dom-bom-revisited/</loc>
		<lastmod>2017-08-06</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/simple-observable-implementation/</loc>
		<lastmod>2017-08-06</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/getting-clever-with-array-reduce/</loc>
		<lastmod>2017-09-06</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/dom-traversal-manipulation/</loc>
		<lastmod>2018-05-08</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/async-testing/</loc>
		<lastmod>2019-01-09</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/focusable-elements-macos/</loc>
		<lastmod>2019-10-19</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/focusing-skipping-tests/</loc>
		<lastmod>2020-01-23</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/code-reviewing-checklist/</loc>
		<lastmod>2020-03-12</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/jira-search-engine/</loc>
		<lastmod>2020-04-21</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/web-frontend-devtools/</loc>
		<lastmod>2021-11-28</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/sublimetext-prettier-eslint/</loc>
		<lastmod>2022-03-12</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/links-vs-buttons/</loc>
		<lastmod>2024-03-05</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/migration-gastsby-to-11ty/</loc>
		<lastmod>2025-07-09</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/defaults/</loc>
		<lastmod>2025-07-19</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/mental-model-elm-architecture/</loc>
		<lastmod>2025-07-22</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/blocking-distracting-sites-mac/</loc>
		<lastmod>2025-09-19</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/engineering-to-pure-maths-self-study-roadmap/</loc>
		<lastmod>2026-01-06</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/using-sublime-text-in-2026/</loc>
		<lastmod>2026-04-03</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/blog/adding-dark-mode-to-11ty-blog/</loc>
		<lastmod>2026-04-29</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/about/</loc>
		<lastmod>2026-10-02</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/</loc>
		<lastmod>2026-10-02</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/now/</loc>
		<lastmod>2026-10-02</lastmod>
	</url>
	<url>
		<loc>https://fedknu.com/uses/</loc>
		<lastmod>2026-10-02</lastmod>
	</url>
</urlset>

</div>

		</main>

		<pagefind-modal></pagefind-modal>

		<script>
			(function () {
	const toggle = document.getElementById("theme-toggle");
	const { readSavedTheme, saveTheme, applyTheme } = window.siteTheme;
	let hasChosenTheme = readSavedTheme() !== null;

	function updateTheme(theme) {
		applyTheme(theme);
		toggle.setAttribute("aria-checked", String(theme === "dark"));
	}

	updateTheme(document.documentElement.getAttribute("data-theme"));

	toggle.addEventListener("click", () => {
		const newTheme = document.documentElement.getAttribute("data-theme") === "dark" ? "light" : "dark";
		updateTheme(newTheme);
		saveTheme(newTheme);
		hasChosenTheme = true;
	});

	window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (event) => {
		if (!hasChosenTheme) {
			updateTheme(event.matches ? "dark" : "light");
		}
	});
})();

		</script>
		<script>
			(function () {
	const button = document.getElementById("search-button");
	const modal = document.querySelector("pagefind-modal");
	const fileLoads = new Map();

	function loadPagefind() {
		return Promise.all([
			loadFile("link", { rel: "stylesheet", href: "/pagefind/pagefind-component-ui.css" }, document.head),
			loadFile("script", { src: "/pagefind/pagefind-component-ui.js" }, document.body)
		]);
	}

	function loadFile(tagName, attributes, parent) {
		const url = attributes.href ?? attributes.src;

		if (!fileLoads.has(url)) {
			const element = Object.assign(document.createElement(tagName), attributes);
			const fileLoad = new Promise((resolve, reject) => {
				element.onload = resolve;
				element.onerror = () => {
					element.remove();
					fileLoads.delete(url);
					reject(new Error(`Could not load ${url}`));
				};
			});
			fileLoads.set(url, fileLoad);
			parent.append(element);
		}

		return fileLoads.get(url);
	}

	function preloadPagefind() {
		loadPagefind().catch(() => {});
	}

	function openSearch() {
		loadPagefind()
			.then(() => modal.open())
			.catch(() => {
				location.href = `https://duckduckgo.com/?q=${encodeURIComponent(`site:${location.hostname} `)}`;
			});
	}

	// Pagefind search UI lazy loading:
	// Pagefind's UI (~46 KB gzipped) is only fetched once someone shows intent to search.
	// Hovering or focusing the button starts the download so it's usually ready by the time they click,
	// and clicking waits for it in case it isn't (e.g. on touch devices).
	button.addEventListener("pointerenter", preloadPagefind);
	button.addEventListener("focus", preloadPagefind);
	button.addEventListener("click", openSearch);
})();

		</script>
	</body>
</html>
