{
    "ready": true,
    "site": {
        "id": 0,
        "domain": "haripm.com",
        "display_name": "Hari's Weblog",
        "primary_country_code": "",
        "category_name": "Personal"
    },
    "metrics": {
        "global_rank": 15985,
        "country_rank": 8377,
        "category_rank": 73,
        "daily_pageviews_per_visitor": 4.01,
        "daily_time_on_site_seconds": 349,
        "bounce_rate": 30.18,
        "search_visits_percent": 41.52,
        "total_sites_linking_in": 1,
        "monthly_unique_visitors": 151,
        "recorded_at": "2026-04-03 07:22:23"
    },
    "audit": {
        "score": 96
    },
    "traffic_sources": {
        "direct_percent": 28.25,
        "search_percent": 36.56,
        "social_percent": 6.69,
        "referral_percent": 12.4,
        "email_percent": 7.23,
        "paid_percent": 8.87
    },
    "seo_profile": {
        "backlinks_total": 1,
        "referring_domains": 1,
        "dofollow_backlinks_percent": 100,
        "organic_keywords": 69,
        "indexed_pages": 40,
        "page_speed_score": 100,
        "mobile_friendliness_score": 91,
        "authority_score": 46,
        "spam_risk_score": 15
    },
    "crawl_report": {
        "robots_status": 200,
        "sitemap_status": 200,
        "sitemap_total_urls": 1,
        "crawl_blocked": false,
        "crawl_blocked_by": "",
        "crawl_blocked_reason": "",
        "notes": [],
        "created_at": "2026-04-03 07:22:23"
    },
    "keywords": [
        {
            "keyword": "Hari's Weblog",
            "position": 19,
            "search_engine": "Estimated",
            "checked_at": "2026-04-13 16:24:26",
            "is_estimated": true
        },
        {
            "keyword": "Hari's Weblog personal",
            "position": 21,
            "search_engine": "Estimated",
            "checked_at": "2026-04-13 16:24:26",
            "is_estimated": true
        },
        {
            "keyword": "Hari's Weblog reviews",
            "position": 23,
            "search_engine": "Estimated",
            "checked_at": "2026-04-13 16:24:26",
            "is_estimated": true
        },
        {
            "keyword": "hari",
            "position": 25,
            "search_engine": "Estimated",
            "checked_at": "2026-04-13 16:24:26",
            "is_estimated": true
        },
        {
            "keyword": "weblog",
            "position": 27,
            "search_engine": "Estimated",
            "checked_at": "2026-04-13 16:24:26",
            "is_estimated": true
        },
        {
            "keyword": "haripm",
            "position": 29,
            "search_engine": "Estimated",
            "checked_at": "2026-04-13 16:24:26",
            "is_estimated": true
        },
        {
            "keyword": "about",
            "position": 31,
            "search_engine": "Estimated",
            "checked_at": "2026-04-13 16:24:26",
            "is_estimated": true
        },
        {
            "keyword": "blog",
            "position": 33,
            "search_engine": "Estimated",
            "checked_at": "2026-04-13 16:24:26",
            "is_estimated": true
        }
    ],
    "rating": {
        "overall": 64,
        "label": "Healthy",
        "breakdown": [
            {
                "label": "Technical foundation",
                "score": 18,
                "max": 18
            },
            {
                "label": "Authority & trust",
                "score": 14,
                "max": 30
            },
            {
                "label": "Reach & market presence",
                "score": 3,
                "max": 18
            },
            {
                "label": "Search visibility",
                "score": 3,
                "max": 12
            },
            {
                "label": "Engagement & retention",
                "score": 9,
                "max": 10
            },
            {
                "label": "Channels & diversification",
                "score": 4,
                "max": 6
            },
            {
                "label": "Registry stability",
                "score": 3,
                "max": 6
            },
            {
                "label": "Quality system",
                "score": 100,
                "max": 100
            },
            {
                "label": "Reputation system",
                "score": 44,
                "max": 100
            },
            {
                "label": "Safety system",
                "score": 100,
                "max": 100
            },
            {
                "label": "Evidence confidence",
                "score": 100,
                "max": 100
            }
        ],
        "authority_score": 46,
        "quality_score": 100,
        "reputation_score": 44,
        "safety_score": 100,
        "confidence_score": 100,
        "fraud_score": 1,
        "authority_signals": {
            "backlinks": 1,
            "referring_domains": 1,
            "organic_keywords": 69,
            "indexed_pages": 40,
            "monthly_visitors": 151,
            "global_rank": 15985,
            "engagement_score": 82,
            "crawl_quality_score": 100,
            "brand_completeness_score": 69,
            "link_diversity_score": 92,
            "technical_reliability_score": 97,
            "whois_score": 63,
            "whois_age_years": 2,
            "whois_stability_score": 100,
            "spam_penalty": 0
        },
        "whois_signals": {
            "age_years": 2,
            "days_to_expiry": 376,
            "days_since_last_registry_update": 15,
            "stability_score": 100,
            "registrar_changes": 0,
            "ownership_changes": 0,
            "nameserver_changes": 0,
            "status_changes": 0,
            "history_entries": 2,
            "privacy_protected": false,
            "dnssec_enabled": false,
            "has_registrant_country": false,
            "registrant_country": "",
            "nameserver_count": 2,
            "status_count": 1
        }
    },
    "authority_score": 46,
    "trust_score": 77,
    "domain_tags": {
        "primary_tag": "T",
        "primary_tag_score": 84,
        "primary_candidate": "T",
        "primary_candidate_score": 84,
        "tag_codes": "T",
        "tags": [
            {
                "code": "T",
                "label": "Trusted",
                "tone": "good",
                "description": "Strong trust, stability, and low-risk signals were detected.",
                "reason": "Low spam indicators plus strong trust, quality, registry, and stability signals were detected.",
                "message": "The site shows a reasonably trustworthy and stable profile.",
                "priority": 84,
                "score": 84,
                "match_percent": 84,
                "threshold_band": "strong"
            }
        ],
        "tag_breakdown": [
            {
                "code": "T",
                "label": "Trusted",
                "tone": "good",
                "description": "Strong trust, stability, and low-risk signals were detected.",
                "reason": "Low spam indicators plus strong trust, quality, registry, and stability signals were detected.",
                "message": "The site shows a reasonably trustworthy and stable profile.",
                "priority": 84,
                "score": 84,
                "match_percent": 84,
                "threshold_band": "strong"
            },
            {
                "code": "Uncertain",
                "label": "Uncertain",
                "tone": "unknown",
                "description": "External checks stayed inconclusive, so the model avoided a harder verdict.",
                "reason": "",
                "message": "The evidence does not currently look notably uncertain.",
                "priority": 18,
                "score": 18,
                "match_percent": 18,
                "threshold_band": "none"
            },
            {
                "code": "Infra",
                "label": "Risky infrastructure",
                "tone": "caution",
                "description": "The hosting / registrar / nameserver neighbourhood looks unusually risky.",
                "reason": "The infrastructure neighbourhood looks riskier than normal.",
                "message": "Infrastructure risk does not currently stand out.",
                "priority": 6,
                "score": 6,
                "match_percent": 6,
                "threshold_band": "none"
            },
            {
                "code": "C",
                "label": "Caution",
                "tone": "caution",
                "description": "Signals are mixed or weak, so this domain should be treated carefully.",
                "reason": "Review carefully: mixed trust signals.",
                "message": "The current crawl does not show a meaningful caution match.",
                "priority": 0,
                "score": 0,
                "match_percent": 0,
                "threshold_band": "none"
            },
            {
                "code": "Crypto",
                "label": "Crypto drainer risk",
                "tone": "toxic",
                "description": "Wallet-connect or seed-phrase theft patterns were detected.",
                "reason": "Wallet-connect or seed-phrase theft patterns were detected.",
                "message": "No meaningful crypto-drainer signals were detected.",
                "priority": 0,
                "score": 0,
                "match_percent": 0,
                "threshold_band": "none"
            }
        ],
        "nsfw_score": 0,
        "trust_score": 78,
        "manual": {
            "has_changes": false,
            "verified_status": "",
            "tag_codes": "",
            "rating_delta": 0,
            "authority_delta": 0,
            "trust_delta": 0,
            "note": "",
            "adjusted_by": 0,
            "adjusted_at": "",
            "lock_scores": false,
            "lock_flags": false
        },
        "summary": "Trusted (84% match) because low spam indicators plus strong trust, quality, registry, and stability signals were detected.",
        "external_intel": [],
        "external_decision": [],
        "signal_scores": [
            {
                "label": "Strongest tag heuristic",
                "value": "T · 84%",
                "tone": "good",
                "detail": "The highest raw tag match from the heuristic engine before visibility thresholds and manual overrides."
            },
            {
                "label": "Trust score",
                "value": "78/100",
                "tone": "good",
                "detail": "Confidence derived from authority, crawl quality, stability, and risk signals."
            },
            {
                "label": "Authority score",
                "value": "46/100",
                "tone": "caution",
                "detail": "A higher authority score usually means broader reputation and backlink confidence."
            },
            {
                "label": "Spam risk",
                "value": "0/100",
                "tone": "good",
                "detail": "Lower is better. This blends spam indicators with false-positive protections for legitimate sites."
            },
            {
                "label": "Quality score",
                "value": "96/100",
                "tone": "good",
                "detail": "Based on crawl quality, content completeness, and technical evidence."
            },
            {
                "label": "Safety score",
                "value": "100/100",
                "tone": "good",
                "detail": "Higher is safer. Direct fraud signals can heavily cap this even when SEO signals look strong."
            },
            {
                "label": "Fraud score",
                "value": "0/100",
                "tone": "good",
                "detail": "Lower is better. This reflects phishing, drainer, fake-support, fake-shop, and malware signals."
            },
            {
                "label": "Infrastructure risk",
                "value": "6/100",
                "tone": "good",
                "detail": "Lower is better. This reflects the IP, registrar, and nameserver neighbourhood seen by the crawler."
            },
            {
                "label": "Evidence confidence",
                "value": "100/100",
                "tone": "good",
                "detail": "Higher means the crawler had enough pages and registry evidence to make a stronger call."
            },
            {
                "label": "External evidence",
                "value": "Low",
                "tone": "unknown",
                "detail": "Quality of the structured search and review evidence cluster."
            },
            {
                "label": "External decision",
                "value": "Inconclusive",
                "tone": "unknown",
                "detail": "How third-party evidence compares with the current candidate tag."
            },
            {
                "label": "NSFW score",
                "value": "0/100",
                "tone": "good",
                "detail": "Context-aware adult-content detection with medical / educational false-positive reduction."
            },
            {
                "label": "Registry stability",
                "value": "100/100",
                "tone": "good",
                "detail": "Based on age, expiry runway, and the amount of ownership / registrar churn."
            }
        ],
        "signal_sections": [
            {
                "title": "Registry & ownership",
                "items": [
                    {
                        "label": "Domain age",
                        "value": "2.0 years",
                        "tone": "caution",
                        "detail": "Older domains generally carry more historical trust than very new ones."
                    },
                    {
                        "label": "Stability score",
                        "value": "100/100",
                        "tone": "good",
                        "detail": "Penalised by registrar, ownership, and nameserver churn."
                    },
                    {
                        "label": "Days to expiry",
                        "value": "376",
                        "tone": "good",
                        "detail": "Very short renewal windows can be a weak trust signal."
                    },
                    {
                        "label": "Registrar / ownership changes",
                        "value": "0 / 0",
                        "tone": "good",
                        "detail": "Frequent ownership churn can weaken trust."
                    },
                    {
                        "label": "Nameserver changes",
                        "value": "0",
                        "tone": "good",
                        "detail": "Repeated infrastructure changes can indicate instability."
                    },
                    {
                        "label": "DNSSEC / privacy",
                        "value": "DNSSEC off · privacy off",
                        "tone": "caution",
                        "detail": "DNSSEC strengthens DNS trust; privacy is neutral on its own."
                    }
                ]
            },
            {
                "title": "Reputation & search evidence",
                "items": [
                    {
                        "label": "Backlinks",
                        "value": "1",
                        "tone": "unknown",
                        "detail": "Broader backlink evidence usually improves confidence."
                    },
                    {
                        "label": "Referring domains",
                        "value": "1",
                        "tone": "unknown",
                        "detail": "Unique linking domains are more useful than raw link volume."
                    },
                    {
                        "label": "Organic keywords",
                        "value": "69",
                        "tone": "caution",
                        "detail": "Search footprint helps distinguish real sites from thin shells."
                    },
                    {
                        "label": "Indexed pages",
                        "value": "40",
                        "tone": "caution",
                        "detail": "Larger index coverage usually means more evidence to classify from."
                    },
                    {
                        "label": "Brand strength",
                        "value": "69/100",
                        "tone": "good",
                        "detail": "Stronger brand signals reduce false positives for legitimate sites."
                    },
                    {
                        "label": "Risk label",
                        "value": "GOOD",
                        "tone": "unknown",
                        "detail": "This is the raw crawl / heuristic risk label feeding the tag model."
                    }
                ]
            },
            {
                "title": "Crawl, content & technicals",
                "items": [
                    {
                        "label": "HTTP status",
                        "value": "200",
                        "tone": "good",
                        "detail": "Healthy responses make classification more reliable."
                    },
                    {
                        "label": "HTTPS / speed",
                        "value": "HTTPS OK · 83 ms",
                        "tone": "good",
                        "detail": "Slow or broken technical signals weaken confidence."
                    },
                    {
                        "label": "Content words",
                        "value": "1,582",
                        "tone": "good",
                        "detail": "Thin pages are harder to trust and easier to manipulate."
                    },
                    {
                        "label": "Schema / structure",
                        "value": "0 schema · meta · H1",
                        "tone": "caution",
                        "detail": "Structured markup and basic on-page hygiene improve quality confidence."
                    },
                    {
                        "label": "Links on page",
                        "value": "41 internal · 7 external",
                        "tone": "good",
                        "detail": "Link patterns help detect thin directories and promo pages."
                    },
                    {
                        "label": "Page speed / mobile",
                        "value": "100/100 · 91/100",
                        "tone": "good",
                        "detail": "Better technical quality generally reduces low-effort site patterns."
                    },
                    {
                        "label": "Crawl access",
                        "value": "Open",
                        "tone": "good",
                        "detail": "The crawler reached the site without an anti-bot challenge."
                    }
                ]
            },
            {
                "title": "External evidence & explainability",
                "items": [
                    {
                        "label": "Decision state",
                        "value": "Inconclusive",
                        "tone": "unknown",
                        "detail": "Structured third-party evidence is still too thin, mixed, or unqualified to force a harder verdict."
                    },
                    {
                        "label": "Evidence quality",
                        "value": "Low",
                        "tone": "unknown",
                        "detail": "Blends source trust, domain matching, evidence diversity, and freshness."
                    },
                    {
                        "label": "Support vs contradiction",
                        "value": "0 / 0",
                        "tone": "unknown",
                        "detail": "Compares how much structured external evidence supports the candidate tag against evidence that contradicts it."
                    },
                    {
                        "label": "Qualified risk sources",
                        "value": "No",
                        "tone": "good",
                        "detail": "Risk tags only promote from external evidence when source diversity or source trust thresholds are met."
                    },
                    {
                        "label": "Uncertainty buffer",
                        "value": "Clear",
                        "tone": "good",
                        "detail": "Prevents thin or mixed external evidence from forcing a stronger tag than the evidence can justify."
                    }
                ]
            }
        ],
        "positives": [
            "Low registrar / ownership churn with solid registry stability.",
            "Healthy crawl quality and on-page completeness."
        ],
        "risks": []
    },
    "traffic_confidence": 60,
    "whois": {
        "current": {
            "id": 49416,
            "domain": "haripm.com",
            "source_type": "rdap",
            "rdap_url": "https://rdap.verisign.com/com/v1/domain/HARIPM.COM",
            "registrar_name": "NameCheap, Inc.",
            "registrar_handle": "1068",
            "registrant_name": "",
            "registrant_org": "",
            "registrant_country": "",
            "registrant_email": "",
            "abuse_email": "abuse@namecheap.com",
            "created_date": "2024-04-25 13:35:47",
            "updated_date": "2026-03-29 11:43:04",
            "expires_date": "2027-04-25 13:35:47",
            "nameservers_json": "[\"adi.ns.cloudflare.com\",\"logan.ns.cloudflare.com\"]",
            "status_json": "[\"client transfer prohibited\"]",
            "dnssec": "unsigned",
            "privacy_protected": 0,
            "content_hash": "2fe80e19ddc495fd5776d1f85f36cb208cfab2ee7291631ab4865cd36e61eda9",
            "history_count": 2,
            "last_checked_at": "2026-04-03 07:22:18",
            "last_changed_at": "2026-04-03 07:22:18",
            "created_at": "2026-03-20 16:23:09",
            "updated_at": "2026-04-03 07:22:18"
        },
        "history": [
            {
                "id": 79958,
                "domain": "haripm.com",
                "source_type": "rdap",
                "registrar_name": "NameCheap, Inc.",
                "registrar_handle": "1068",
                "registrant_name": "",
                "registrant_org": "",
                "registrant_country": "",
                "registrant_email": "",
                "abuse_email": "abuse@namecheap.com",
                "created_date": "2024-04-25 13:35:47",
                "updated_date": "2026-03-29 11:43:04",
                "expires_date": "2027-04-25 13:35:47",
                "nameservers_json": "[\"adi.ns.cloudflare.com\",\"logan.ns.cloudflare.com\"]",
                "status_json": "[\"client transfer prohibited\"]",
                "dnssec": "unsigned",
                "privacy_protected": 0,
                "content_hash": "2fe80e19ddc495fd5776d1f85f36cb208cfab2ee7291631ab4865cd36e61eda9",
                "checked_at": "2026-04-03 07:22:18",
                "change_summary": "Last update date changed; Expiry date changed.",
                "created_at": "2026-04-03 07:22:18"
            },
            {
                "id": 50433,
                "domain": "haripm.com",
                "source_type": "rdap",
                "registrar_name": "NameCheap, Inc.",
                "registrar_handle": "1068",
                "registrant_name": "",
                "registrant_org": "",
                "registrant_country": "",
                "registrant_email": "",
                "abuse_email": "abuse@namecheap.com",
                "created_date": "2024-04-25 13:35:47",
                "updated_date": "2025-04-01 22:31:03",
                "expires_date": "2026-04-25 13:35:47",
                "nameservers_json": "[\"adi.ns.cloudflare.com\",\"logan.ns.cloudflare.com\"]",
                "status_json": "[\"client transfer prohibited\"]",
                "dnssec": "unsigned",
                "privacy_protected": 0,
                "content_hash": "e7226d43dfac665206e838faa8cef05fb12583e533dd32d4641a26b25076ba86",
                "checked_at": "2026-03-20 16:23:09",
                "change_summary": "Initial WHOIS snapshot captured.",
                "created_at": "2026-03-20 16:23:09"
            }
        ],
        "signals": {
            "age_years": 2,
            "days_to_expiry": 376,
            "days_since_last_registry_update": 15,
            "stability_score": 100,
            "registrar_changes": 0,
            "ownership_changes": 0,
            "nameserver_changes": 0,
            "status_changes": 0,
            "history_entries": 2,
            "privacy_protected": false,
            "dnssec_enabled": false,
            "has_registrant_country": false,
            "registrant_country": "",
            "nameserver_count": 2,
            "status_count": 1
        }
    },
    "discovered_domain": {
        "id": 81254,
        "domain": "haripm.com",
        "first_seen_at": "2026-03-15 20:25:02",
        "last_crawled_at": "2026-04-03 07:22:23",
        "last_title": "Hari's Weblog",
        "last_http_status": 200,
        "discovered_from_domain": "personalsit.es",
        "depth": 0,
        "backlinks_count": 1,
        "rating_cache": 49,
        "spam_score": 24,
        "risk_label": "good",
        "category_name": "Personal",
        "primary_country_code": "",
        "internal_links_count": 41,
        "external_links_count": 7,
        "social_profiles_count": 1,
        "content_word_count": 1582,
        "title_quality_score": 79,
        "has_meta_description": 1,
        "has_h1": 1,
        "language_code": "en",
        "response_time_ms": 83,
        "robots_status": 200,
        "sitemap_status": 200,
        "sitemap_total_urls": 1,
        "quality_score": 96,
        "site_name": "",
        "canonical_domain": "",
        "favicon_present": 1,
        "schema_org_count": 0,
        "noindex_detected": 0,
        "feed_links_count": 2,
        "https_working": 1,
        "estimated_authority_score": 36,
        "trust_score": 76,
        "nsfw_score": 0,
        "overall_rank_estimate": 2542245,
        "primary_tag": "C",
        "tag_codes": "C,T,Uncertain",
        "manual_verified_status": "",
        "manual_tag_codes": "",
        "manual_rating_delta": 0,
        "manual_authority_delta": 0,
        "manual_trust_delta": 0,
        "manual_note": null,
        "manual_adjusted_by": null,
        "manual_adjusted_at": null,
        "manual_lock_scores": 0,
        "manual_lock_flags": 0,
        "crawl_blocked": 0,
        "crawl_blocked_by": "",
        "crawl_blocked_reason": null,
        "safety_score": 100,
        "fraud_score": 1,
        "legitimacy_score": 46,
        "infrastructure_risk_score": 6,
        "score_confidence": 100,
        "tag_confidence": 72,
        "category_confidence": 30,
        "deep_crawl_pages": 43,
        "resolved_ip": "91.98.131.130",
        "category_candidates_json": "[{\"category\":\"Personal\",\"score\":28},{\"category\":\"Business\",\"score\":22},{\"category\":\"Technology\",\"score\":22},{\"category\":\"Education\",\"score\":6}]",
        "page_signals_json": "[{\"path\":\"/about\",\"status\":200,\"title\":\"About\",\"word_count\":166,\"summary_text\":\"About Aboutarticle[data-astro-cid-kh7btl4r]{margin-bottom:1rem;p{margin-top:1rem}} Hari&#39;s Weblog About Slashes /about Hi! I’m Hari. I’m a 3rd year university student working towards a Bachelor’s in Messing Around with Computers at University College Dublin. Right now, I’m interested in type systems, statically typed languages, programming languages, compilers, formal methods, and things of a similar vein. If that sounds like a lot, it is! I jump between interests quite a bit, so I know a little bit about a lot of things. I don’t think that’s a bad thing, per se, but I’d like to lean into one thing and get really good at it over time, so I’m currently trying to pick up Rust. I’ve rebuilt this website from scratch more times than I’ve actually written an article for it, but maybe 7th time’s th\",\"classification_terms\":[\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/contact\",\"status\":200,\"title\":\"Contact\",\"word_count\":69,\"summary_text\":\"Contact Contactarticle[data-astro-cid-uw5kdbxl]{p,ul{margin-bottom:1rem}} Hari&#39;s Weblog About Slashes /contact If you like something I've written and want to tell me about it, or if you find something confusing and want to clarify, or for any other reason, you can contact me via the following means: Email: hello [at] [this domain] Bluesky: @haripm.com Here are some of the other identities I own and operate online. Tangled: @haripm.com GitHub: seafoamteal &copy; 2024-2026 Hari Mohan\",\"classification_terms\":[\"contact\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/slashes\",\"status\":200,\"title\":\"Slashes\",\"word_count\":89,\"summary_text\":\"Slashes Slashesarticle[data-astro-cid-wgndznux]{p{margin-bottom:1rem}} Hari&#39;s Weblog About Slashes /slashes Inspired by Slashpages, this is a catalog of “slash pages” on this site, i.e. pages of the form haripm.com/page. Have a look through them if you want to learn more about me and my blog! /about /contact /feeds — A list of RSS feeds available for this blog /colophon — What went into the design of this website: fonts, colours, and other tools /blogroll — A list of interesting blogs I follow that I think you might like too &copy; 2024-2026 Hari Mohan\",\"classification_terms\":[\"slashes\",\"about\",\"about me\",\"contact\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/feeds\",\"status\":200,\"title\":\"Feeds\",\"word_count\":157,\"summary_text\":\"Feeds Feedsarticle[data-astro-cid-3ywlqc5r]{p{margin-bottom:1rem}} Hari&#39;s Weblog About Slashes /feeds RSS is a way to follow websites you like, away from the walled gardens of traditional social media platforms. It’s really simple: you tell your RSS reader (I recommend Miniflux) that you want updates from my blog. The reader regularly checks my site for the rss.xml document(s) that I publish, which contain the details of each of my posts. When it sees a new one, it shows you the post in your own feed. Read it or ignore it, it’s up to you! I won’t know either way. Dead easy. Pasting https://haripm.com into your RSS reader should be enough for it to automatically detect each of the RSS feeds I publish, but here’s direct links to them anyway. All Content - Short notes, longer articles, and inte\",\"classification_terms\":[\"feeds\",\"about\",\"blog\",\"links\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags\",\"status\":200,\"title\":\"All Tags\",\"word_count\":34,\"summary_text\":\"All Tags All Tags h1[data-astro-cid-os4i7owy]{text-align:center;margin-bottom:1rem}ul[data-astro-cid-os4i7owy]{padding:0;list-style-type:none;display:flex;gap:1rem;flex-wrap:wrap} Hari&#39;s Weblog About Slashes All Tags algorithms blogging college docker dotfiles editors fp gleam go haskell helix linux meta month-in-review neovim nixos program-construction selfhosted sem-in-review sysadmin tech &copy; 2024-2026 Hari Mohan\",\"classification_terms\":[\"tags\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2026/01/31/jan-26\",\"status\":200,\"title\":\"Notes from January 2026\",\"word_count\":518,\"summary_text\":\"Notes from January 2026 Notes from January 2026 .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 31 Jan 2026 Notes from January 2026I’m a fan of Evan Hahn’s “Notes from Month” posts and I’ve wanted to do the same for a while now. When this month’s appeared in my RSS reader this morning, I realised that I still had just enough time to write and publish my own before the month ended! Things I Did I had 4 PRs merged into Gleam! Two of them were minor typos, one was a bugfix, and the biggest was a enhancement to the “Extract Function” code action. I love Gleam and its community, and I’m really excited to be able to contribute to the language. I’m still very new to Rust, but working on a Real Com\",\"classification_terms\":[\"2026/01/31/jan-26\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/month-in-review\",\"status\":200,\"title\":\"#month-in-review\",\"word_count\":31,\"summary_text\":\"#month-in-review #month-in-review article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-wh\",\"classification_terms\":[\"tags/month-in-review\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2026/01/17/nixmas-part-3\",\"status\":200,\"title\":\"Nixmas Pt. 3 - Friendship ended with Docker...\",\"word_count\":1351,\"summary_text\":\"Nixmas Pt. 3 - Friendship ended with Docker... Nixmas Pt. 3 - Friendship ended with Docker... .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 17 Jan 2026 Nixmas Pt. 3 - Friendship ended with Docker...Now that I have a couple of servers up and running with Caddy installed, I can go about setting up the services I want to self-host. I like running my services in OCI containers and knowing they’re well isolated from each other. Previously, I’d been using Docker, but I’ve had my eye on Podman for a while now due to its rootless, daemonless model and systemd integration. Nix has a good service module to interact with virtualisation settings, so the first thing to do is enable it. Podman # in /hosts/verdigris/container\",\"classification_terms\":[\"2026/01/17/nixmas-part-3\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":6,\"depth\":1},{\"path\":\"/tags/nixos\",\"status\":200,\"title\":\"#nixos\",\"word_count\":348,\"summary_text\":\"#nixos #nixos article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&[\",\"classification_terms\":[\"tags/nixos\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/sysadmin\",\"status\":200,\"title\":\"#sysadmin\",\"word_count\":497,\"summary_text\":\"#sysadmin #sysadmin article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]\",\"classification_terms\":[\"tags/sysadmin\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/selfhosted\",\"status\":200,\"title\":\"#selfhosted\",\"word_count\":323,\"summary_text\":\"#selfhosted #selfhosted article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbsp\",\"classification_terms\":[\"tags/selfhosted\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2026/01/17/nixmas-part-2\",\"status\":200,\"title\":\"Nixmas Pt. 2 - The Wild, Wild Web\",\"word_count\":1498,\"summary_text\":\"Nixmas Pt. 2 - The Wild, Wild Web Nixmas Pt. 2 - The Wild, Wild Web .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 17 Jan 2026 Nixmas Pt. 2 - The Wild, Wild WebIn my last post, I wrote about cleaning up the Nix flake I use to configure my laptop and promised to describe using Nix to manage remote servers in a later post. This is that post! My previous server has been hosted on Hetzner for about a year now and I’ve had a wholly positive experience, so I’m sticking with them, naturally. The NixOS Wiki has a very helpful page detailing installing NixOS on Hetzner Cloud servers. I’d planned to set up 3 different servers: one for publicly available resources (my website, currently) one for services priva\",\"classification_terms\":[\"2026/01/17/nixmas-part-2\",\"about\",\"help\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2026/01/13/nixmas-part-1\",\"status\":200,\"title\":\"Nixmas Pt. 1 - Spring (Winter) Cleaning\",\"word_count\":1301,\"summary_text\":\"Nixmas Pt. 1 - Spring (Winter) Cleaning Nixmas Pt. 1 - Spring (Winter) Cleaning .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 13 Jan 2026 Nixmas Pt. 1 - Spring (Winter) CleaningI’ve been using NixOS since June 21 2025, according to my commit history, but I never bothered to really learn Nix after setting it up. Recently, a couple of my friends started getting into Nix themselves. I couldn’t miss out on the fun, so decided to reboot my system config over the holidays, fully modularising my Nix flake and upgrading my old Ubuntu VPS to three new NixOS servers for my self-hosted experiments! To set expectations, this isn’t a proper guide. If you’re looking to set NixOS up for the first time, I recommend this\",\"classification_terms\":[\"2026/01/13/nixmas-part-1\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2026/01/04/bad-is-okay\",\"status\":200,\"title\":\"Note from 4 Jan\",\"word_count\":257,\"summary_text\":\"Note from 4 Jan Note from 4 Jan .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 4 Jan 2026 I’d really like for this website to be around in 20 years. And that means this website won’t be around in 20 years. It’ll have been Ship-of-Theseus’d out of existence multiple times over by then. It’s really quite a freeing realisation, because it means I can quit obsessing over the little details and actually do the thing that matters, which is writing for this blog. It doesn’t matter if the padding and margins are inconsistent in some places, nor does it matter that the code I use to generate this site is a bit messy and could be refactored. The only thing left five, ten, twenty years from t\",\"classification_terms\":[\"2026/01/04/bad-is-okay\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/blogging\",\"status\":200,\"title\":\"#blogging\",\"word_count\":435,\"summary_text\":\"#blogging #blogging article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]\",\"classification_terms\":[\"tags/blogging\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/meta\",\"status\":200,\"title\":\"#meta\",\"word_count\":435,\"summary_text\":\"#meta #meta article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&[d\",\"classification_terms\":[\"tags/meta\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2026/01/03/helix\",\"status\":200,\"title\":\"Note from 3 Jan\",\"word_count\":249,\"summary_text\":\"Note from 3 Jan Note from 3 Jan .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 3 Jan 2026 I’ve been using Helix since October 22 2025, according to the commit history on my system’s Nix flake. Coming from Neovim, it wasn’t a radical change, but there are some things that Helix does right, imo: Select-then-edit model: In the traditional Vi(m) editing model, your keybinds look like &#x3C;action>&#x3C;selection> e.g. dw to delete the next word. Helix keybinds work in reverse i.e. &#x3C;selection>&#x3C;action>. After using it for a while, I’m convinced that this is a much more intuitive way to edit text: being able to see what your action will affect before you do it makes for a much n\",\"classification_terms\":[\"2026/01/03/helix\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/editors\",\"status\":200,\"title\":\"#editors\",\"word_count\":256,\"summary_text\":\"#editors #editors article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{\",\"classification_terms\":[\"tags/editors\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/helix\",\"status\":200,\"title\":\"#helix\",\"word_count\":256,\"summary_text\":\"#helix #helix article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&[\",\"classification_terms\":[\"tags/helix\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2026/01/01/simonw-link-blog\",\"status\":200,\"title\":\"Simon Willison's approach to running a link blog\",\"word_count\":187,\"summary_text\":\"Simon Willison's approach to running a link blog Simon Willison&#39;s approach to running a link blog .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 1 Jan 2026 Simon Willison&#39;s approach to running a link blog . I’m finally getting around to publishing a link blog! And what better post to start off with than Simon Willison talking about his approach to maintaining a link blog. A slightly self-involved concern I have is that I like to prove that I’ve read it. This is more for me than for anyone else: I don’t like to recommend something if I’ve not read that thing myself, and sticking in a detail that shows I read past the first paragraph helps keep me honest about that. This is important to me too, but I’d like\",\"classification_terms\":[\"2026/01/01/simonw-link-blog\",\"about\",\"help\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2025/12/03/aoc-day-3-without-thinking\",\"status\":200,\"title\":\"Solving AoC Day 3 Without Thinking\",\"word_count\":2911,\"summary_text\":\"Solving AoC Day 3 Without Thinking Solving AoC Day 3 Without Thinking .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} .equation[data-astro-cid-tvag7nm6]{text-wrap-mode:nowrap;overflow-x:scroll;margin-bottom:.5rem;border-radius:5px;background-color:var(--flexoki-100);padding:.5rem 1rem;margin:1rem 0px;p{margin-top:0}}@media screen and (prefers-color-scheme:dark){.equation[data-astro-cid-tvag7nm6]{background-color:var(--flexoki-950)}} Hari&#39;s Weblog About Slashes 3 Dec 2025 • Updated 11 Dec 2025 Solving AoC Day 3 Without ThinkingBeware: Spoilers for Advent of Code Day 3 ahead! I’m doing Advent of Code again this year, and part 1 of today’s problem reminded me immediately of some of the problems I’m doing in my Program Construction\",\"classification_terms\":[\"2025/12/03/aoc-day-3-without-thinking\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/algorithms\",\"status\":200,\"title\":\"#algorithms\",\"word_count\":196,\"summary_text\":\"#algorithms #algorithms article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbsp\",\"classification_terms\":[\"tags/algorithms\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/gleam\",\"status\":200,\"title\":\"#gleam\",\"word_count\":89,\"summary_text\":\"#gleam #gleam article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&[\",\"classification_terms\":[\"tags/gleam\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/program-construction\",\"status\":200,\"title\":\"#program-construction\",\"word_count\":89,\"summary_text\":\"#program-construction #program-construction article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-c\",\"classification_terms\":[\"tags/program-construction\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2025/09/05/neovim-nixos-setup\",\"status\":200,\"title\":\"Setting up Neovim on NixOS\",\"word_count\":1034,\"summary_text\":\"Setting up Neovim on NixOS Setting up Neovim on NixOS .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 5 Sept 2025 Setting up Neovim on NixOSOf all the pieces of software I had to set up again when I switched to NixOS, Neovim took me the longest. This kind of surprised me at first: given that the Venn Diagram of NixOS users and Neovim users is fairly close to a circle ­— the set of people who are most productive when fiddling with configuration — I thought it’d be a breeze to get Neovim going on NixOS. Unfortunately, all that seems to have happened is, perhaps predictably, the evolution of a dozen different ways to go about this. Between options like NixVim and mnw, I was fairly confused about\",\"classification_terms\":[\"2025/09/05/neovim-nixos-setup\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/neovim\",\"status\":200,\"title\":\"#neovim\",\"word_count\":124,\"summary_text\":\"#neovim #neovim article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&\",\"classification_terms\":[\"tags/neovim\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/dotfiles\",\"status\":200,\"title\":\"#dotfiles\",\"word_count\":124,\"summary_text\":\"#dotfiles #dotfiles article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]\",\"classification_terms\":[\"tags/dotfiles\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2025/02/19/insertion-sort-is-merge-sort\",\"status\":200,\"title\":\"Insertion Sort is... Crappy Mergesort?\",\"word_count\":492,\"summary_text\":\"Insertion Sort is... Crappy Mergesort? Insertion Sort is... Crappy Mergesort? .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 19 Feb 2025 Insertion Sort is... Crappy Mergesort?mergeSort :: (Ord a) => [a] -> [a] mergeSort [] = [] mergeSort [x] = [x] mergeSort xs = merge (mergeSort (drop n xs)) (mergeSort (take n xs)) where n = length xs `div` 2 merge :: (Ord a) => [a] -> [a] -> [a] merge [] xs = xs merge xs [] = xs merge (x : xs) (y : ys) | x &#x3C;= y = x : merge xs (y : ys) | otherwise = y : merge (x : xs) ys I wrote this mergesort implementation during my algorithms lecture the other day. Initially, I was bit confused with the take n xs drop n xs part because for some reason I subconsciously thought tha\",\"classification_terms\":[\"2025/02/19/insertion-sort-is-merge-sort\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/haskell\",\"status\":200,\"title\":\"#haskell\",\"word_count\":41,\"summary_text\":\"#haskell #haskell article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{\",\"classification_terms\":[\"tags/haskell\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/fp\",\"status\":200,\"title\":\"#fp\",\"word_count\":41,\"summary_text\":\"#fp #fp article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&[dat\",\"classification_terms\":[\"tags/fp\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2025/01/01/autumn-stage-2\",\"status\":200,\"title\":\"Semester in Review: Stage 2 Autumn\",\"word_count\":1653,\"summary_text\":\"Semester in Review: Stage 2 Autumn Semester in Review: Stage 2 Autumn .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 1 Jan 2025 Semester in Review: Stage 2 AutumnA while back, I came across a couple of other blogs by college students reviewing the courses they took over the previous semester. I decided to do the same because it feels like a good way to lend a sense of closure to the semester, especially since exam season was a mad rush without time for much else than revision. Note: Technically, it’s a trimester here at UCD and not a semester because there’s also a summer trimester that undergrads don’t do. However, I’m going to continue calling it a semester because 1. it feels more natural and 2. G\",\"classification_terms\":[\"2025/01/01/autumn-stage-2\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/college\",\"status\":200,\"title\":\"#college\",\"word_count\":91,\"summary_text\":\"#college #college article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{\",\"classification_terms\":[\"tags/college\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/sem-in-review\",\"status\":200,\"title\":\"#sem-in-review\",\"word_count\":91,\"summary_text\":\"#sem-in-review #sem-in-review article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmk\",\"classification_terms\":[\"tags/sem-in-review\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2024/08/29/my-selfhosted-setup\",\"status\":200,\"title\":\"My Self-Hosted Setup\",\"word_count\":758,\"summary_text\":\"My Self-Hosted Setup My Self-Hosted Setup .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 29 Aug 2024 My Self-Hosted SetupI recently deployed a couple of services on a VM in the cloud so I could get my feet wet when it comes to self-hosting apps for my own personal use. So far, it’s been pretty fun but also frustrating at times; I figured I’d document everything I’ve done up until now so it’s easier for me when I migrate to a different server at some point in the future. My current VM Right now, I’m using an Azure Standard_B1s VM (1 vCPU / 1 GB RAM / 30 GB SSD) because it’s free with Azure’s yearly $100 credits for students. Signing up for Azure and verifying my student email was unexpec\",\"classification_terms\":[\"2024/08/29/my-selfhosted-setup\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/tech\",\"status\":200,\"title\":\"#tech\",\"word_count\":358,\"summary_text\":\"#tech #tech article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&[d\",\"classification_terms\":[\"tags/tech\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2024/07/28/shunting-yard-truth-tables\",\"status\":200,\"title\":\"Using the Shunting Yard Algorithm to Write Truth Tables\",\"word_count\":1958,\"summary_text\":\"Using the Shunting Yard Algorithm to Write Truth Tables Using the Shunting Yard Algorithm to Write Truth Tables .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 28 Jul 2024 Using the Shunting Yard Algorithm to Write Truth TablesIf you’ve gone through the first year of a undergraduate Computer Science degree, you’ll have written enough truth tables to last you a lifetime. Personally, I decided I’d had enough halfway through the semester and wrote a program to write my truth tables for me in Go. Unfortunately, we’d moved on from the topic before I finished working on this, but I still think it’s a pretty interesting project. The first step is to parse the formula and convert it into a form that can easily be evaluated. Norma\",\"classification_terms\":[\"2024/07/28/shunting-yard-truth-tables\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/tags/go\",\"status\":200,\"title\":\"#go\",\"word_count\":104,\"summary_text\":\"#go #go article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&[dat\",\"classification_terms\":[\"tags/go\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2024/07/11/docker-bad-dns\",\"status\":200,\"title\":\"The Docker Container Only Works on My Computer\",\"word_count\":1221,\"summary_text\":\"The Docker Container Only Works on My Computer The Docker Container Only Works on My Computer .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 11 Jul 2024 The Docker Container Only Works on My ComputerA few months ago, one of NetSoc’s committee members built an r/place clone just for NetSoc’s members, and we figured it would be nice to have a Discord bot to periodically take screenshots of the pixel art website and post updates to our server. When I volunteered to make it (because why not?), I never thought I’d spend about 5 hours wrestling with Docker while trying to deploy the app to our server, because the Dockerised app would only run on my computer. Obviously, this goes against the very principle of Docker: l\",\"classification_terms\":[\"2024/07/11/docker-bad-dns\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":8,\"depth\":1},{\"path\":\"/tags/docker\",\"status\":200,\"title\":\"#docker\",\"word_count\":117,\"summary_text\":\"#docker #docker article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&\",\"classification_terms\":[\"tags/docker\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/2024/06/10/using-htpdate\",\"status\":200,\"title\":\"Using Htpdate\",\"word_count\":433,\"summary_text\":\"Using Htpdate Using Htpdate .hyperlink[data-astro-cid-3x2mygxc]{font-family:Alegreya Sans;font-weight:700}main[data-astro-cid-3x2mygxc]{p:first-of-type{display:inline}} Hari&#39;s Weblog About Slashes 10 Jun 2024 Using HtpdateWhile doing some routine maintenance on a society server running Ubuntu (I’m a sysadmin for my university’s computer and networking society), I noticed that its system clock had drifted away from the true time by approximately 20 minutes. This amount of drift isn’t something one would expect to see on a long-running server with an active NTP service … except, of course, the NTP service wasn’t working. It was only then that I remembered that Port 123, which is reserved for the Network Time Protocol, is blocked on the campus network1. I first encountered this a few weeks before, when\",\"classification_terms\":[\"2024/06/10/using-htpdate\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":2,\"depth\":1},{\"path\":\"/tags/linux\",\"status\":200,\"title\":\"#linux\",\"word_count\":95,\"summary_text\":\"#linux #linux article[data-astro-cid-whmkbspe]{position:relative;margin-bottom:1rem;padding-bottom:1rem;main{p{margin-top:1rem}}&:not(:last-of-type){border-bottom:1px solid rgba(0,0,0,.4);&:after{content:\\\"***\\\";position:absolute;bottom:-24px;left:50%;right:50%;width:fit-content;padding:4px;background-color:var(--flexoki-paper);color:#0006}}}footer[data-astro-cid-whmkbspe]{display:flex;gap:.5rem;margin-top:.25rem;white-space:nowrap;overflow:hidden;position:relative;&[data-astro-cid-whmkbspe]:after{position:absolute;right:0;height:100%;width:3rem;top:0;content:\\\"\\\";background:linear-gradient(to right,transparent,var(--flexoki-paper))}}.tags[data-astro-cid-whmkbspe]{list-style-type:none;padding:0;display:flex;gap:.5rem;font-weight:700}@media(prefers-color-scheme:dark){footer[data-astro-cid-whmkbspe]{&[\",\"classification_terms\":[\"tags/linux\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":1},{\"path\":\"/colophon\",\"status\":200,\"title\":\"Colophon\",\"word_count\":116,\"summary_text\":\"Colophon Colophonarticle[data-astro-cid-bl3zq74b]{p,ul{margin-bottom:1rem}} Hari&#39;s Weblog About Slashes /colophon This website uses Steph Ango's beautiful Flexoki colour scheme. For syntax highlighting code blocks, I use Tommasso Laurenzi's Kanagawa colour scheme, specifically the \\\"Wave\\\" variant. This is also what I use on a day-to-day basis in my terminal and editor! These are the fonts I use: Alegreya: For body text Alegreya Sans: For headings Monaspace Neon: For code blocks They were all run through FontSquirrel to compress them and strip away unnecessary Unicode glyphs, keeping the bundle size of this website tiny. I use Astro as my Static Site Generator of choice, and can only recommend it. It's fantastically easy to use and very very flexible. &copy; 2024-2026 Hari Mohan\",\"classification_terms\":[\"colophon\",\"about\",\"contact\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":2},{\"path\":\"/blogroll\",\"status\":200,\"title\":\"Blogroll\",\"word_count\":182,\"summary_text\":\"Blogroll Blogroll h2[data-astro-cid-o2p577kt]{position:relative;text-align:right;&[data-astro-cid-o2p577kt]:after{position:absolute;content:\\\"\\\";height:0px;top:50%;left:0;width:95%;opacity:50%;border:1px dotted var(--flexoki-black)}@media(prefers-color-scheme:dark){&[data-astro-cid-o2p577kt]:after{border-color:var(--flexoki-paper)}}}ul[data-astro-cid-o2p577kt]{list-style-type:none;display:flex;flex-direction:column;gap:1rem;padding-left:0}section[data-astro-cid-o2p577kt]{margin-bottom:2rem} Hari&#39;s Weblog About Slashes /blogroll These are blogs and websites that I've come across and found interesting. Odds are that you'll find something worthwhile in a couple of these too! A Alexis Métaireau Abhinav Sarkar Aditya Bhargava Alex Kladov Alisa Sireneva Armin Ronacher B Bryan Cantrill C Cassidy William\",\"classification_terms\":[\"blogroll\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":2}]",
        "score_reasons_json": "[\"Category confidence was reduced, so the classifier fell back to the broader parent category.\",\"Category evidence stayed thin, so the output was softened to a broader classification.\",\"Trusted status now requires clean crawl access and stronger confidence, so this result was downgraded to caution.\"]",
        "route_domain": "haripm.com",
        "display_domain": "haripm.com"
    },
    "explainability": {
        "summary": "haripm.com currently scores 64/100. Technical and crawl-quality evidence are doing most of the lifting for the score. Evidence confidence is strong enough for a relatively stable read. This is an estimated profile rather than a manually tracked one. Crawler access looks clean.",
        "badges": [
            {
                "label": "Profile",
                "value": "Estimated profile",
                "tone": "unknown",
                "detail": null
            },
            {
                "label": "Evidence confidence",
                "value": "High confidence",
                "tone": "good",
                "detail": "100/100"
            },
            {
                "label": "Traffic confidence",
                "value": "Solid confidence",
                "tone": "caution",
                "detail": "60/100"
            },
            {
                "label": "Crawler access",
                "value": "Clean visibility",
                "tone": "good",
                "detail": null
            }
        ],
        "weighted_contributions": [
            {
                "label": "Quality system",
                "points": "+34.0",
                "tone": "good",
                "detail": "Technical quality, crawl depth, page structure, and implementation hygiene. Current subsystem score: 100/100."
            },
            {
                "label": "Reputation system",
                "points": "+15.0",
                "tone": "caution",
                "detail": "Authority, search visibility, reach, engagement, and registry stability. Current subsystem score: 44/100."
            },
            {
                "label": "Safety system",
                "points": "+32.0",
                "tone": "good",
                "detail": "Fraud, spam, and trust signals from infrastructure, crawl, and registry evidence. Current subsystem score: 100/100."
            },
            {
                "label": "Risk clamp",
                "points": "-17.0",
                "tone": "risk",
                "detail": "Safety thresholds capped the final score until the risk profile improves."
            }
        ],
        "evidence_cards": [
            {
                "label": "Authority and trust",
                "value": "46/100 · trust 77/100",
                "tone": "caution",
                "detail": "151 monthly visitors, 69 organic keywords, brand completeness 69/100, engagement 82/100."
            },
            {
                "label": "Backlink and search evidence",
                "value": "1 referring domains",
                "tone": "good",
                "detail": "1 backlinks across 1 referring domains. Diversity 92/100; spam penalty 0."
            },
            {
                "label": "Registry and domain stability",
                "value": "2.0 years old",
                "tone": "good",
                "detail": "Stability 100/100 · age 2.0 years · registrar NameCheap, Inc. · expires in 376 days."
            },
            {
                "label": "Safety and fraud posture",
                "value": "Safety 100/100 · fraud 1/100",
                "tone": "good",
                "detail": "Primary tag T · safety 100/100 · fraud 1/100."
            }
        ],
        "positives": [
            "Low registrar / ownership churn with solid registry stability.",
            "Healthy crawl quality and on-page completeness.",
            "Registry history looks stable, which supports legitimacy and trust.",
            "HTTPS is working, so the site clears a basic transport-security check.",
            "Backlink diversity looks broad enough to strengthen authority confidence."
        ],
        "risks": [],
        "freshness": [
            {
                "label": "Crawl evidence",
                "value": "2026-04-03 07:22:23",
                "tone": "risk",
                "detail": "Crawl and page content sample. Age: 10d ago."
            },
            {
                "label": "WHOIS snapshot",
                "value": "2026-04-03 07:22:18",
                "tone": "risk",
                "detail": "Registry profile and stability signals. Age: 10d ago."
            },
            {
                "label": "Keyword view",
                "value": "2026-04-13 16:24:26",
                "tone": "good",
                "detail": "Estimated visibility until tracked keyword snapshots exist. Age: 0s ago."
            },
            {
                "label": "Rank history",
                "value": "2026-04-13 16:24:26",
                "tone": "good",
                "detail": "Estimated trend derived from current profile and crawl signals. Age: 0s ago."
            },
            {
                "label": "Audience geography",
                "value": "Not captured yet",
                "tone": "unknown",
                "detail": "Audience mix is estimated from available signals rather than first-party audience logs."
            }
        ],
        "section_notes": {
            "audience": "Audience geography is estimated from category, country, traffic mix, and brand signals until first-party audience data is collected.",
            "keywords": "Top keywords are estimated from crawl language, brand, category, and visibility signals until tracked keyword snapshots are stored.",
            "history": "Rank history is estimated from the current profile because no stored history exists for this domain yet."
        },
        "base_weighted_score": 81,
        "fraud_clamp_penalty": 17,
        "final_score": 64
    },
    "insight_snapshot": {
        "version": 1,
        "generated_at": "2026-04-13T16:24:26+00:00",
        "domain": "haripm.com",
        "display_name": "Hari's Weblog",
        "is_tracked": false,
        "is_estimated": true,
        "overall_score": 64,
        "authority_score": 46,
        "trust_score": 77,
        "safety_score": 100,
        "fraud_score": 1,
        "confidence_score": 100,
        "traffic_confidence": 60,
        "last_crawled_at": "2026-04-03 07:22:23",
        "crawl_blocked": false,
        "summary": "haripm.com currently scores 64/100. Technical and crawl-quality evidence are doing most of the lifting for the score. Evidence confidence is strong enough for a relatively stable read. This is an estimated profile rather than a manually tracked one. Crawler access looks clean.",
        "badges": [
            {
                "label": "Profile",
                "value": "Estimated profile",
                "tone": "unknown",
                "detail": null
            },
            {
                "label": "Evidence confidence",
                "value": "High confidence",
                "tone": "good",
                "detail": "100/100"
            },
            {
                "label": "Traffic confidence",
                "value": "Solid confidence",
                "tone": "caution",
                "detail": "60/100"
            },
            {
                "label": "Crawler access",
                "value": "Clean visibility",
                "tone": "good",
                "detail": null
            }
        ],
        "top_positive_signals": [
            "Low registrar / ownership churn with solid registry stability.",
            "Healthy crawl quality and on-page completeness.",
            "Registry history looks stable, which supports legitimacy and trust.",
            "HTTPS is working, so the site clears a basic transport-security check.",
            "Backlink diversity looks broad enough to strengthen authority confidence."
        ],
        "top_risk_signals": [],
        "freshness": [
            {
                "label": "Crawl evidence",
                "value": "2026-04-03 07:22:23",
                "tone": "risk",
                "detail": "Crawl and page content sample. Age: 10d ago."
            },
            {
                "label": "WHOIS snapshot",
                "value": "2026-04-03 07:22:18",
                "tone": "risk",
                "detail": "Registry profile and stability signals. Age: 10d ago."
            },
            {
                "label": "Keyword view",
                "value": "2026-04-13 16:24:26",
                "tone": "good",
                "detail": "Estimated visibility until tracked keyword snapshots exist. Age: 0s ago."
            },
            {
                "label": "Rank history",
                "value": "2026-04-13 16:24:26",
                "tone": "good",
                "detail": "Estimated trend derived from current profile and crawl signals. Age: 0s ago."
            },
            {
                "label": "Audience geography",
                "value": "Not captured yet",
                "tone": "unknown",
                "detail": "Audience mix is estimated from available signals rather than first-party audience logs."
            }
        ],
        "top_tags": [
            {
                "code": "T",
                "label": "Trusted",
                "tone": "good"
            }
        ]
    },
    "is_tracked": false,
    "is_estimated": true,
    "live_state": {
        "status": "processing",
        "status_label": "Cache build running",
        "message": "The refreshed page cache is still being built for this domain.",
        "updated_at": "2026-04-13T17:51:07+00:00"
    },
    "refresh_state": {
        "canRequest": false,
        "queued": true,
        "processing": true,
        "stageKey": "cache-queued",
        "stageLabel": "Cache build running",
        "cooldownUntil": null,
        "message": "The refreshed page cache is still being built for this domain.",
        "action": "/domain/haripm.com/refresh",
        "isGuestCooldown": false,
        "cooldownSeconds": 0
    },
    "urlscan_report": {
        "domain": "haripm.com",
        "status": "idle",
        "submitted_at": null,
        "completed_at": null,
        "last_checked_at": null,
        "last_error": "",
        "submitted_url": "https://haripm.com/",
        "uuid": "",
        "result_url": "",
        "api_result_url": "",
        "visibility": "public",
        "summary": "No urlscan.io report has been requested for this domain yet.",
        "report": [],
        "report_summary": [],
        "is_fresh": false,
        "can_retry": true,
        "poll_after_seconds": 20
    }
}