• About
    • Contact

/root

  • Tailscale + Mullvad + Firefox DoH: Solving the DNS Resolution Problem

    January 31st, 2026

    If you’re using Tailscale with Mullvad VPN (either via the native Tailscale integration or standalone) and Firefox’s DNS over HTTPS (DoH), you might suddenly find yourself unable to access your Tailscale services via their *.ts.net hostnames—even though everything worked fine before.

    The symptoms are frustrating: tailscale ping works, dig resolves the hostname correctly, but Firefox just refuses to connect.

    Why This Happens

    When you enable DNS over HTTPS in Firefox (especially with “Max Protection” mode), Firefox bypasses your system’s DNS resolver entirely and sends all DNS queries directly to your chosen DoH provider—in this case, Mullvad’s DNS server at https://base.dns.mullvad.net/dns-query.

    The problem? Mullvad’s public DNS server has no idea what my-server.my-tailnet.ts.net is. That’s a private hostname that only Tailscale’s MagicDNS (running at 100.100.100.100) knows how to resolve.

    So while your system can resolve the hostname just fine:

    $ dig my-server.my-tailnet.ts.net
    ;; ANSWER SECTION:
    my-server.my-tailnet.ts.net. 600 IN A 100.x.x.x
    ;; SERVER: 100.100.100.100#53(100.100.100.100) (UDP)

    Firefox completely ignores this and asks Mullvad instead, which returns nothing.

    The Solution

    Firefox provides a way to exclude specific domains from DoH, forcing it to fall back to system DNS for those domains. Here’s how to set it up:

    1. Open Firefox and navigate to about:config
    2. Search for network.trr.excluded-domains
    3. Add ts.net to the list (comma-separated if there are existing entries)

    For example:

    ts.net

    Or if you have other exclusions:

    example.local, ts.net

    This tells Firefox: “For any domain ending in .ts.net, use the system DNS resolver instead of DoH.” Since your system DNS is controlled by Tailscale’s MagicDNS, the hostname will resolve correctly.

    The Gotcha: Old Tailnet Names

    Here’s a subtle issue that can trip you up: if you previously had a different Tailscale account or renamed your tailnet, you might have an old, specific exclusion that no longer applies.

    For example, you might have:

    my-nas.old-tailnet.ts.net

    But your current tailnet is new-tailnet.ts.net. The old exclusion does nothing for your new tailnet!

    The fix is simple: instead of excluding specific tailnet hostnames, just exclude the entire ts.net domain. This covers all Tailscale hostnames, regardless of your tailnet name, now and in the future.

    Verifying the Fix

    After making the change, you can verify everything is working:

    1. Test Tailscale connectivity (should already work): tailscale ping your-machine-name
    2. Test DNS resolution from the command line: dig your-machine-name.your-tailnet.ts.net
    3. Test in Firefox: Navigate to your Tailscale hostname—it should now load.

    Summary

    If you’re combining Firefox DoH with Tailscale:

    • Firefox’s DoH bypasses Tailscale’s MagicDNS
    • Add ts.net to network.trr.excluded-domains in about:config
    • Use ts.net (not a specific tailnet name) to future-proof the setting

    This gives you the best of both worlds: private DNS for general browsing via Mullvad, and working hostname resolution for your Tailscale network.

  • Immich v2.5.0: The 90,000 Stars Release – Major Features for Self-Hosted Photo Management

    January 28th, 2026

    Happy New Year, self-hosters! The Immich team has kicked off 2026 with a bang, releasing version 2.5.0 – aptly named the “90,000 Stars Release” in celebration of reaching this impressive GitHub milestone. This release is packed with long-awaited features that significantly improve both the mobile and web experience. Let’s dive into what’s new.

    Free Up Space: Finally Here

    This feature has been one of the most requested since the early days of Immich (it has a 3-digit issue ID!). Free Up Space allows you to remove local media files from your mobile device that have already been successfully backed up to your Immich server.

    Free Up Space feature in Immich mobile app showing storage reclaim options
    Free Up Space accessible from the user profile panel
    Free Up Space configuration options
    Configuration options for Free Up Space

    The feature includes smart configuration options:

    • Cutoff date: Only process photos and videos on or before a specified date
    • Keep albums: Preserve specific albums (WhatsApp-related albums are kept by default)
    • Keep favorites: Favorited assets stay on your device
    • Keep on device: Option to always keep all photos or all videos

    Before any files are removed, you’ll see a review screen showing exactly what will be deleted and how much storage you’ll reclaim. Deleted items go to your device’s native Trash, giving you a safety net.

    Non-Destructive Photo Editing

    Immich now supports non-destructive editing – a major enhancement for anyone who’s hesitated to edit photos for fear of losing the original. Edits are stored in the database while original files remain untouched. You can always revert to the original.

    Edit icon in Immich web interface
    Click the edit icon to enter edit mode

    Currently supported editing operations:

    • Cropping
    • Rotation
    • Mirroring
    Immich photo editing interface showing crop and rotation tools
    The editing interface with cropping, rotation, and mirroring tools
    Opening the editor on an already edited asset
    Opening the editor on an edited asset loads existing edits for adjustment

    When downloading an edited asset, you get the edited version by default, but can also choose to download the original. Note that mobile editing still uses the old system for now – the non-destructive approach will come to mobile in a future release.

    Web-Based Database Backup and Restore

    Database management just got significantly easier. Previously, restoring an Immich instance required command-line access – a barrier for users new to self-hosting. Now, the entire backup and restore pipeline is built into the web UI.

    You can restore from two locations:

    Database restore from Administration Maintenance page
    Restore from the Administration → Maintenance page
    Database restore from Onboarding page
    Restore from the Onboarding page on a fresh installation

    This is particularly valuable if you’ve ever worried about database corruption from power loss or system failures.

    Upload Improvements

    Foreground uploads on mobile have been significantly improved. The new implementation brings back reliable upload handling while adding concurrent uploads and proper support for assets with missing file extensions (common with DJI and Fusion Camera files).

    Improved upload interface in Immich mobile app
    Improved upload interface with concurrent upload support

    A notable improvement for iOS/iCloud users: uploads now send unique metadata to the server for faster checksum retrieval when reinstalling the app. To take advantage of this for existing uploads, go to App Settings → Sync Status and tap “Sync Cloud IDs” once.

    Sync Cloud IDs option in Immich settings
    Sync Cloud IDs to backfill metadata for existing uploads (iOS/iCloud users)

    Visual Refresh

    The entire Immich experience has received a visual update across web, mobile, and documentation. A new font improves readability, especially for numbers and smaller text.

    Immich visual refresh with new typography
    Refreshed visual design with improved typography

    The UI library has been integrated more deeply into the web app, providing more consistent components and better visual hierarchy.

    Standardized UI components in Immich
    More standardized and coherent UI components

    All icon buttons now include tooltips – no more guessing what a button does.

    Icon buttons with tooltips in Immich
    All icon buttons now show helpful tooltips

    Additional Highlights

    Star Rating on Mobile

    Mobile users can now rate their photos with stars, bringing feature parity with the web application.

    Star rating feature on Immich mobile
    Star rating now available on mobile

    Disable Admin Setup

    New environment variable IMMICH_ALLOW_SETUP=true|false lets you prevent the admin setup page from appearing after initial configuration – useful if your database ever gets accidentally reset.

    Fine-Grained API Permissions

    New scoped permissions for API keys include: map.read, map.search, and folder.read.

    Progressive JPEGs

    Image generation settings now include an option for progressive JPEGs, allowing supported browsers to render images progressively as they load.

    Progressive JPEG setting in Immich
    New progressive JPEG option in image generation settings

    Slideshow Loop

    Web slideshows can now automatically restart when they reach the end.

    Slideshow loop option in Immich
    New loop option in slideshow settings

    Native HTTP Clients

    All remote images now use optimized HTTP clients supporting HTTP/2 and HTTP/3. Images load faster, caching is improved, and the offline experience is more responsive with a larger cache size.

    Important Notes

    Mobile App Update Paused: As of the release, the team has temporarily halted the mobile app release due to some reported migration issues. Check the GitHub release page for the latest status.

    Client Compatibility: Mobile clients must be updated to v2.5.0 to view edited versions of assets. Older clients will continue to see original images.

    How to Update

    Follow the standard update procedure for your deployment method. As always, ensure you have a backup before upgrading.

    For the complete changelog including all bug fixes and documentation updates, check the full release notes on GitHub.

    Support the Project

    If you find Immich helpful, consider supporting the project by purchasing a product key at buy.immich.app or grabbing some merchandise at immich.store.

  • January 27th, 2026

    Introducing ankiR Stats: The Only Anki Addon with Time Series Analytics

    I’m excited to announce the release of ankiR Stats, a new Anki addon that brings advanced statistical analysis to your flashcard reviews. If you’ve ever wondered about the patterns hidden in your study data, this addon is for you.

    Why Another Stats Addon?

    There are several statistics addons for Anki already – Review Heatmap, More Overview Stats, True Retention. They’re great for basic numbers. But none of them answer questions like:

    • Is my retention trending up or down over time?
    • What’s my weekly study pattern? Do I study more on weekends?
    • Which days were unusually productive (or lazy)?
    • How are my card intervals growing over months?

    ankiR Stats answers all of these using the same statistical techniques data scientists use.

    Features

    📊 Time Series Charts

    Track your retention, reviews, and intervals over time with a 4-week moving average to smooth out the noise:

    Time Series Chart

    🗓️ GitHub-style Heatmap

    See your entire year of reviews at a glance:

    Review Heatmap

    🔬 Time Series Decomposition

    This is the killer feature. The addon breaks down your daily reviews into three components:

    • Trend – Are you studying more or less over time?
    • Seasonal – Your weekly pattern (which days you study most)
    • Residual – Random variation that doesn’t fit the pattern
    Decomposition

    ⚠️ Anomaly Detection

    The addon automatically finds unusual study days using z-score analysis. Days where you studied way more (or less) than normal are flagged with their statistical significance.

    No Dependencies

    Unlike many addons that require you to install Python packages, ankiR Stats uses web-based charts (Chart.js). It works out of the box on Windows, Mac, and Linux.

    Installation

    1. Open Anki
    2. Go to Tools → Add-ons → Get Add-ons
    3. Enter code: 419954163
    4. Restart Anki
    5. Access via Tools → ankiR Stats

    Based on ankiR

    This addon is a Python port of key features from ankiR, an R package I developed for comprehensive Anki analytics. The R package has 91 functions including forecasting, autocorrelation analysis, and FSRS integration – if you want even deeper analysis, check it out.

    Open Source

    The addon is open source and available on GitHub. Issues and contributions welcome!

    Links

    • AnkiWeb Page
    • GitHub Repository
    • ankiR on CRAN

    Let me know what you think in the comments!

  • KDE Plasma 6.6 Beta 2

    January 27th, 2026

    https://kde.org/announcements/changelogs/plasma/6/6.5.5-6.5.90/

  • January 24th, 2026
  • ZFS Knowledge be like … :)

    January 21st, 2026
  • Officially member of Open Spaced Repetition

    January 21st, 2026

    https://github.com/open-spaced-repetition/r-fsrs

    https://github.com/orgs/open-spaced-repetition/people

  • ankiR published for Windows

    January 21st, 2026
  • Introducing ankiR: Analyzing Your Anki Flashcard Data with R

    January 18th, 2026

    Unlock insights from your spaced repetition learning journey


    If you’re serious about learning, chances are you’ve encountered Anki—the powerful, open-source flashcard application that uses spaced repetition to help you remember anything. Whether you’re studying medicine, languages, programming, or any other subject, Anki has likely become an indispensable part of your learning toolkit.

    But have you ever wondered what stories your flashcard data could tell? How your review patterns have evolved over time? Which decks demand the most cognitive effort? That’s exactly why I created ankiR.

    What is ankiR?

    ankiR is an R package that lets you read, analyze, and visualize your Anki collection data directly in R. Under the hood, Anki stores all your notes, cards, review history, and settings in a SQLite database. ankiR provides a clean, user-friendly interface to access this treasure trove of learning data.

    Installation

    ankiR is available on CRAN and R-universe, making installation straightforward:

    From CRAN

    install.packages("ankiR")

    From R-universe (development version)

    # Enable the r-universe repository
    options(repos = c(
    chrislongros = "https://chrislongros.r-universe.dev",
    CRAN = "https://cloud.r-project.org"
    ))
    # Install ankiR
    install.packages("ankiR")

    Key Features

    • Read Anki databases: Access your collection.anki2 file or unpack .apkg exports
    • Extract review history: Analyze your complete review log (revlog table)
    • Access cards and notes: Work with your flashcard content programmatically
    • Deck analysis: Examine deck structures and configurations
    • Model inspection: Understand your note types and templates

    Quick Start Example

    Here’s how easy it is to start exploring your Anki data:

    library(ankiR)
    # Connect to your Anki collection
    # (Find it at ~/.local/share/Anki2/User 1/collection.anki2 on Linux)
    conn <- read_anki("path/to/collection.anki2")
    # Get your review history
    reviews <- get_revlog(conn)
    # Analyze review patterns
    library(ggplot2)
    ggplot(reviews, aes(x = as.Date(as.POSIXct(id/1000, origin = "1970-01-01")))) +
    geom_histogram(binwidth = 1) +
    labs(title = "Daily Review Activity",
    x = "Date",
    y = "Number of Reviews")
    # Don't forget to close the connection
    close_anki(conn)

    Why Analyze Your Anki Data?

    Understanding your learning patterns can help you:

    • Optimize study habits: Identify your most productive review times
    • Track progress: Visualize your learning journey over weeks, months, or years
    • Identify problem areas: Find cards or decks with high lapse rates
    • Research: Contribute to the growing body of spaced repetition research
    • Build custom tools: Create personalized dashboards and reports

    Understanding Anki’s Database Structure

    For those curious about what’s under the hood, Anki stores data in several tables:

    • notes: Your actual flashcard content (fields, tags)
    • cards: Individual review items generated from notes
    • revlog: Complete history of every review you’ve ever done
    • col: Collection metadata, deck configurations, and models

    ankiR abstracts away the complexity of parsing JSON-encoded columns and timestamp conversions, giving you clean data frames ready for analysis.

    Links and Resources

    • CRAN: https://cran.r-project.org/web/packages/ankiR/
    • R-universe: https://chrislongros.r-universe.dev/ankiR
    • Bug reports: Feel free to open issues on the package repository

    Related Projects

    If you’re interested in spaced repetition and R, you might also want to check out:

    • FSRS: The Free Spaced Repetition Scheduler algorithm, which Anki now supports natively
    • anki-snapshot: Git-based version control for Anki collections

    Conclusion

    Your Anki reviews represent countless hours of deliberate practice. With ankiR, you can finally extract meaningful insights from that data. Whether you’re a medical student tracking board exam prep, a language learner monitoring vocabulary acquisition, or a researcher studying memory, ankiR gives you the tools to understand your learning at a deeper level.

    Give it a try, and let me know what insights you discover in your own data!


    ankiR is open source and contributions are welcome. Happy learning!

  • r-fsrs: R bindings for the FSRS algorithm

    January 17th, 2026

    As someone who uses Anki extensively for medical studies, I’ve always been fascinated by the algorithms that power spaced repetition. When the FSRS (Free Spaced Repetition Scheduler) algorithm emerged as a more accurate alternative to Anki’s traditional SM-2, I wanted to bring its power to the R ecosystem for research and analysis.

    The result is rfsrs — R bindings for the fsrs-rs Rust library, now available on r-universe.

    Install it now:
    install.packages("rfsrs", repos = "https://chrislongros.r-universe.dev")

    What is FSRS?

    FSRS is a modern spaced repetition algorithm developed by Jarrett Ye that models memory more accurately than traditional algorithms. It’s based on the DSR (Difficulty, Stability, Retrievability) model of memory:

    • Stability — How long a memory will last (in days) before dropping to 90% retrievability
    • Difficulty — How hard the material is to learn (affects stability growth)
    • Retrievability — The probability of recalling the memory at any given time

    FSRS-6, the latest version, uses 21 optimizable parameters that can be trained on your personal review history to predict optimal review intervals with remarkable accuracy.

    The Rating Scale

    FSRS uses a simple 4-point rating scale after each review:

    1
    Again
    Blackout
    2
    Hard
    Struggled
    3
    Good
    Correct
    4
    Easy
    Effortless

    Why Rust + R?

    The reference implementation of FSRS is written in Rust (fsrs-rs), which provides excellent performance and memory safety. Rather than rewriting the algorithm in R, I used rextendr to create native R bindings to the Rust library.

    This approach offers several advantages:

    • Performance — Native Rust speed for computationally intensive operations
    • Correctness — Uses the official, well-tested implementation
    • Maintainability — Updates to fsrs-rs can be easily incorporated
    • Type Safety — Rust’s compiler catches errors at build time

    Architecture

    Here’s how rfsrs connects R to the Rust library:

    rfsrs Architecture
    R Layer
    fsrs_default_parameters() fsrs_initial_state() fsrs_next_state() fsrs_retrievability()
    ▼
    rextendr Bridge
    R → Rust
    Vectors → Vec, Lists → structs
    Rust → R
    f64 → numeric, structs → lists
    ▼
    Rust Layer (fsrs-rs)
    Algorithm
    FSRS-6, 21 params
    MemoryState
    stability, difficulty
    Functions
    next_states(), etc.

    Usage Examples

    Getting Started

    library(rfsrs)
    
    # Get the 21 default FSRS-6 parameters
    params <- fsrs_default_parameters()
    
    # Create initial memory state (rating: Good)
    state <- fsrs_initial_state(rating = 3)
    # $stability: 2.3065
    # $difficulty: 2.118104

    Tracking Memory Decay

    # How well will you remember?
    for (days in c(1, 7, 30, 90)) {
      r <- fsrs_retrievability(state$stability, days)
      cat(sprintf("Day %2d: %.1f%%\n", days, r * 100))
    }
    # Day  1: 95.3%
    # Day  7: 76.4%
    # Day 30: 49.7%
    # Day 90: 26.5%
    Note: Stability of 2.3 days means memory drops to 90% retrievability after 2.3 days. This increases with each successful review.

    Use Cases for R

    • Research — Analyze spaced repetition data with R’s statistical tools
    • Visualization — Plot memory decay curves with ggplot2
    • Integration with ankiR — Combine with ankiR to analyze your Anki collection
    • Custom schedulers — Build spaced repetition apps in R/Shiny

    Building Rust + R Packages

    The rextendr workflow:

    1. Create package with usethis::create_package()
    2. Run rextendr::use_extendr()
    3. Write Rust with #[extendr] macros
    4. Run rextendr::document()
    5. Build and check
    Windows builds: Cross-compiling Rust for Windows can be tricky. My r-universe builds work on Linux and macOS but fail on Windows. Windows users can install from source with Rust installed.

    Resources

    • rfsrs on r-universe
    • rfsrs on GitHub
    • fsrs-rs — The Rust library
    • ABC of FSRS — Algorithm intro
    • rextendr — R + Rust bindings

    What’s Next

    Future plans include parameter optimization (training on your review history), batch processing, and tighter ankiR integration.

    If you’re interested in spaced repetition or memory research, give rfsrs a try. Feedback welcome!

  • anki-snapshot: Git-Based Version Control for Your Anki Collection

    January 14th, 2026

    I’ve released anki-snapshot, a tool that brings proper version control to your Anki flashcard collection. Every change to your notes is tracked in git, giving you full history, searchable diffs, and the ability to see exactly what changed and when.

    The Problem

    Anki’s built-in backup system saves complete snapshots of your database, but it doesn’t tell you what changed. If you accidentally delete a note, modify a card incorrectly, or want to see how your deck evolved over time, you’re stuck comparing opaque database files.

    The Solution

    anki-snapshot exports your Anki collection to human-readable text files and commits them to a git repository. This means you get:

    • Full history: See every change ever made to your collection
    • Meaningful diffs: View exactly which notes were added, modified, or deleted
    • Search through time: Find when a specific term appeared or disappeared
    • Easy recovery: Restore individual notes from any point in history

    How It Works

    The tool reads your Anki SQLite database and exports notes and cards to pipe-delimited text files. These files are tracked in git, so each time you run anki-snapshot, any changes are committed with a timestamp.

    ~/anki-snapshot/
    ├── .git/
    ├── notes.txt      # All notes: id|model|fields...
    ├── cards.txt      # All cards: id|note_id|deck|type|queue|due|ivl...
    └── decks.txt      # Deck information
    

    Commands

    CommandDescription
    anki-snapshotExport current state and commit to git
    anki-diffShow changes since last snapshot
    anki-logShow commit history with stats
    anki-search "term"Search current notes for a term
    anki-search "term" --historySearch through all git history
    anki-restore <commit> <note_id>Restore a specific note from history

    Example: Tracking Changes

    After editing some cards in Anki, run the snapshot and see what changed:

    $ anki-snapshot
    [main a3f2b1c] Snapshot 2026-01-14 21:30:45
     1 file changed, 3 insertions(+), 1 deletion(-)
    
    $ anki-diff
    ━━━ Changes since last snapshot ━━━
    
    Modified notes: 2
    + [1462223862805] Which antibodies are associated with Hashimoto...
    − [1462223862805] Which antibodies are associated with Hashimoto...
    
    New notes: 1
    + [1767170915030] Germline polymorphisms of the ATPase 6 gene...
    

    Example: Searching History

    Find when “mitochondria” was added or modified across your entire collection history:

    $ anki-search "mitochondria" --history
    
    commit e183cea7b3e36ad8b8faf7ca9d5eb8ca44d5bb5e
    Date:   Tue Jan 13 22:43:47 2026 +0100
    + [1469146863262] If a disease has a mitochondrial inheritance pattern...
    + [1469146878242] Mitochondrial diseases often demonstrate variable expression...
    
    commit 41c25a53471fc72a520d2683bd3defd6c0d92a88
    Date:   Tue Jan 13 22:34:48 2026 +0100
    − [1469146863262] If a disease has a mitochondrial inheritance pattern...
    

    Integration with Anki

    For seamless integration, you can hook the snapshot into your Anki workflow. I use a wrapper script that runs the snapshot automatically when closing Anki:

    $ anki-wrapper  # Opens Anki, snapshots on close
    

    Or add it to your shell aliases to run before building/syncing your deck.

    Installation

    The tool is available on the AUR for Arch Linux users:

    yay -S anki-snapshot
    

    Or install manually:

    git clone https://github.com/chrislongros/anki-snapshot-tool
    cd anki-snapshot-tool
    ./install.sh
    

    Requires: bash, git, sqlite3

    Why Not Just Use Anki’s Backups?

    Anki’s backups are great for disaster recovery, but they’re binary blobs. You can’t:

    • See what changed between two backups without restoring them
    • Search for when specific content was added
    • Selectively restore individual notes
    • Track your collection’s evolution over months or years

    With git-based snapshots, your entire editing history becomes searchable, diffable, and recoverable.

    Screenshot:

    Source Code

    github.com/chrislongros/anki-snapshot-tool

  • Introducing fsrsr: R Bindings for the FSRS Spaced Repetition Algorithm

    January 14th, 2026

    I’ve just released fsrsr, an R package that provides bindings to fsrs-rs, the Rust implementation of the Free Spaced Repetition Scheduler (FSRS) algorithm. This means you can now use the state-of-the-art spaced repetition algorithm directly in R without the maintenance burden of a native implementation.

    What is FSRS?

    FSRS is a modern spaced repetition algorithm that outperforms traditional algorithms like SM-2 (used in Anki’s default scheduler). It uses a model based on the DSR (Difficulty, Stability, Retrievability) framework to predict memory states and optimize review intervals for long-term retention.

    Why Bindings Instead of Native R?

    Writing and maintaining a native R implementation of FSRS would be challenging:

    • The algorithm involves complex mathematical models that evolve with research
    • Performance matters when scheduling thousands of cards
    • Keeping pace with upstream changes requires ongoing effort

    By using extendr to create Rust bindings, we get:

    • Automatic updates: Just bump the fsrs-rs version to get algorithm improvements
    • Native performance: Rust’s speed with R’s convenience
    • Battle-tested code: The same implementation used by Anki and other major apps

    Installation

    You’ll need Rust installed (rustup.rs), then:

    remotes::install_github("chrislongros/fsrsr")
    

    Basic Usage

    Here’s a simple example showing the core workflow:

    library(fsrsr)
    
    # Initialize a new card with a "Good" rating (3)
    state <- fsrs_initial_state(3)
    # $stability: 3.17
    # $difficulty: 5.28
    
    # After reviewing 3 days later with "Good" rating
    new_state <- fsrs_next_state(
      stability = state$stability,
      difficulty = state$difficulty,
      elapsed_days = 3,
      rating = 3
    )
    
    # Calculate next interval for 90% target retention
    interval <- fsrs_next_interval(new_state$stability, 0.9)
    # Returns: days until next review
    
    # Check recall probability after 5 days
    prob <- fsrs_retrievability(new_state$stability, 5)
    # Returns: 0.946 (94.6% chance of recall)
    

    Available Functions

    FunctionDescription
    fsrs_default_parameters()Get the 21 default FSRS parameters
    fsrs_initial_state(rating)Initialize memory state for a new card
    fsrs_next_state(S, D, days, rating)Calculate next memory state after review
    fsrs_next_interval(S, retention)Get optimal interval for target retention
    fsrs_retrievability(S, days)Calculate probability of recall

    Ratings follow Anki’s convention: 1 = Again, 2 = Hard, 3 = Good, 4 = Easy.

    Use Cases

    • Research: Analyze spaced repetition data using R’s statistical tools
    • Custom SRS apps: Build R Shiny applications with proper scheduling
    • Simulation: Model learning outcomes under different review strategies
    • Data analysis: Process Anki export data with accurate FSRS calculations

    Technical Details

    The package uses extendr to generate R bindings from Rust code. The actual FSRS calculations happen in Rust via the fsrs-rs library (v2.0.4), with results passed back to R as native types.

    Source code: github.com/chrislongros/fsrsr

  • High iowait in TrueNAS server

    January 12th, 2026

    I recently ran into a performance issue on my TrueNAS SCALE 25.10.1 system where the server felt sluggish despite low CPU usage. The system was running Docker-based applications, and at first glance nothing obvious looked wrong. The real problem turned out to be high iowait.

    What iowait actually means

    In Linux, iowait represents the percentage of time the CPU is idle while waiting for I/O operations (usually disk). High iowait doesn’t mean the CPU is busy — it means the CPU is stuck waiting on storage.

    In top, this appears as wa:

    %Cpu(s): 1.8 us, 1.7 sy, 0.0 ni, 95.5 id, 0.2 wa, 0.0 hi, 0.8 si, 0.0 st

    Under normal conditions, iowait should stay very low (usually under 1–2%). When it starts climbing higher, the system can feel slow even if CPU usage looks fine.

    Confirming the issue with iostat

    To get a clearer picture, I used iostat, which shows per-disk activity and latency:

    iostat -x 1

    This immediately showed the problem. One or more disks had:

    • Very high %util (near or at 100%)
    • Elevated await times
    • Consistent read/write pressure

    At that point it was clear the bottleneck was storage I/O, not CPU or memory.

    Tracking it down to Docker services

    This system runs several Docker-based services. Using top alongside iostat, I noticed disk activity drop immediately when certain services were stopped.

    In particular, high I/O was coming from applications that:

    • Continuously read/write large files
    • Perform frequent metadata operations
    • Maintain large active datasets

    Examples included downloaders, media managers, and backup-related containers.

    Stopping services to confirm

    To confirm the cause, I stopped Docker services one at a time and watched disk metrics:

    iostat -x 1

    Each time a heavy I/O service was stopped, iowait dropped immediately. Once the worst offender was stopped, iowait returned to normal levels and the system became responsive again.

    Why the system looked “fine” at first

    This was tricky because:

    • CPU usage was low
    • Memory usage looked reasonable
    • The web UI was responsive but sluggish

    Without checking iostat, it would have been easy to misdiagnose this as a CPU or RAM issue.

    Lessons learned

    • High iowait can cripple performance even when CPU is idle
    • top alone is not enough — use iostat -x
    • Docker workloads can silently saturate disks
    • Stopping services one by one is an effective diagnostic technique

    Final takeaway

    On TrueNAS SCALE 25.10.1 with Docker, high iowait was the real cause of my performance issues. The fix wasn’t a reboot, more CPU, or more RAM — it was identifying and controlling disk-heavy services.

    If your TrueNAS server feels slow but CPU usage looks fine, check iowait and run iostat. The disk may be the real bottleneck.

  • Seaweedfs 4.06

    January 12th, 2026

    What’s Changed

    • Helm Chart
      • chart: Set admin metrics port to http port by @sheyabernstein in #7936
      • fix: Invalid volume mount conditional in filer template by @nichobi in #7992
    • S3 API
      • Fix S3 list objects marker adjustment for delimiters by @chrislusf in #7938
      • fix: directory incorrectly listed as object in S3 ListObjects by @chrislusf in #7939
      • Refine Bucket Size Metrics: Logical and Physical Size by @chrislusf in #7943
      • Fix AWS SDK Signature V4 with STS credentials (issue #7941) by @chrislusf in #7944
      • fix: correcting S3 nil cipher dereference in filer init by @tjasko in #7952
      • Support AWS standard IAM role ARN formats (issue #7946) by @chrislusf in #7948
      • s3api: fix authentication bypass and potential SIGSEGV (Issue #7912) by @chrislusf in #7954
      • store S3 storage class in extended atrributes #7961 by @ravenschade in #7962
      • fix: handle range requests on empty objects (size=0) by @chrislusf in #7963
      • Fix trust policy wildcard principal handling by @chrislusf in #7970
      • Support Policy Attachment for Object Store Users by @chrislusf in #7981
      • Fix STS identity authorization by populating PolicyNames (#7985) by @chrislusf in #7986
      • Fix: ListObjectVersions delimiter support by @chrislusf in #7987
      • Fix STS authorization in streaming/chunked uploads by @chrislusf in #7988
      • fix(s3api): ensure S3 configuration persistence and refactor authorization tests by @chrislusf in #7989
    • Misc
      • Standardize -ip.bind flags to default to empty and fall back to -ip by @chrislusf in #7945
      • Fix unaligned 64-bit atomic operation on ARM32 (#7958) by @aimmac23 in #7959
      • Fix flaky EC integration tests by collecting server logs on failure by @chrislusf in #7969
      • test: fix EC integration test needle blob mismatch by @chrislusf in #7972
      • chore: execute goimports to format the code by @promalert in #7983
    • Filer
      • fix(gcs): resolve credential conflict and improve backup logging by @chrislusf in #7951
      • Fix jwt error in Filer pod (k8s) by @MorezMartin in #7960
      • Fix chown Input/output error on large file sets by @chrislusf in #7996
    • Admin
      • fix: EC UI template error when viewing shard details by @chrislusf in #7955
      • Fix special characters in admin-generated secret keys by @chrislusf in #7994
    • FUSE Mount
      • Fix: prevent panic when swap file creation fails by @LeeXN in #7957
      • Enable writeback_cache and async_dio FUSE options by @chrislusf in #7980
    • Mini
      • feat: add flags to disable WebDAV and Admin UI in weed mini by @chrislusf in #7971
    • Volume Server
      • storage/needle: add bounds check for WriteNeedleBlob buffer by @chrislusf in #7973
      • opt: reduce ShardsInfo memory usage with bitmap and sorted slice by @chrislusf in #7974

    https://github.com/seaweedfs/seaweedfs/releases/tag/4.06

  • Contributing to Open Source: Creating Packages for FreeBSD and Arch Linux

    January 11th, 2026

    A journey through packaging Python libraries for spaced repetition and Anki deck generation across multiple platforms.

    As someone passionate about both medical education tools and open-source software, I recently embarked on a project to make several useful Python libraries available as native packages for FreeBSD and Arch Linux. This post documents the process and shares what I learned along the way.

    The Motivation

    Spaced repetition software like Anki has become indispensable for medical students and lifelong learners. However, the ecosystem of tools around Anki—libraries for generating decks programmatically, analyzing study data, and implementing scheduling algorithms—often requires manual installation via pip. This creates friction for users and doesn’t integrate well with system package managers.

    My goal was to package three key Python libraries:

    • genanki – A library for programmatically generating Anki decks
    • fsrs – The Free Spaced Repetition Scheduler algorithm (used in Anki and other SRS apps)
    • ankipandas – A library for analyzing Anki collections using pandas DataFrames

    Arch Linux User Repository (AUR)

    The AUR is a community-driven repository for Arch Linux users. Creating packages here involves writing a PKGBUILD file that describes how to fetch, build, and install the software.

    python-fsrs 6.3.0

    The FSRS (Free Spaced Repetition Scheduler) algorithm represents the cutting edge of spaced repetition research. Version 6.x brought significant API changes, including renaming the main FSRS class to Scheduler.

    # PKGBUILD for python-fsrs
    pkgname=python-fsrs
    pkgver=6.3.0
    pkgrel=1
    pkgdesc="Free Spaced Repetition Scheduler algorithm"
    arch=('any')
    url="https://github.com/open-spaced-repetition/py-fsrs"
    license=('MIT')
    depends=('python' 'python-typing_extensions')
    makedepends=('python-build' 'python-installer' 'python-wheel' 'python-setuptools')
    source=("https://files.pythonhosted.org/packages/source/f/fsrs/fsrs-${pkgver}.tar.gz")
    sha256sums=('3abbafd66469ebf58d35a5d5bb693a492e1db44232e09aa8e4d731bf047cd0ae')
    
    build() {
        cd "fsrs-$pkgver"
        python -m build --wheel --no-isolation
    }
    
    package() {
        cd "fsrs-$pkgver"
        python -m installer --destdir="$pkgdir" dist/*.whl
        install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
    }
    

    The package is now available at: aur.archlinux.org/packages/python-fsrs

    python-genanki 0.13.1

    genanki allows developers to create Anki decks programmatically—perfect for generating flashcards from databases, APIs, or other structured data sources.

    Package available at: aur.archlinux.org/packages/python-genanki

    python-ankipandas 0.3.15

    ankipandas provides a pandas-based interface for reading and analyzing Anki collection databases, enabling data science workflows on your study data.

    Package available at: aur.archlinux.org/packages/python-ankipandas

    FreeBSD Ports Collection

    FreeBSD’s ports system is more formal than the AUR, with stricter guidelines and a review process. Ports are submitted via Bugzilla and reviewed by committers before inclusion in the official ports tree.

    py-genanki Port

    Creating a FreeBSD port required several steps:

    1. Setting up the port skeleton – Creating the Makefile, pkg-descr, and distinfo files
    2. Handling dependencies – Mapping Python dependencies to existing FreeBSD ports
    3. Patching setup.py – Removing the pytest-runner build dependency which doesn’t exist in FreeBSD ports
    4. Testing the build – Running make and make install in a FreeBSD environment

    The final Makefile:

    PORTNAME=       genanki
    PORTVERSION=    0.13.1
    CATEGORIES=     devel python
    MASTER_SITES=   PYPI
    PKGNAMEPREFIX=  ${PYTHON_PKGNAMEPREFIX}
    
    MAINTAINER=     chris.longros@gmail.com
    COMMENT=        Library for generating Anki decks
    WWW=            https://github.com/kerrickstaley/genanki
    
    LICENSE=        MIT
    LICENSE_FILE=   ${WRKSRC}/LICENSE.txt
    
    RUN_DEPENDS=    ${PYTHON_PKGNAMEPREFIX}cached-property>0:devel/py-cached-property@${PY_FLAVOR} \
                    ${PYTHON_PKGNAMEPREFIX}chevron>0:textproc/py-chevron@${PY_FLAVOR} \
                    ${PYTHON_PKGNAMEPREFIX}frozendict>0:devel/py-frozendict@${PY_FLAVOR} \
                    ${PYTHON_PKGNAMEPREFIX}pystache>0:textproc/py-pystache@${PY_FLAVOR} \
                    ${PYTHON_PKGNAMEPREFIX}pyyaml>0:devel/py-pyyaml@${PY_FLAVOR}
    
    USES=           python
    USE_PYTHON=     autoplist distutils
    
    .include <bsd.port.mk>
    

    One challenge was that genanki’s setup.py required pytest-runner as a build dependency, which doesn’t exist in FreeBSD ports. The solution was to create a patch file that removes this requirement:

    --- setup.py.orig       2026-01-11 15:32:48.887894000 +0100
    +++ setup.py    2026-01-11 15:32:51.336128000 +0100
    @@ -27,9 +27,6 @@
             'chevron',
             'pyyaml',
           ],
    -      setup_requires=[
    -          'pytest-runner',
    -      ],
           tests_require=[
               'pytest>=6.0.2',
           ],
    

    py-fsrs Port

    The FSRS port followed a similar pattern, with its own set of dependencies to map to FreeBSD ports.

    Both ports are available in my GitHub repository and have been submitted to FreeBSD Bugzilla for review:

    • py-genanki branch
    • py-fsrs branch

    Lessons Learned

    Dependency Resolution

    One of the biggest challenges in packaging is mapping upstream dependencies to existing packages in the target ecosystem. For FreeBSD, this meant:

    • Searching /usr/ports for existing Python packages
    • Understanding the @${PY_FLAVOR} suffix for Python version flexibility
    • Discovering hidden dependencies (like chevron) that weren’t immediately obvious from the package metadata

    Build System Quirks

    Python packaging has evolved significantly, with projects using various combinations of:

    • setup.py with setuptools
    • pyproject.toml with various backends (setuptools, flit, hatch, poetry)
    • Legacy setup_requires patterns that don’t translate well to system packaging

    Creating patches to work around these issues is a normal part of the porting process.

    Testing Across Platforms

    Running a FreeBSD VM (via VirtualBox) proved essential for testing ports before submission. The build process can reveal missing dependencies, incorrect paths, and other issues that only appear in the actual target environment.

    Summary

    PackageVersionAURFreeBSD
    python-fsrs / py-fsrs6.3.0✅ Published📝 Submitted
    python-genanki / py-genanki0.13.1✅ Published📝 Submitted
    python-ankipandas0.3.15✅ Published🔜 Planned

    Get Involved

    If you use these tools on Arch Linux or FreeBSD, I’d love to hear your feedback. And if you’re interested in contributing to open-source packaging:

    • AUR: Browse orphaned packages and consider adopting one you use
    • FreeBSD: Run pkg query -e %m=ports@FreeBSD.org %o to find unmaintained ports you have installed

    Every package maintained is one less barrier to entry for users who want to use great software without fighting with dependency management.


    Published: January 2026

    Repository: github.com/chrislongros/freebsd-ports

←Previous Page
1 2 3 4 5 6 … 136
Next Page→

Blog at WordPress.com.

Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy
 

Loading Comments...
 

    • Subscribe Subscribed
      • /root
      • Already have a WordPress.com account? Log in now.
      • /root
      • Subscribe Subscribed
      • Sign up
      • Log in
      • Report this content
      • View site in Reader
      • Manage subscriptions
      • Collapse this bar