Files
kennethreitz ce93f429a2 Add Knowledge: the vault's reference shelf, crosslinked across the site
Publish the Obsidian vault's Knowledge folder as /knowledge (881 notes,
67 folders), with a Knowledge item in the nav and footer.

- scripts/import_knowledge.py regenerates data/knowledge from the vault:
  slugged paths, folder notes as index pages, wikilinks resolved to site
  links (or plain text), callouts, highlights, and Dataview tables
  rendered statically. Personal notes are withheld via an exclusion
  list plus a privacy guard.
- tuftecms/core/knowledge.py builds a concept index from note titles and
  aliases. First mentions on ordinary pages link to their Knowledge note
  (capped, never in headings, code, links, or sidenotes); Knowledge pages
  list related notes and where they're mentioned across the site; other
  pages get a Related Knowledge block.
- Knowledge URLs join sitemap.xml (so the sweep test covers them), never
  displace existing legacy slugs, list alphabetically, and mermaid
  diagrams render client-side only on pages that have them.
2026-10-18 20:08:46 -04:00

629 lines
33 KiB
HTML

<!doctype html>
<html lang="en" class="loaded">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>{% block title %}{{ title }} - Kenneth Reitz{% endblock %}</title>
<!-- SEO and Meta -->
<meta name="description" content="{% block description %}Kenneth Reitz - Creator of Requests and Certifi, trusted by millions of developers worldwide. Thoughts on technology, philosophy, and building software for humans.{% endblock %}" />
<meta name="author" content="Kenneth Reitz" />
<link rel="canonical" href="{% block canonical_url %}https://kennethreitz.org{{ request.path if request.path != '/' else '' }}{% endblock %}" />
<!-- Mobile & App Meta -->
<meta name="theme-color" content="#fffff8" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#0d1117" media="(prefers-color-scheme: dark)" />
<link rel="apple-touch-icon" sizes="180x180" href="/static/images/apple-touch-icon.png" />
<link rel="icon" href="data:," />
<!-- OpenGraph -->
<meta property="og:title" content="{% block og_title %}{{ title }} - Kenneth Reitz{% endblock %}" />
<meta property="og:description" content="{% block og_description %}Creator of Requests and Certifi - libraries trusted by millions of developers worldwide{% endblock %}" />
<meta property="og:type" content="{% block og_type %}website{% endblock %}" />
<meta property="og:url" content="{% block og_url %}https://kennethreitz.org{% endblock %}" />
<meta property="og:image" content="{% block og_image %}https://kennethreitz.org/static/images/social-card.jpg{% endblock %}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="{% block og_image_alt %}Kenneth Reitz - Software developer and open source creator{% endblock %}" />
<meta property="og:site_name" content="Kenneth Reitz" />
<meta property="og:locale" content="en_US" />
{% block extra_meta %}{% endblock %}
<!-- Identity verification (IndieWeb / Mastodon) -->
<link rel="me" href="https://github.com/kennethreitz" />
<link rel="me" href="https://twitter.com/kennethreitz42" />
<!-- Twitter Card -->
<meta name="twitter:card" content="{% block twitter_card %}summary_large_image{% endblock %}" />
<meta name="twitter:creator" content="@kennethreitz42" />
<meta name="twitter:title" content="{% block twitter_title %}{{ title }} - Kenneth Reitz{% endblock %}" />
<meta name="twitter:description" content="{% block twitter_description %}Creator of Requests and Certifi - libraries trusted by millions of developers worldwide{% endblock %}" />
<meta name="twitter:image" content="{% block twitter_image %}https://kennethreitz.org/static/images/social-card.jpg{% endblock %}" />
<!-- RSS Feed -->
<link rel="alternate" type="application/rss+xml" title="Kenneth Reitz - Essays &amp; AI Writings" href="/feed.xml" />
<!-- Preload critical resources -->
<link rel="preload" href="/static/tufte/tufte.css" as="style" />
<link rel="preload" href="/static/custom.css?v={{ static_v }}" as="style" />
<link rel="preload" href="/static/tufte/et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff" as="font" type="font/woff" crossorigin />
<link rel="preload" href="/static/tufte/et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff" as="font" type="font/woff" crossorigin />
<!-- Tufte CSS -->
<link rel="stylesheet" href="/static/tufte/tufte.css" />
<!-- Custom Site CSS -->
<link rel="stylesheet" href="/static/custom.css?v={{ static_v }}" />
<!-- Site CSS (layout, nav, dark mode, etc.) -->
<link rel="stylesheet" href="/static/site.css?v={{ static_v }}" />
<!-- Structured Data (JSON-LD) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "{% block schema_type %}WebSite{% endblock %}",
"name": "{% block schema_name %}Kenneth Reitz{% endblock %}",
"url": "https://kennethreitz.org{% block schema_url %}/{% endblock %}",
"description": "{% block schema_description %}Kenneth Reitz - Creator of Requests and Certifi, trusted by millions of developers worldwide. Thoughts on technology, philosophy, and building software for humans.{% endblock %}",
"author": {
"@type": "Person",
"name": "Kenneth Reitz",
"url": "https://kennethreitz.org",
"sameAs": [
"https://github.com/kennethreitz",
"https://twitter.com/kennethreitz42"
],
"jobTitle": "Python Developer",
"worksFor": {
"@type": "Organization",
"name": "Independent"
},
"knowsAbout": [
"Python Programming",
"API Design",
"Software Architecture",
"Open Source Development",
"Artificial Intelligence",
"Mental Health Advocacy"
]
},
"publisher": {
"@type": "Person",
"name": "Kenneth Reitz",
"url": "https://kennethreitz.org"
}{% block schema_extra %}{% endblock %}
}
</script>
{% block extra_head %}{% endblock %}
<!-- Breadcrumb Structured Data -->
{% if current_path and current_path != '/' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://kennethreitz.org/"
}{% if breadcrumbs %}{% for crumb in breadcrumbs %},
{
"@type": "ListItem",
"position": {{ loop.index + 1 }},
"name": "{{ crumb.name }}",
"item": "https://kennethreitz.org{{ crumb.url }}"
}{% endfor %}{% elif current_path %}{% set path_parts = current_path.strip('/').split('/') %}{% for part in path_parts if part %},
{
"@type": "ListItem",
"position": {{ loop.index + 1 }},
"name": "{{ part | replace('-', ' ') | replace('_', ' ') | title }}",
"item": "https://kennethreitz.org/{{ path_parts[:loop.index]|join('/') }}"
}{% endfor %}{% endif %}
]
}
</script>
{% endif %}
<!-- Analytics -->
{% if not (config.get('DISABLE_ANALYTICS') or request.environ.get('DISABLE_ANALYTICS')) %}
<!-- Umami (self-hosted) -->
<script defer src="https://analytics.kennethreitz.org/script.js" data-website-id="41b1fd15-82b1-4211-aeff-b3caa2d50ea3"></script>
{% endif %}
<!-- Minimal syntax styling: comments only, keeps code literary -->
</head>
<body>
<!-- Apply theme + color scheme before first paint to avoid a flash
of the wrong mode. Runs here, not at the end of the body. -->
<script>
(function() {
const body = document.body;
const savedTheme = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (savedTheme) {
body.classList.add(savedTheme);
} else if (prefersDark) {
body.classList.add('dark-mode');
} else {
body.classList.add('light-mode');
}
const lightColorSchemes = [
'scheme-ocean',
'scheme-forest',
'scheme-sunset',
'scheme-lavender',
'scheme-rose',
'scheme-sage',
'scheme-amber'
];
// Change scheme occasionally (20% chance on page load)
let scheme = localStorage.getItem('current-color-scheme');
if (!scheme || Math.random() < 0.2) {
scheme = lightColorSchemes[Math.floor(Math.random() * lightColorSchemes.length)];
localStorage.setItem('current-color-scheme', scheme);
}
body.classList.add(scheme);
})();
</script>
<a class="skip-link" href="#main-content">Skip to content</a>
<!-- Reading progress bar -->
<div class="reading-progress" id="reading-progress"></div>
{% set github_base = 'https://github.com/kennethreitz/kennethreitz.org' %}
{% if github_file %}
<a href="{{ github_base }}/blob/main/{{ github_file }}" class="github-corner" aria-label="View source on GitHub" target="_blank">
{% else %}
<a href="{{ github_base }}" class="github-corner" aria-label="View source on GitHub" target="_blank">
{% endif %}
<img src="/static/images/github-banner.svg" alt="View on GitHub" class="github-corner-img">
</a>
<button id="theme-toggle" class="theme-toggle" aria-label="Toggle dark mode">
<svg class="sun-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
<svg class="moon-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
<article>
<header>
<nav>
<a href="/">Home</a>
<a href="/archive">Archive</a>
<a href="/search">Search</a>
<div class="nav-dropdown">
<span class="nav-dropdown-trigger" tabindex="0" role="button" aria-haspopup="true">Themes</span>
<div class="nav-dropdown-content" id="themes-dropdown">
{% for t in nav_themes %}
<div class="tree-item tree-file">{% if t.icon %}<img src="{{ t.icon }}" class="tree-item-icon" alt="">{% endif %}<a href="{{ t.path }}">{{ t.name }}</a></div>
{% endfor %}
<div class="tree-item tree-folder" style="border-top: 1px solid rgba(128,128,128,0.2); margin-top: 0.25rem; padding-top: 0.25rem;"><a href="/themes">All Themes →</a></div>
</div>
</div>
<div class="nav-dropdown">
<a href="/knowledge" class="nav-dropdown-trigger" aria-haspopup="true">Knowledge</a>
<div class="nav-dropdown-content" id="knowledge-dropdown">
{% for k in nav_knowledge %}
<div class="tree-item tree-folder">{% if k.icon %}<img src="{{ k.icon }}" class="tree-item-icon" alt="">{% endif %}<a href="{{ k.path }}">{{ k.name }}</a></div>
{% endfor %}
<div class="tree-item tree-folder" style="border-top: 1px solid rgba(128,128,128,0.2); margin-top: 0.25rem; padding-top: 0.25rem;"><a href="/knowledge">All Knowledge →</a></div>
</div>
</div>
<div class="nav-dropdown">
<span class="nav-dropdown-trigger" style="font-style: italic;" tabindex="0" role="button" aria-haspopup="true">etc.</span>
<div class="nav-dropdown-content" id="browse-dropdown">
{% for item in nav_browse %}
<div class="tree-item {{ 'tree-folder' if item.is_dir else 'tree-file' }}">{% if item.icon %}<img src="{{ item.icon }}" class="tree-item-icon" alt="">{% endif %}<a href="{{ item.path }}">{{ item.name }}</a></div>
{% endfor %}
</div>
</div>
</nav>
{% if current_path and current_path != '/' %}
{% set path_parts = current_path.strip('/').split('/') %}
{% if path_parts|length > 1 %}
<div class="breadcrumbs">
<a href="/">~</a>
{% for part in path_parts[:-1] %}
<span class="breadcrumb-separator">/</span>
{% set partial_path = '/' + path_parts[:loop.index]|join('/') %}
<a href="{{ partial_path }}">{{ part|replace('-', ' ')|replace('_', ' ')|title }}</a>
{% endfor %}
</div>
{% endif %}
{% endif %}
</header>
<main id="main-content">
{% block content %}{% endblock %}
</main>
<footer>
<div class="footer-content">
<nav class="footer-map">
<a href="/essays">Essays</a><span class="sep">·</span><a href="/themes">Themes</a><span class="sep">·</span><a href="/knowledge">Knowledge</a><span class="sep">·</span><a href="/software">Software</a><span class="sep">·</span><a href="/photography">Photography</a><span class="sep">·</span><a href="/music">Music</a><span class="sep">·</span><a href="/contact">Contact</a><span class="sep">·</span><a href="/feed.xml">RSS</a>
</nav>
<div class="footer-note">
<p>&copy; {{ "now"|strftime("%Y") }} Kenneth Reitz. <a href="https://kjvstudy.org/topics/Love">Made with love</a>.</p>
</div>
</div>
</footer>
</article>
{% block extra_scripts %}{% endblock %}
<!-- Progressive enhancements: link previews, heading anchors, theme-color sync -->
<script defer src="/static/js/enhance.js?v={{ static_v }}"></script>
<script>
// Mermaid diagrams (used by Knowledge notes): load the renderer only when a page has one.
document.addEventListener('DOMContentLoaded', function () {
var blocks = document.querySelectorAll('pre > code.language-mermaid');
if (!blocks.length) return;
blocks.forEach(function (code) {
var div = document.createElement('div');
div.className = 'mermaid';
div.textContent = code.textContent;
code.parentNode.replaceWith(div);
});
import('https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs').then(function (m) {
var dark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
m.default.initialize({ startOnLoad: false, theme: dark ? 'dark' : 'neutral', securityLevel: 'strict' });
m.default.run({ querySelector: '.mermaid' });
}).catch(function () {});
});
</script>
<!-- Theme Toggle (theme itself is applied at the top of the body) -->
<script>
(function() {
const themeToggle = document.getElementById('theme-toggle');
const body = document.body;
themeToggle.addEventListener('click', function() {
if (body.classList.contains('light-mode')) {
body.classList.remove('light-mode');
body.classList.add('dark-mode');
localStorage.setItem('theme', 'dark-mode');
} else {
body.classList.remove('dark-mode');
body.classList.add('light-mode');
localStorage.setItem('theme', 'light-mode');
}
});
})();
</script>
<script>
// Main DOMContentLoaded handler
document.addEventListener('DOMContentLoaded', function() {
// First priority: Add loaded class to reveal content
document.documentElement.classList.add('loaded');
// Find all pre elements (code blocks)
const codeBlocks = document.querySelectorAll('pre');
// Function to add subtle comment highlighting
function highlightComments(pre) {
const code = pre.querySelector('code') || pre;
let html = code.innerHTML;
// Python/Shell comments (# comment) - both line start and inline
html = html.replace(/(^|\s+)(#.*)$/gm, '$1<span style="color: #888; font-style: italic;">$2</span>');
// Python docstrings (""" or ''') — italic but readable, not grayed out
html = html.replace(/("""[\s\S]*?""")/g, '<span style="font-style: italic;">$1</span>');
html = html.replace(/('''[\s\S]*?''')/g, '<span style="font-style: italic;">$1</span>');
// Python class names (class ClassName)
html = html.replace(/(\bclass\s+)([A-Za-z_][A-Za-z0-9_]*)/g, '$1<span style="font-weight: bold;">$2</span>');
// Variable assignment targets (name = ...)
html = html.replace(/^(\s*)([a-zA-Z_][a-zA-Z0-9_]*)(\s*=\s)/gm, '$1<span style="font-weight: bold;">$2</span>$3');
// Shell prompt ($ command) - bold the $
html = html.replace(/^(\$ )/gm, '<span style="font-weight: bold;">$1</span>');
// JavaScript/C++/Java comments (// comment) - only at line start, not in URLs
html = html.replace(/^(\s*\/\/.*)$/gm, '<span style="color: #888; font-style: italic;">$1</span>');
// CSS/C/Java block comments (/* comment */)
html = html.replace(/(\/\*[\s\S]*?\*\/)/g, '<span style="color: #888; font-style: italic;">$1</span>');
// HTML comments (<!-- comment -->)
html = html.replace(/(&lt;!--[\s\S]*?--&gt;)/g, '<span style="color: #888; font-style: italic;">$1</span>');
code.innerHTML = html;
}
codeBlocks.forEach(function(pre) {
// Add subtle comment highlighting first
highlightComments(pre);
// Skip if already wrapped
if (pre.parentElement.classList.contains('code-block-wrapper')) {
return;
}
// Create wrapper div
const wrapper = document.createElement('div');
wrapper.className = 'code-block-wrapper';
// Create copy button
const copyButton = document.createElement('button');
copyButton.className = 'copy-button';
copyButton.textContent = 'Copy';
copyButton.setAttribute('aria-label', 'Copy code to clipboard');
// Add click handler
copyButton.addEventListener('click', async function() {
try {
// Get the text content of the pre element
const codeText = pre.textContent || pre.innerText;
// Use modern clipboard API if available
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(codeText);
} else {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = codeText;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
document.execCommand('copy');
textArea.remove();
}
// Show feedback
const originalText = copyButton.textContent;
copyButton.textContent = 'Copied!';
copyButton.classList.add('copied');
setTimeout(function() {
copyButton.textContent = originalText;
copyButton.classList.remove('copied');
}, 2000);
} catch (err) {
console.error('Failed to copy code: ', err);
// Show error feedback
const originalText = copyButton.textContent;
copyButton.textContent = 'Failed';
setTimeout(function() {
copyButton.textContent = originalText;
}, 2000);
}
});
// Wrap the pre element and add the button
pre.parentNode.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
wrapper.appendChild(copyButton);
});
// Initialize reading progress and article icons
const currentPath = window.location.pathname;
const isIndexPage = currentPath === '/' ||
currentPath === '/archive' ||
currentPath.endsWith('/index') ||
currentPath.match(/^\/(archive|search|sidenotes|outlines|connections|quotes|terms|graph|random)\/?$/);
if (!isIndexPage) {
// Load article icons
loadArticleIcons();
}
// Check if this is a content page (essay/article) rather than an index
const isContentPage = document.querySelector('main').textContent.length > 2000;
if (isContentPage) {
window.addEventListener('scroll', updateReadingProgress);
window.addEventListener('resize', updateReadingProgress);
updateReadingProgress(); // Initial call
}
// Lazy loading for images
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
if (img.dataset.src) {
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
}
});
}, {
rootMargin: '50px 0px'
});
// Apply lazy loading to all images with data-src
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
}
});
// Reading progress indicator
function updateReadingProgress() {
const progressBar = document.getElementById('reading-progress');
if (!progressBar) return;
const mainContent = document.querySelector('main');
if (!mainContent) return;
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight;
const winHeight = window.innerHeight;
const scrollPercent = scrollTop / (docHeight - winHeight);
const scrollPercentRounded = Math.round(scrollPercent * 100);
progressBar.style.width = scrollPercentRounded + '%';
// Only show progress bar if there's meaningful content to scroll
if (docHeight > winHeight * 1.5) {
progressBar.style.opacity = '1';
} else {
progressBar.style.opacity = '0';
}
}
// Load icons for article links at the beginning of paragraphs
function loadArticleIcons() {
// Find all paragraphs that start with a link
const paragraphs = document.querySelectorAll('p');
paragraphs.forEach(paragraph => {
// Skip paragraphs that are sidenotes or contain sidenote elements
if (paragraph.classList.contains('sidenote-entry') ||
paragraph.querySelector('.sidenote') ||
paragraph.querySelector('.marginnote') ||
paragraph.querySelector('.margin-toggle')) {
return;
}
// Skip paragraphs inside directory listings or item lists
if (paragraph.closest('.items-list') || paragraph.closest('.directory-listing') || paragraph.closest('.item')) {
return;
}
// Check if the paragraph starts with a link (no text before it)
const firstNode = paragraph.firstChild;
let firstElement = null;
// Skip any whitespace/text nodes at the beginning
for (let node = firstNode; node; node = node.nextSibling) {
if (node.nodeType === Node.ELEMENT_NODE) {
firstElement = node;
break;
} else if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
// If there's non-whitespace text before any element, don't add icon
return;
}
}
// Check if first element is a link, or if it's a strong/b tag containing a link
let linkElement = null;
if (firstElement && firstElement.tagName === 'A') {
linkElement = firstElement;
} else if (firstElement && (firstElement.tagName === 'STRONG' || firstElement.tagName === 'B')) {
// Check if the strong/b tag contains a link as its first child
const strongFirstChild = firstElement.firstElementChild;
if (strongFirstChild && strongFirstChild.tagName === 'A') {
linkElement = strongFirstChild;
}
}
if (linkElement) {
const href = linkElement.getAttribute('href');
// Check if it's an internal link
if (href && href.startsWith('/') && !href.startsWith('//')) {
// Skip if icon already exists
if (paragraph.querySelector('.article-link-icon')) return;
// Fetch icon with simple error handling
fetch(`/api/icon${href}`)
.then(response => response.ok ? response.json() : null)
.then(data => {
if (data && data.success && data.icon) {
// Validate the data URL format
if (!data.icon.startsWith('data:image/svg+xml;base64,')) {
return;
}
try {
// Decode the SVG to insert as inline SVG instead of data URL
const base64Part = data.icon.split(',')[1];
const svgContent = atob(base64Part);
// Create a container div for the SVG
const iconContainer = document.createElement('div');
iconContainer.className = 'article-link-icon';
iconContainer.style.cssText = `
display: inline-block;
width: 20px;
height: 20px;
margin-right: 0.75rem;
margin-left: -2.25rem;
margin-top: -0.25em;
vertical-align: middle;
flex-shrink: 0;
`;
// Add CSS to hide on mobile and tablet - only add once
if (!window.articleIconStylesAdded) {
const style = document.createElement('style');
style.textContent = `
@media (max-width: 760px) {
.article-link-icon,
.article-link-icon.fallback {
display: none !important;
visibility: hidden !important;
}
}
`;
document.head.appendChild(style);
window.articleIconStylesAdded = true;
}
// Insert the SVG content directly
iconContainer.innerHTML = svgContent;
// Insert icon before the first element (which contains the link)
paragraph.insertBefore(iconContainer, firstElement);
// Add some styling to the paragraph
paragraph.style.position = 'relative';
} catch (e) {
// If decoding fails, skip silently
}
}
})
.catch(() => {});
}
}
});
}
</script>
<!-- Client-side oEmbed -->
<script>
(function() {
document.querySelectorAll('.oembed-placeholder').forEach(function(el) {
var url = el.getAttribute('data-oembed-url');
if (!url) return;
fetch('/api/oembed?url=' + encodeURIComponent(url))
.then(function(r) { return r.ok ? r.json() : Promise.reject(); })
.then(function(data) {
if (data.html) {
el.innerHTML = data.html;
}
})
.catch(function() {
// Fallback link is already in place — do nothing.
});
});
})();
</script>
</body>
</html>