Skip to content

Update to al-folio v1.1 (v0 → v1 gem architecture migration) - #50

Merged
kastnerp merged 121 commits into
devfrom
chore/al-folio-v1.1
Jul 30, 2026
Merged

kastnerp merged 121 commits into
devfrom
chore/al-folio-v1.1

Conversation

@kastnerp

@kastnerp kastnerp commented Jul 30, 2026 •

Copy link
Copy Markdown
Member

What this is

Updates the site to al-folio v1.1.

Heads-up on scope: this is not a version bump. This fork was last synced against a
pre-v1.0 al-folio, from the era when layouts, includes and styles lived in this
repo. al-folio v1.x moved all of that into a family of gems (al_folio_core plus
al_* plugins), so getting to v1.1 means going through the v0 → v1 architecture
migration
. The v1.1 release notes assume you are already on v1.0 and only need to
bump Gemfile pins — that path does not apply to us.

Merged from upstream tag v1.1 (119 commits). 290 files changed, mostly deletions:
the local theme is gone and comes from gems now.

Why now

v1.1 is a security release. Three fixes we currently do not have:

Fix Gem
Swiper prototype pollution — CVSS 9.4 (CVE-2026-27212), 11.0.5 → 12.1.2 al_img_tools 1.0.3
polyfill.io removed from the MathJax path (June 2024 supply-chain takeover) al_math 1.0.2
Distill runtime no longer fetched from a third-party origin without SRI al_folio_distill 1.0.3

al_folio.distill.allow_remote_loader is set to false, which is what actually
opts us into the Distill hardening.

Overrides we keep

In v1.x a local file at a gem-owned path acts as an override. We had 14 customised
theme files; 8 survive as real overrides, the rest turned out to be unnecessary.

File Why we still override it
_includes/figure.liquid skip the webp srcset for GIFs (upstream still converts them and kills the animation); pass style through
_includes/footer.liquid Umami analytics — al_analytics ships Google/Cloudflare/Simple/Openpanel/Pirsch, but no Umami provider
_includes/header.liquid navbar wordmark via site.logo.*
_includes/repository/repo.liquid pin show_owner=false; our repos span three orgs and we keep github_users unset so the "GitHub users" block on /code/ stays hidden
_layouts/about.liquid title/subtitle hidden, capitalised section headings
_layouts/bib.liquid publications/ preview dir, DOI button suppressed
_layouts/page.liquid team profile portraits + GitHub README embed
assets/css/main.scss copy of the gem's, plus @use "custom"

Each was rebased onto the v1 gem version of the file rather than carried over
verbatim, so we are not shipping pre-v1 markup against v1 CSS.

Overrides we dropped

Dropped Replaced by
_includes/repository/repo_user.liquid the stats host is configurable now (external_services.github_readme_stats_url), and v1's default github-stats-extended is the maintained fork — the old public instance is why the cards had been blank
_includes/social.liquid (7.6 KB) a linkedin_company custom entry in _data/socials.yml. jekyll-socials hard-codes linkedin_username → /in/<user>, but it renders unknown keys straight from url/title/logo, which gives us the company URL and the linkedin-in icon with no template override
_sass/_base.scss, _sass/_themes.scss pre-v1 monoliths. Everything we had actually added moved to _sass/_custom.scss, including the .theme-aware-logo rules. The obsolete #light-toggle-* rules are gone — v1 renders the tri-state theme toggle itself

Bootstrap utilities v1 dropped

Pre-v1 al-folio loaded bootstrap.min.css and mdb.min.css from a CDN. v1
dropped both for al_folio_core's Tailwind layer, which reimplements many of the
same class names — some with different semantics. Two visual regressions came
out of this and are fixed in _sass/_custom.scss:

Home page logo. The hero logo comes from the org profile README, pulled in by
{% remote_include %} in _pages/about.md, as
<img src="assets/img/cd/…svg" class="img-fluid theme-aware-logo">. That src is
relative to that repo and 404s here — the image is only ever visible because
.theme-aware-logo { content: url(…) } swaps in a local wordmark. Because the class
lives in a remote file, grepping this repo for it finds nothing, so an earlier pass
of this branch mistook it for dead CSS and dropped it. Restored for dark, light and
system.

Team page rendered as boxed cards. _includes/team_member.liquid is written
against Bootstrap 4 + MDB:

class pre-v1 under v1
.h-100 height: 100% 100 Tailwind spacing units = 25rem
.card plain, no chrome gains a background and drop shadow
.card-body .p-2 → 8px gem's 1.25rem outranks .p-2
.card-title Bootstrap h5, 20px inherits gem heading sizing, 32px

Pinned to the pre-migration computed values under a new .team-member hook. Those
utility names appear nowhere else in the repo.

Also restored site-wide, at the values Bootstrap 4 served, because neither
al_folio_core nor the compat gem ships them: .text-muted (51 uses),
.bg-transparent, .border-0, and the .row-cols-* family — the team grid needs
row-cols-lg-5 for its 5-across layout.

Why not just enable al_folio_bootstrap_compat? Its utilities are
Tailwind-scale, so it defines .h-100 as 25rem and would make this worse. Its
.bg-transparent also lacks the !important needed to beat .card.

Verified against the live site with matching computed styles: card background
transparent, no shadow, card-title 20px/400, card-body 8px padding, columns
flex: 0 0 20%, text-muted #6c757d, and the logo resolving to the white
wordmark in dark/system and black in light.

Other changes

  • _pages/code.md passes repository=repo.id — our _data/repositories.yml uses the
    object form, and fixing the caller beats overriding the gem include.
  • feedjira and httparty dropped: unused. _plugins/github-profile-readme.rb uses
    stdlib open-uri.
  • Upstream demo content this fork had already deleted (Einstein page, sample posts,
    _books/, 3_project.md) stays deleted.
  • The teaching collection stays singular. Upstream renamed it to teachings in v1,
    but renaming would change every /teaching/... URL, so it is kept deliberately —
    there is a comment in _config.yml saying so.
  • compat.bootstrap.enabled stays false: our content leans on Bootstrap classes
    heavily (105× z-depth-1, 76× row, 41× col-sm-10), but al_folio_core's
    Tailwind layer already defines them, so the compat gem is not needed.
  • The citation workflow keeps our secrets.PAT || github.token fallback.

Verification

Built in Docker on ruby:3.3 (3.3.12) — local Ruby here is 2.6, the site needs 3.3.

  • bundle exec jekyll build — clean, 25.9s
  • bundle exec al-folio upgrade audit — 0 blocking, 9 non-blocking (8 were the
    unacknowledged overrides, now recorded in .al-folio-overrides.yml; the 9th is
    below)
  • Resolved gems carrying the security fixes: al_img_tools 1.0.3, al_math 1.0.2,
    al_folio_distill 1.0.3, al_folio_core 1.0.12. Swiper resolves to 12.1.2
    with matching SRI hashes.

Checked in the generated HTML: navbar wordmark renders, LinkedIn points at the
company page with the linkedin-in icon and no /in/ URL survives anywhere,
repository cards use github-stats-extended with show_owner=false, publication
previews resolve from assets/img/publications/, the Umami beacon is present,
team-profile-content is applied, and no polyfill.io reference remains.

Three things the verification turned up, all fixed in the second commit:

  1. The logo alt rendered "Sustainable Urban Systems Lab Urban Systems Lab" — the
    filter chain appended the name parts even when site.title was set. Pre-existing
    bug, fixed since the file was being rewritten anyway.
  2. v1.1 ships a test/ harness in the starter but does not exclude it, so the
    Playwright specs and shell scripts were being published to the live site. Added
    to exclude:.
  3. The remaining non-blocking finding is legacy_data_toggle at
    _layouts/bib.liquid:142. al_folio_core's own bib.liquid has the identical
    data-toggle="popover" at the same line — the audit only flags ours because
    overriding the file brings it into the scanned tree. Left as-is so future diffs
    against upstream stay clean.

What still needs a human

The build passing does not mean it looks right. Worth clicking through before merge:

  • Home — navbar wordmark, news, selected publications
  • /publications/ — preview images resolve from assets/img/publications/, DOI buttons still suppressed, altmetric/dimensions badges
  • /team/ and an individual member page — portrait float + clearfix, GitHub README embed
  • /code/ — repository cards actually render (they were blank on the old stats host)
  • /teaching/ — the singular collection still resolves
  • Social icons — LinkedIn points at the company page and uses the right icon, in both the navbar and the about page
  • Dark / light / system toggle — v1 renders the system state with .fa-half-sun-moon instead of the old Tabler icon
  • Umami — confirm the beacon still fires

One deliberate visual change: the search button now shows v1's ctrl k hint and a
Font Awesome magnifying glass, where we previously showed a bare Tabler icon. v1
dropped Tabler; keeping it would have meant a larger override for no functional gain.
Easy to revert in _includes/header.liquid if you dislike it.

Follow-ups, not in this PR

  • _layouts/profiles_new.liquid is dead — no page references it.
  • _teaching/gt-arch-6242.md hand-writes <swiper-container> markup, but nothing
    loads Swiper on that page, so the slider renders as inert custom elements. This is
    not a migration regression — pre-v1 al-folio never injected Swiper here either
    (the merge base has no swiper wiring at all). al_img_tools gates the assets on
    page front matter, so it likely just needs the right key adding.
  • After merge, run bundle exec al-folio upgrade overrides audit on gem bumps;
    .al-folio-overrides.yml records the reviewed upstream checksums.

🤖 Generated with Claude Code

george-gca and others added 30 commits January 2, 2026 19:11
Since a lot of our users don't have a coding background and given
recently development with AI agents, I decided to try to add support for
specialized agents in our repository. They were created following
[agents.md](https://agents.md/) "specifications" and are currently 2:
- `customize-agent` - to help new users with access to GitHub Copilot
customize their site
- `docs-agent` - to help us keep the documentation always updated with
the latest changes in our code

I don't really know how useful they'll actually be, but I think most of
our users might actually benefit from the `customize-agent`, so it is
worth a shot.

<img width="852" height="1043" alt="image"
src="https://github.com/user-attachments/assets/e8390f1a-cec3-42a8-b01e-26d658ea78e8"
/>

Edit: also added a link to a [Code Wiki to our
repository](https://codewiki.google/github.com/alshedivat/al-folio) and
[DeepWiki](https://deepwiki.com/alshedivat/al-folio). This allows any
user to chat online with AIs (Gemini and Devin) about our repository.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Resolve alshedivat#3370
Resolve alshedivat#3380

Based on the
[comment](alshedivat#3370 (comment))
of @MarkusThill, I created a bugfix that solved the issue on my website.
Hope that fixes it in general; thus the PR :) However, I'm not an expert
for scss .. so handle with care :)
…lshedivat#3391)

Fixes alshedivat#3386 (the part about the wrong months; the other part (layouting
of bibtex) is fixed in alshedivat#3387)

## Summary
- Fixes incorrect month shown for bibliography entries that do not
specify a `month` in BibTeX.
- Ensures `month`/`year` do not persist between entries in
`_layouts/bib.liquid`.

## Root Cause
- In Liquid, captured variables persist across iterations if not
reinitialized.
- `entrymonth` and `entryyear` were only set when
`entry.month`/`entry.year` existed, causing values from a previous entry
to leak into the next one when those fields were missing.

## Changes
- Reinitialize date-related variables per entry before conditional
captures:

## Behavior
- Before: Entries without a `month` could display the previous entry's
month.
- After: Entries without a `month` display only the `year`; entries with
a `month` display the correct month and year.


<img width="1956" height="918" alt="image"
src="https://github.com/user-attachments/assets/7a9682e7-55ab-43b7-8f82-f638d14ce08e"
/>
Fix alshedivat#3164

Signed-off-by: George Araújo <george.gcac@gmail.com>
…hedivat#3417)

Based on discussion alshedivat#3393.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Currently, images generated by Imagemagick do not respect the
orientation of the source image. By adding the auto-orient flag, the
images are the correct orientation.

Before
<img width="920" height="562" alt="image"
src="https://github.com/user-attachments/assets/73f59d7f-b6c5-468a-9023-0f0457a53a3c"
/>

After
<img width="947" height="621" alt="image"
src="https://github.com/user-attachments/assets/2f24de99-2e84-4052-8d0f-945acdad81e4"
/>
Closes alshedivat#3402

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Signed-off-by: George Araújo <george.gcac@gmail.com>
This PR fixes a recurring typo in multiple Liquid templates where the
Bootstrap class `cl-sm` is used instead of `col-sm`.

Because of this typo, the `col-sm` styling was not being applied. All
instances have been corrected.
…at#3422)

## Description

This PR makes the URLs for external services used on the repository page
configurable in `_config.yml`. This allows users to self-host these
services for better reliability, privacy, and customization.

## Changes

- Added `external_services` configuration section in `_config.yml` with:
- `github_readme_stats_url` (default:
`https://github-readme-stats.vercel.app`)
- `github_profile_trophy_url` (default:
`https://github-profile-trophy.vercel.app`)
- Updated repository template files to use configurable URLs:
  - `_includes/repository/repo_user.liquid`
  - `_includes/repository/repo.liquid`
  - `_includes/repository/repo_trophies.liquid`
- Added documentation in `CUSTOMIZE.md` explaining:
- Why self-hosting is recommended (default services may have
availability issues)
  - How to configure custom service URLs
  - Links to the service repositories for deployment instructions

## Resolves

Resolves alshedivat#3388 - This makes it possible to configure self-hosted
versions of these services, giving users full control over the external
services used for displaying GitHub statistics and trophies.

## Testing

- Verified that default configuration still works with original service
URLs
- Confirmed that URLs are properly interpolated in all template files
- Documentation clearly explains the configuration options
Removed a link to sam-bieberich.github.io from the README.
Hi! I'd like to add my academic website to the User community section.

**Website:** https://j1yoo.github.io/

This PR adds a single star link to the Academics row in the User
community table.

Thank you for creating and maintaining this beautiful theme!

Co-authored-by: Jaewon Yoo <jwyoo4@gmail.com>
add `dimensions, eprint` and `pmid` to the filtered keywords
Adds a HAL button in the same spirit as the arXiv button.
- add HAL button to `_layouts/bib.liquid`
- add `hal` to the filtered keywords in `_config.yml`
- add `hal` to the documentation  in `CUSTOMIZE.md`
Improved section based on comments from alshedivat#2369.

Signed-off-by: George Araújo <george.gcac@gmail.com>
Adding my personal website for the al-folio community :) Thanks for
creating such a cool template!
Signed-off-by: George Araújo <george.gcac@gmail.com>
Signed-off-by: George Araújo <george.gcac@gmail.com>
Signed-off-by: George Araújo <george.gcac@gmail.com>
Signed-off-by: George Araújo <george.gcac@gmail.com>
actions-user and others added 23 commits July 15, 2026 01:07
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.19.3
to 1.19.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/sparklemotion/nokogiri/releases">nokogiri's
releases</a>.</em></p>
<blockquote>
<h2>v1.19.4 / 2026-06-18</h2>
<h3>Security</h3>
<ul>
<li>[CRuby] (Low) Fixed a possible invalid memory read when
<code>XML::Node#initialize_copy_with_args</code> is called with an
argument that is not a <code>Node</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-g9g8-vgvw-g3vf">GHSA-g9g8-vgvw-g3vf</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when an
<code>XML::XPathContext</code> is used after its source document has
been garbage collected. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-p67v-3w7g-wjg7">GHSA-p67v-3w7g-wjg7</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free during XInclude
processing via <code>Node#do_xinclude</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wfpw-mmfh-qq69">GHSA-wfpw-mmfh-qq69</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#root=</code> is assigned a non-element node. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wjv4-x9w8-wm3h">GHSA-wjv4-x9w8-wm3h</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when setting an
attribute value via <code>XML::Attr#value=</code> or
<code>#content=</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-phwj-rprq-35pp">GHSA-phwj-rprq-35pp</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a null pointer dereference when methods are
called on uninitialized wrapper objects (e.g. via
<code>allocate</code>); these now raise instead of crashing the process.
See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-9cv2-cfxc-v4v2">GHSA-9cv2-cfxc-v4v2</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#encoding=</code> raises an exception. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5v8h-3h3q-446p">GHSA-5v8h-3h3q-446p</a>
for more information.</li>
<li>[CRuby] (Medium) Fixed an out-of-bounds read in
<code>XML::NodeSet#[]</code> (alias <code>#slice</code>) when given a
large negative index. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5prr-v3j2-97mh">GHSA-5prr-v3j2-97mh</a>
for more information.</li>
<li>[JRuby] (Low) <code>XML::Schema</code> now enforces the
<code>NONET</code> parse option, which Nokogiri enables by default. It
was not enforced on JRuby, so a schema parsed with default options could
still fetch external resources over the network, potentially enabling
SSRF or XXE attacks and bypassing the mitigation for CVE-2020-26247. See
<a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-8678-w3jw-xfc2">GHSA-8678-w3jw-xfc2</a>
for more information.</li>
</ul>
<!-- raw HTML omitted -->

<pre><code>1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f
nokogiri-1.19.4-aarch64-linux-gnu.gem
35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af
nokogiri-1.19.4-aarch64-linux-musl.gem
a301313e38bb065d68239e79734bcd6f56fb6efaacebde29e9abf2a4735340ca
nokogiri-1.19.4-arm-linux-gnu.gem
588923c101bcfa78869734d247d25b598674323e7f22474fc468f6e5647311eb
nokogiri-1.19.4-arm-linux-musl.gem
a46db9853286e6597b36ebc6953817d15acf3a299583eb3f89fdc6f91dd63527
nokogiri-1.19.4-arm64-darwin.gem
ce04b9e268c9626852231a48b49128ed52034f1ccb39484a6da3875491cd709e
nokogiri-1.19.4-java.gem
051da97b8eccfdb5444fed40246a35e10d7298b9efe759b4cd25455ea04c587e
nokogiri-1.19.4-x64-mingw-ucrt.gem
7fd17057d3e1f00e9954a74b3cd76595d3d4a5ef233b7ed9599047c204f70551
nokogiri-1.19.4-x86_64-darwin.gem
379fae440b28915e3f19d752ce2dcf8465ed2b2fbefd2a7ca0dd497bc981a06a
nokogiri-1.19.4-x86_64-linux-gnu.gem
17dfb7c1fa194ae02fbf7c51a7afc8d278045ab3fdacfd86f91d02d7b274470b
nokogiri-1.19.4-x86_64-linux-musl.gem
50c951611c92bca05c51411aef45f1cbc50f2821c4802758c5c6d34696533ab5
nokogiri-1.19.4.gem
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md">nokogiri's
changelog</a>.</em></p>
<blockquote>
<h2>v1.19.4 / 2026-06-18</h2>
<h3>Security</h3>
<ul>
<li>[CRuby] (Low) Fixed a possible invalid memory read when
<code>XML::Node#initialize_copy_with_args</code> is called with an
argument that is not a <code>Node</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-g9g8-vgvw-g3vf">GHSA-g9g8-vgvw-g3vf</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when an
<code>XML::XPathContext</code> is used after its source document has
been garbage collected. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-p67v-3w7g-wjg7">GHSA-p67v-3w7g-wjg7</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free during XInclude
processing via <code>Node#do_xinclude</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wfpw-mmfh-qq69">GHSA-wfpw-mmfh-qq69</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#root=</code> is assigned a non-element node. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wjv4-x9w8-wm3h">GHSA-wjv4-x9w8-wm3h</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when setting an
attribute value via <code>XML::Attr#value=</code> or
<code>#content=</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-phwj-rprq-35pp">GHSA-phwj-rprq-35pp</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a null pointer dereference when methods are
called on uninitialized wrapper objects (e.g. via
<code>allocate</code>); these now raise instead of crashing the process.
See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-9cv2-cfxc-v4v2">GHSA-9cv2-cfxc-v4v2</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#encoding=</code> raises an exception. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5v8h-3h3q-446p">GHSA-5v8h-3h3q-446p</a>
for more information.</li>
<li>[CRuby] (Medium) Fixed an out-of-bounds read in
<code>XML::NodeSet#[]</code> (alias <code>#slice</code>) when given a
large negative index. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5prr-v3j2-97mh">GHSA-5prr-v3j2-97mh</a>
for more information.</li>
<li>[JRuby] (Low) <code>XML::Schema</code> now enforces the
<code>NONET</code> parse option, which Nokogiri enables by default. It
was not enforced on JRuby, so a schema parsed with default options could
still fetch external resources over the network, potentially enabling
SSRF or XXE attacks and bypassing the mitigation for CVE-2020-26247. See
<a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-8678-w3jw-xfc2">GHSA-8678-w3jw-xfc2</a>
for more information.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/8cfb9daae9ee4a0837508eab43c40fbc8c4138c9"><code>8cfb9da</code></a>
version bump to v1.19.4</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/a856d1e46bda04ef47a0bd2b9eefe86df1eb0bb2"><code>a856d1e</code></a>
fix: JRuby NONET bypass in XML::Schema (v1.19.x) (<a
href="https://redirect.github.com/sparklemotion/nokogiri/issues/3639">#3639</a>)</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/6a0aa1e7042ea58e10db713d4984c692a8db1a30"><code>6a0aa1e</code></a>
fix(CRuby): use-after-free in Document#encoding= when setter raises
(v1.19.x)...</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/f658a54ab2df58a3525967c339edce9649c197d4"><code>f658a54</code></a>
fix: JRuby NONET bypass in XML::Schema</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/39d26fea52cda8ac15313561824fd0bc018818aa"><code>39d26fe</code></a>
fix(CRuby): use-after-free in Document#encoding= when setter raises</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/04a09ddd67a4b573eb5c634655c2fb857e0436ad"><code>04a09dd</code></a>
fix(CRuby): out-of-bounds read in NodeSet#[] with large negative index
(v1.19...</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/7799fbd325f9f5e10fcccc77daaa903949a9d545"><code>7799fbd</code></a>
fix: avoid NPE on uninitialized XML::Node structs (v1.19.x) (<a
href="https://redirect.github.com/sparklemotion/nokogiri/issues/3645">#3645</a>)</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/ef19e1329c39f885e980b301f33fb233f3431d14"><code>ef19e13</code></a>
fix(CRuby): avoid UAF in XML::Attr#value= (v1.19.x) (<a
href="https://redirect.github.com/sparklemotion/nokogiri/issues/3644">#3644</a>)</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/5524fa97868ae26dfd74d700aba256b117262267"><code>5524fa9</code></a>
fix: <code>Document#root=</code> rejects non-element nodes (v1.19.x) (<a
href="https://redirect.github.com/sparklemotion/nokogiri/issues/3643">#3643</a>)</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/9891ad1092a265ae1cef220c377ebbabc9fde622"><code>9891ad1</code></a>
fix(CRuby): use-after-free in XPathContext document lifetime (v1.19.x)
(<a
href="https://redirect.github.com/sparklemotion/nokogiri/issues/3641">#3641</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/sparklemotion/nokogiri/compare/v1.19.3...v1.19.4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=nokogiri&package-manager=bundler&previous-version=1.19.3&new-version=1.19.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/alshedivat/al-folio/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps
[concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby)
from 1.3.6 to 1.3.7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ruby-concurrency/concurrent-ruby/releases">concurrent-ruby's
releases</a>.</em></p>
<blockquote>
<h2>v1.3.7</h2>
<!-- raw HTML omitted -->
<p>There are 3 security fixes in this release, so updating is
recommended.
These security vulnerabilities are not very likely to be hit in practice
and have a corresponding <code>Low</code> severity score.</p>
<!-- raw HTML omitted -->
<h2>What's Changed</h2>
<ul>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-h8w8-99g7-qmvj">CVE-2026-54904</a>
<code>AtomicReference#update</code> livelocks when the stored value is
<code>Float::NAN</code>. Fix by <a
href="https://github.com/joshuay03"><code>@​joshuay03</code></a> and <a
href="https://github.com/eregon"><code>@​eregon</code></a></li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-wv3x-4vxv-whpp">CVE-2026-54905</a>
<code>ReentrantReadWriteLock</code> read-count overflow grants a write
lock without exclusivity. Fix by <a
href="https://github.com/joshuay03"><code>@​joshuay03</code></a></li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-6wx8-w4f5-wwcr">CVE-2026-54906</a>
<code>ReadWriteLock</code> allows wrong-thread write release and stray
read-release counter corruption. Fix by <a
href="https://github.com/joshuay03"><code>@​joshuay03</code></a></li>
<li>concurrent-ruby-ext: fix build on Darwin 32-bit by <a
href="https://github.com/barracuda156"><code>@​barracuda156</code></a>
in <a
href="https://redirect.github.com/ruby-concurrency/concurrent-ruby/pull/1064">ruby-concurrency/concurrent-ruby#1064</a></li>
<li>Add SECURITY.md by <a
href="https://github.com/eregon"><code>@​eregon</code></a> in <a
href="https://redirect.github.com/ruby-concurrency/concurrent-ruby/pull/1104">ruby-concurrency/concurrent-ruby#1104</a></li>
<li>Add Ruby 4.0 in CI by <a
href="https://github.com/eregon"><code>@​eregon</code></a> in <a
href="https://redirect.github.com/ruby-concurrency/concurrent-ruby/pull/1106">ruby-concurrency/concurrent-ruby#1106</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/barracuda156"><code>@​barracuda156</code></a>
made their first contribution in <a
href="https://redirect.github.com/ruby-concurrency/concurrent-ruby/pull/1064">ruby-concurrency/concurrent-ruby#1064</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ruby-concurrency/concurrent-ruby/compare/v1.3.6...v1.3.7">https://github.com/ruby-concurrency/concurrent-ruby/compare/v1.3.6...v1.3.7</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ruby-concurrency/concurrent-ruby/blob/master/CHANGELOG.md">concurrent-ruby's
changelog</a>.</em></p>
<blockquote>
<h2>Release v1.3.7 (16 June 2026)</h2>
<p>concurrent-ruby:</p>
<ul>
<li>See the <a
href="https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.3.7">release
notes on GitHub</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/4c8fc28ab6bb9bd8258a4c0c2fa6d35ebe77b3cb"><code>4c8fc28</code></a>
Release 1.3.7</li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/d91ca9426cb819d6cc63f1bd64bfe54644d0beca"><code>d91ca94</code></a>
Fix AtomicReference#update livelock when stored value is Float::NAN on
JRuby ...</li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/7e4d711bacf7a1dac3ef6bda44004387be2dc7e6"><code>7e4d711</code></a>
Fix <code>ReentrantReadWriteLock</code> read hold overflow into
write-lock bit</li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/6e37e0644b83b182971dc540d2e4bee38df61386"><code>6e37e06</code></a>
Fix <code>AtomicReference#update</code> livelock when stored value is
<code>Float::NAN</code></li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/2825cfa12cb708b76557803957f76862eb1151a2"><code>2825cfa</code></a>
Cleanup spec</li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/3fd493283ca5f84f0ef4e84aabd43ad68df4626b"><code>3fd4932</code></a>
Fix <code>ReadWriteLock</code> wrong-thread write release and stray read
release</li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/1974b4772efc034ee8eaa562b4370343f4c5c54b"><code>1974b47</code></a>
Add Ruby 4.0 in CI</li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/df8706d40c483d76bbb0b3a35a633c68fa9e17be"><code>df8706d</code></a>
Add SECURITY.md (<a
href="https://redirect.github.com/ruby-concurrency/concurrent-ruby/issues/1104">#1104</a>)</li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/7a1b78941c081106c20a9ca0144ac73a48d254ab"><code>7a1b789</code></a>
Bump actions/upload-pages-artifact from 4 to 5</li>
<li><a
href="https://github.com/ruby-concurrency/concurrent-ruby/commit/9b2dbf712896a638a73d2fa221206961c8d6484d"><code>9b2dbf7</code></a>
Bump actions/deploy-pages from 4 to 5</li>
<li>Additional commits viewable in <a
href="https://github.com/ruby-concurrency/concurrent-ruby/compare/v1.3.6...v1.3.7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=concurrent-ruby&package-manager=bundler&previous-version=1.3.6&new-version=1.3.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/alshedivat/al-folio/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [loofah](https://github.com/flavorjones/loofah) from 2.25.1 to
2.25.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/flavorjones/loofah/releases">loofah's
releases</a>.</em></p>
<blockquote>
<h2>2.25.2 / 2026-07-15</h2>
<h3>Security</h3>
<ul>
<li>Ensure <code>Loofah::HTML5::Scrub.allowed_uri?</code> recognizes
numeric character references without semicolons (e.g.
<code>javascript&amp;#58alert(1)</code>), which browsers decode and
execute, and rejects schemes split by them. See <a
href="https://github.com/flavorjones/loofah/security/advisories/GHSA-5qhf-9phg-95m2">GHSA-5qhf-9phg-95m2</a>.
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
<li>Ensure <code>Loofah::HTML5::Scrub.allowed_uri?</code> recognizes the
named character references <code>&amp;Tab;</code> and
<code>&amp;NewLine;</code>, which <code>CGI.unescapeHTML</code> does not
decode and browsers strip from URIs, and rejects schemes split by them
(e.g. <code>java&amp;Tab;script:alert(1)</code>). See <a
href="https://github.com/flavorjones/loofah/security/advisories/GHSA-8whx-365g-h9vv">GHSA-8whx-365g-h9vv</a>.
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
<li>Ensure that both <code>href</code> and <code>xlink:href</code>
attributes on SVG elements like <code>use</code> are restricted to local
(same-document) references. Previously only <code>xlink:href</code> was
restricted, allowing the SVG 2 <code>href</code> attribute to reference
external documents. See <a
href="https://github.com/flavorjones/loofah/security/advisories/GHSA-9wjq-cp2p-hrgf">GHSA-9wjq-cp2p-hrgf</a>.
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
</ul>
<h3>Improved</h3>
<ul>
<li>Harden <code>data:</code> URI mediatype parsing in
<code>Loofah::HTML5::Scrub.allowed_uri?</code>. The mediatype is now
parsed following the <a
href="https://fetch.spec.whatwg.org/#data-urls">WHATWG data: URL
spec</a> and <a href="https://www.rfc-editor.org/rfc/rfc2397">RFC
2397</a> instead of simply being split on a colon. A <code>data:</code>
URI with an omitted or malformed mediatype is now treated as
<code>text/plain</code> and allowed, and one without the required comma
is now rejected. <a
href="https://redirect.github.com/flavorjones/loofah/issues/305">#305</a>
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
<li>Remove <code>feed</code> from the default set of allowed protocols.
The <a href="https://en.wikipedia.org/wiki/Feed_URI_scheme">feed URI
scheme</a> was never accepted as a standard protocol, and no major
browser supports it. Removing it reduces the attack surface particularly
for non-browser contexts. <a
href="https://redirect.github.com/flavorjones/loofah/issues/304">#304</a>
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
<li>Remove a vestigial <code>&amp;#x70</code> alternative from
<code>Loofah::HTML5::SafeList::PROTOCOL_SEPARATOR</code>. This appears
to be an ancient typo dating back to pre-extraction Rails circa 2007. <a
href="https://redirect.github.com/flavorjones/loofah/issues/305">#305</a>
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/flavorjones/loofah/blob/main/CHANGELOG.md">loofah's
changelog</a>.</em></p>
<blockquote>
<h2>2.25.2 / 2026-07-15</h2>
<h3>Security</h3>
<ul>
<li>Ensure <code>Loofah::HTML5::Scrub.allowed_uri?</code> recognizes
numeric character references without semicolons (e.g.
<code>javascript&amp;#58alert(1)</code>), which browsers decode and
execute, and rejects schemes split by them. See <a
href="https://github.com/flavorjones/loofah/security/advisories/GHSA-5qhf-9phg-95m2">GHSA-5qhf-9phg-95m2</a>.
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
<li>Ensure <code>Loofah::HTML5::Scrub.allowed_uri?</code> recognizes the
named character references <code>&amp;Tab;</code> and
<code>&amp;NewLine;</code>, which <code>CGI.unescapeHTML</code> does not
decode and browsers strip from URIs, and rejects schemes split by them
(e.g. <code>java&amp;Tab;script:alert(1)</code>). See <a
href="https://github.com/flavorjones/loofah/security/advisories/GHSA-8whx-365g-h9vv">GHSA-8whx-365g-h9vv</a>.
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
<li>Ensure that both <code>href</code> and <code>xlink:href</code>
attributes on SVG elements like <code>use</code> are restricted to local
(same-document) references. Previously only <code>xlink:href</code> was
restricted, allowing the SVG 2 <code>href</code> attribute to reference
external documents. See <a
href="https://github.com/flavorjones/loofah/security/advisories/GHSA-9wjq-cp2p-hrgf">GHSA-9wjq-cp2p-hrgf</a>.
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
</ul>
<h3>Improved</h3>
<ul>
<li>Harden <code>data:</code> URI mediatype parsing in
<code>Loofah::HTML5::Scrub.allowed_uri?</code>. The mediatype is now
parsed following the <a
href="https://fetch.spec.whatwg.org/#data-urls">WHATWG data: URL
spec</a> and <a href="https://www.rfc-editor.org/rfc/rfc2397">RFC
2397</a> instead of simply being split on a colon. A <code>data:</code>
URI with an omitted or malformed mediatype is now treated as
<code>text/plain</code> and allowed, and one without the required comma
is now rejected. <a
href="https://redirect.github.com/flavorjones/loofah/issues/305">#305</a>
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
<li>Remove <code>feed</code> from the default set of allowed protocols.
The <a href="https://en.wikipedia.org/wiki/Feed_URI_scheme">feed URI
scheme</a> was never accepted as a standard protocol, and no major
browser supports it. Removing it reduces the attack surface particularly
for non-browser contexts. <a
href="https://redirect.github.com/flavorjones/loofah/issues/304">#304</a>
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
<li>Remove a vestigial <code>&amp;#x70</code> alternative from
<code>Loofah::HTML5::SafeList::PROTOCOL_SEPARATOR</code>. This appears
to be an ancient typo dating back to pre-extraction Rails circa 2007. <a
href="https://redirect.github.com/flavorjones/loofah/issues/305">#305</a>
<a
href="https://github.com/flavorjones"><code>@​flavorjones</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/flavorjones/loofah/commit/2706d7e858426ba856d9711b0e761b2fee7986c4"><code>2706d7e</code></a>
version bump to v2.25.2</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/1afde0cb8db147debed5d7200a7de947b09c1d9b"><code>1afde0c</code></a>
Merge pull request <a
href="https://redirect.github.com/flavorjones/loofah/issues/308">#308</a>
from flavorjones/security-2252</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/f1be9d893b5a8dd79240441a912d8897e74c38c0"><code>f1be9d8</code></a>
Update <code>allowed_uri?</code> to decode semicolon-less numeric
character references</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/5e91af861e3cdab47b91dd0b81f3afdfd13a5e19"><code>5e91af8</code></a>
Update <code>allowed_uri?</code> to handle named whitespace character
references</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/20867b9be689521887364b74822c41ef830523c9"><code>20867b9</code></a>
Properly restrict SVG href attributes</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/5f3bff46b610c1221c4bdb4e5b5b90e1178576cc"><code>5f3bff4</code></a>
test: opt into JSON comment parsing for sanitizer testdata (<a
href="https://redirect.github.com/flavorjones/loofah/issues/307">#307</a>)</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/b07713d155ec7f5ae101464f09483a45efd481c2"><code>b07713d</code></a>
test: do not run in verbose mode</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/babe7a86e808e4f4df638140bf6719d18d97ffae"><code>babe7a8</code></a>
doc: update CHANGELOG</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/a8d8d96d916f08ac46f478cbe9e8ae056c98f2b3"><code>a8d8d96</code></a>
Merge pull request <a
href="https://redirect.github.com/flavorjones/loofah/issues/305">#305</a>
from flavorjones/drop-protocol-typo</li>
<li><a
href="https://github.com/flavorjones/loofah/commit/b52f4b022db0a35f08d7f916fdf6034d312c7c8d"><code>b52f4b0</code></a>
version bump to 2.25.2.beta1</li>
<li>Additional commits viewable in <a
href="https://github.com/flavorjones/loofah/compare/v2.25.1...v2.25.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=loofah&package-manager=bundler&previous-version=2.25.1&new-version=2.25.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/alshedivat/al-folio/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [json](https://github.com/ruby/json) from 2.19.7 to 2.19.9.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ruby/json/releases">json's
releases</a>.</em></p>
<blockquote>
<h2>v2.19.9</h2>
<ul>
<li>Fix buffer overflow that could lead to a crash when writing JSON
directly into an IO
with <code>JSON.generate(object, io)</code>. [CVE-2026-54696].</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ruby/json/compare/v2.19.8...v2.19.9">https://github.com/ruby/json/compare/v2.19.8...v2.19.9</a></p>
<h2>v2.19.8</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix 1-byte buffer overread on EOS errors.</li>
<li>Handle invalid types passed as <code>max_nesting</code> option.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ruby/json/compare/v2.19.7...v2.19.8">https://github.com/ruby/json/compare/v2.19.7...v2.19.8</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ruby/json/blob/master/CHANGES.md">json's
changelog</a>.</em></p>
<blockquote>
<h3>2026-06-11 (2.19.9)</h3>
<ul>
<li>Fix buffer overflow that could lead to a crash when writing JSON
directly into an IO
with <code>JSON.generate(object, io)</code>. [CVE-2026-54696].</li>
</ul>
<h3>2026-06-03 (2.19.8)</h3>
<ul>
<li>Fix 1-byte buffer overread on EOS errors.</li>
<li>Handle invalid types passed as <code>max_nesting</code> option.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ruby/json/commit/2cff2678d5af54890a49da58345ac141b571f661"><code>2cff267</code></a>
Release 2.19.9</li>
<li><a
href="https://github.com/ruby/json/commit/fd6a65bd08e5f3a429c03919ebfd8dd19158f095"><code>fd6a65b</code></a>
generator.c: don't start with a stack buffer in IO case</li>
<li><a
href="https://github.com/ruby/json/commit/5233dd9b851a4924f793aec1a1658ed8b66a34c7"><code>5233dd9</code></a>
Release 2.19.8</li>
<li><a
href="https://github.com/ruby/json/commit/3f44b26cf34f37e97065ff37f5eaecac69d5f28e"><code>3f44b26</code></a>
Prevent buffer over-read when generating EOF error</li>
<li><a
href="https://github.com/ruby/json/commit/be8d068a8eb1124fdc2273e102dc986edf1140f7"><code>be8d068</code></a>
Handle invalid types passed as <code>max_nesting</code> option</li>
<li><a
href="https://github.com/ruby/json/commit/59501c07de4257714d94a2d5bd44f08fad1a4a4c"><code>59501c0</code></a>
Get rid of all_images gem</li>
<li><a
href="https://github.com/ruby/json/commit/c7a7b2be6f20e52439f4fdc5263e9b539fc6ad6c"><code>c7a7b2b</code></a>
Add a security note in README</li>
<li>See full diff in <a
href="https://github.com/ruby/json/compare/v2.19.7...v2.19.9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=json&package-manager=bundler&previous-version=2.19.7&new-version=2.19.9)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/alshedivat/al-folio/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Summary

Added our lab from Worcester Polytechnic Institute (WPI CHIPS Design
Studio) to the README.md file.

## Ownership Routing

- [x] I confirmed this PR targets the correct repo based on
`docs/BOUNDARIES.md`.
- [X] This PR only changes starter-owned scope (`al-folio`) **or** I am
porting a routed change and linked the owning repo issue/PR.

Owning repo (if not starter): <!-- e.g., al-org-dev/al-folio-core -->
Related issue/PR: <!-- link -->

## Plugin Ecosystem (if applicable)

- [X] Not applicable
- [ ] This PR proposes a plugin for **featured-only** listing.
- [ ] This PR proposes a plugin for **bundled** starter inclusion.

If plugin-related, provide:

- Plugin repo URL:
- Gem name:
- Jekyll plugin id:
- Compatibility (`al_folio_min`/`al_folio_max`):
- Demo page/post path:
- Maintainer contact:

## Starter Wiring Changes

- [X] Not applicable
- [ ] Updated `Gemfile` dependency wiring.
- [ ] Updated `_config.yml` plugin activation/config.
- [ ] Updated `_data/featured_plugins.yml` metadata.

## Validation

- [ ] `npm ci`
- [ ] `bundle exec jekyll build`
- [ ] `npm run lint:prettier`
- [ ] `npm run lint:style-contract`
- [ ] Integration tests (`test/integration_*.sh`) as needed
- [ ] Visual tests (`npm run test:visual`) as needed

## Notes
README-only change, no wiring or runtime impact

Compatibility, migration implications, and follow-ups:
## Summary

Adds my personal site (https://chrhenning.com/) to the user community
list in `README.md`, as invited by the "Feel free to add your own
page(s) by sending a PR" note. Single-line addition; no config, runtime,
or plugin changes.

## Ownership Routing

- [x] I confirmed this PR targets the correct repo based on
`docs/BOUNDARIES.md`.
- [x] This PR only changes starter-owned scope (`al-folio`) **or** I am
porting a routed change and linked the owning repo issue/PR.

Owning repo (if not starter): N/A — starter-owned (`README.md`)
Related issue/PR: N/A

## Plugin Ecosystem (if applicable)

- [x] Not applicable
- [ ] This PR proposes a plugin for **featured-only** listing.
- [ ] This PR proposes a plugin for **bundled** starter inclusion.

If plugin-related, provide:

- Plugin repo URL:
- Gem name:
- Jekyll plugin id:
- Compatibility (`al_folio_min`/`al_folio_max`):
- Demo page/post path:
- Maintainer contact:

## Starter Wiring Changes

- [x] Not applicable
- [ ] Updated `Gemfile` dependency wiring.
- [ ] Updated `_config.yml` plugin activation/config.
- [ ] Updated `_data/featured_plugins.yml` metadata.

## Validation

- [ ] `npm ci`
- [ ] `bundle exec jekyll build`
- [ ] `npm run lint:prettier`
- [ ] `npm run lint:style-contract`
- [ ] Integration tests (`test/integration_*.sh`) as needed
- [ ] Visual tests (`npm run test:visual`) as needed

N/A — change is a single content line in `README.md` and touches no
build, runtime, or styling paths.

## Notes

No compatibility or migration implications. Documentation/content-only
change.
## Summary

Adds my al-folio-based academic homepage to the User community →
Academics list.

Website: https://dylantao.github.io/

## Validation

Not run; README-only documentation change.

## Ownership Routing

- [x] I confirmed this PR targets the correct repo based on
`docs/BOUNDARIES.md`.
- [x] This PR only changes starter-owned scope (`al-folio`) **or** I am
porting a routed change and linked the owning repo issue/PR.

Owning repo (if not starter): <!-- e.g., al-org-dev/al-folio-core -->
Related issue/PR: <!-- link -->

## Plugin Ecosystem (if applicable)

- [x] Not applicable
- [ ] This PR proposes a plugin for **featured-only** listing.
- [ ] This PR proposes a plugin for **bundled** starter inclusion.

If plugin-related, provide:

- Plugin repo URL:
- Gem name:
- Jekyll plugin id:
- Compatibility (`al_folio_min`/`al_folio_max`):
- Demo page/post path:
- Maintainer contact:

## Starter Wiring Changes

- [x] Not applicable
- [ ] Updated `Gemfile` dependency wiring.
- [ ] Updated `_config.yml` plugin activation/config.
- [ ] Updated `_data/featured_plugins.yml` metadata.

## Validation

- [x] `npm ci`
- [x] `bundle exec jekyll build`
- [x] `npm run lint:prettier`
- [x] `npm run lint:style-contract`
- [x] Integration tests (`test/integration_*.sh`) as needed
- [x] Visual tests (`npm run test:visual`) as needed

## Notes

Compatibility, migration implications, and follow-ups:

Co-authored-by: Maruan <alshedivat@users.noreply.github.com>
…the showcase out of the README (alshedivat#3681)

A documentation overhaul in four commits. Every claim was verified
against the repo, the workflows, or the installed gem before being
changed — where a reported defect turned out to be inaccurate, it was
skipped and is called out below.

**Docs-only.** No runtime, no `test/style_contract.js`, no CI gating
changes.

---

## 1. Factual errors in user-facing guides (`59eecedd`)

| Fix | Detail |
| --- | --- |
| `QUICKSTART.md` | Told users to edit a `theme_color` key in
`_config.yml`. No such key exists — in v1.x the palette is a Sass token
owned by `al_folio_core` (`--global-theme-color` / `$purple-color`). Now
points at `CUSTOMIZE.md#changing-theme-color`. |
| `CUSTOMIZE.md` / `ANALYTICS.md` | Analytics schema corrected.
`_config.yml` ships `analytics.{google,cronitor,pirsch,openpanel}` ID
values; a provider activates when its **ID** is non-empty. |
| `CUSTOMIZE.md` | `assets/pdfs/` → `assets/pdf/` (contradicted the same
section 50 lines later). |
| `CUSTOMIZE.md` | `bin/update_citations.py` →
`bin/update_scholar_citations.py`, plus the `scholarly` dependency. |
| `CUSTOMIZE.md` | Three default collections → four (`news`, `projects`,
`books`, `teachings`), matching `collections:` in `_config.yml`. |
| `INSTALL.md` | `purgecss` is not a devDependency, so `purgecss -c
purgecss.config.js` is not runnable after `npm ci`. Documented
installing it (CI installs it globally). |
| `FAQ.md` | Two dead deployment anchors (`#deployment` on FAQ itself,
and on the README) → `INSTALL.md#deployment`. |
| `FAQ.md` | Workflow list regenerated: it documented 10 of the 19
workflows. Now complete and grouped by purpose. |
| `CONTRIBUTING.md` | Corrected the claim that `CLAUDE.md` "simply
contains `@AGENTS.md`". |

## 2. Agent-facing documentation (`7bb7e5e3`)

The ownership rule was restated in ~9 places with none declaring itself
authoritative, while the highest-value operational knowledge lived
**only** in `CLAUDE.md` — which non-Claude agents never read.

- **New `docs/ARCHITECTURE.md`** — single home for cross-repo
architecture. Leads with *"failure modes that produce no error
message"*: silent feature gating, the two-list `Gemfile`/`_config.yml`
sync, and the `--baseurl /al-folio` requirement. Also holds the
wrapper→tag→gem delegation table (moved out of `CLAUDE.md`, re-verified
against each installed gem's `register_tag` calls).
- **`AGENTS.md` rewritten** as the authoritative, tool-neutral entry
point: a change-type routing table up top, and an explicit **stop sign**
naming the paths that must not exist here.
- **`.github/copilot-instructions.md`** reduced from a verbatim
duplicate to a pointer, so the two cannot drift.
- **`CLAUDE.md`** trimmed to Claude-specific content. Three defects
fixed along the way: a stale `al_folio_core '= 1.0.9'` pin (Gemfile says
`1.0.11` — now tells you to read the Gemfile rather than quoting a
version), a hardcoded machine-specific path, and an incorrect
description of `bin/setup-python-deps` (it only pip-installs
jupyter/nbconvert and never reads `requirements.txt`).
- **Integration test count corrected** from "five" to six everywhere —
`test/integration_css_minify.sh` exists and is gated by
`unit-tests.yml`. Added the missing `bundle install` to the validated
command set.

## 3. Showcase moved out of the README (`ea6473c7`)

The table was 199 lines and ~34% of the README, sitting above both the
TOC and "Getting started".

- Extracted verbatim to **`docs/SHOWCASE.md`**. All **190 links diffed
before and after: none removed, reordered, or added.** No liveness audit
ran in this environment, so nothing was pruned.
- "Getting started" now sits directly under the badges, above the fold.
- **Add-your-site-by-PR is retired.** README, `CONTRIBUTING.md`, the PR
template, and the issue chooser now point to the *Showcase* category of
GitHub Discussions, worded to read correctly once a dedicated category
exists.
- README opening reframed from "a Jekyll theme for academics" to the
thin-starter/plugin identity.
- ⚠️ **`docs/SHOWCASE.md` added to the lychee excludes.** Those 190
community links were only unchecked because `README.md` is excluded;
moving them to a checked path would have started failing
`broken-links.yml`, which runs with `fail: true`.

## 4. Repo hygiene (`082faac9`)

- **`update-tocs.yml`**: `paths:`/`files:` globs were `*.md` / `./*.md`,
which never match `docs/*.md` — the root cause of every stale TOC under
`docs/`. Now matches both; stale TOCs regenerated.
- **`_config.yml` `exclude:`**: dropped four entries for files that now
live in `docs/`; added `AGENTS.md` and `CLAUDE.md`, which were being
**copied into `_site/` on every build**.
- **`.prettierignore`**: pruned five entries for gem-owned paths, each
verified absent.
- **`_pages/plugins.md`**: `nav: false` was hiding the plugin catalog
page the README promotes.

---

## 🔶 Maintainer decision needed: style contract vs. documented overrides

`BOUNDARIES.md` and the FAQ tell **users** that local
`_layouts`/`_includes`/`_sass` overrides are supported — but
`test/style_contract.js` fails when those directories exist, and that
check **ships to every site created from this template**. A user who
adds a perfectly legal override sees the starter's own contract check
fail in their fork.

Per instructions I **documented the distinction but changed no code**:
overrides are legal in a user's own site; the starter repo itself must
not contain them. Whether to re-scope the check to the upstream repo
only is flagged as an open decision in `ARCHITECTURE.md` and
`BOUNDARIES.md`.

## Survey claims I found inaccurate

- **"`enable_google_analytics: true` is a nonexistent key."** Not quite
— `al_analytics` **does** read it, as an optional *off-switch*. The real
problem is that the flag doesn't enable anything (the ID does), and
setting it alone is a no-op. Documented accurately rather than as
"nonexistent".
- **"The repo has ~22 workflows."** It has **19** `.yml` workflows plus
`schedule-posts.txt`, which is a disabled template, not a workflow.
- **"Showcase PR instructions in README, CONTRIBUTING, PR template, and
issue templates."** Only `README.md:34` actually had one. The other
locations were updated proactively so the new policy is visible where
people would look.

## Validation

| Check | Result |
| --- | --- |
| `npm run lint:prettier` | ✅ pass (after `npx prettier . --write`) |
| `npm run lint:style-contract` | ✅ pass |
| `bundle exec jekyll build --baseurl /al-folio` | ✅ builds (see caveat)
|
| `bundle exec al-folio upgrade audit` | ✅ Blocking: 0 |
| `bundle exec al-folio upgrade overrides audit` | ✅ no overrides |
| `bash test/integration_upgrade_cli.sh` | ✅ pass |
| Internal doc links/anchors | ✅ all resolve (scripted check across 16
files) |
| Showcase links | ✅ 190/190 byte-identical |

**Build caveat:** in this sandbox a full build fails inside
`al_ext_posts` fetching `medium.com`/`blog.google` through the HTTPS
proxy. **Confirmed pre-existing** — clean `origin/main` fails
identically. With `external_sources: []` and ImageMagick disabled
(binary absent here), the build completes in ~12s.
`integration_plugin_toggles.sh` fails for the same network reason. CI
has network and should be unaffected.

Verified in the built output: `AGENTS.md`/`CLAUDE.md` no longer leak
into `_site/`, and `/plugins/` builds and appears in the navbar.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01J5uhLakE68MtxJhRxpYL7C)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
…alshedivat#3680)

Closes alshedivat#3629 (the service-switch half of it).

## Problem

The `/repositories/` page points its stat cards at the public
**github-readme-stats** instance, which has been unreliable for a long
time — cards come back blank. Reported in alshedivat#3539, alshedivat#3388 and alshedivat#2625.

In alshedivat#3629 a maintainer of
**[github-stats-extended](https://github.com/stats-organization/github-stats-extended)**,
the actively maintained successor fork, proposed switching to it and
offered to help. This is the starter-side half of that switch.

## The swap

Per the fork's [compatibility
notes](https://github.com/stats-organization/github-stats-extended/blob/master/docs/fork.md#compatibility-notes):

> "you can change an existing stats card url from github-readme-stats to
GitHub-Stats-Extended simply by changing the domain […] The card will
look the same."

Only the host changes — `/api/` and `/api/pin/` and every query
parameter stay identical.

### Parameter mapping

| Parameter | Old | New | Note |
| --- | --- | --- | --- |
| `username` | ✓ | ✓ | identical |
| `repo` | ✓ | ✓ | identical |
| `theme` | ✓ | ✓ | `repo_theme_light` / `repo_theme_dark` keep working;
the fork ships the same [inbuilt theme
names](https://github.com/stats-organization/github-stats-extended/blob/master/packages/core/src/themes/README.md)
|
| `locale` | ✓ | ✓ | same codes, now at
[`docs/advanced_documentation.md#available-locales`](https://github.com/stats-organization/github-stats-extended/blob/master/docs/advanced_documentation.md#available-locales)
|
| `show_owner` | ✓ | ✓ | identical |
| `description_lines_count` | ✓ | ✓ | identical |
| `show_icons` | ✓ | ✓ | identical |
| `anon` | not sent | n/a | al-folio has never sent this |

**No parameter lost an equivalent.** The one documented rendering
difference is improved line wrapping for long repository descriptions.

Trophies are unchanged — `github-profile-trophy` is a separate project
and out of scope.

## Ownership

Per `docs/BOUNDARIES.md`, the includes that build these URLs are owned
by `al_folio_core`, so the runtime change lives in
**al-org-dev/al-folio-core#29**. This PR only touches starter wiring,
docs and the visual tests.

## Changes

- **`_config.yml`** — `external_services.github_readme_stats_url` →
`https://github-stats-extended.vercel.app`; `repo_theme_*` comments
repointed at the fork's theme list
- **`docs/CUSTOMIZE.md`** — updated the external-services section, plus
a new *Migrating from github-readme-stats* subsection, since existing
sites have the old host pinned in their own `_config.yml` and need to
change it by hand
- **`README.md`** — feature description links to the new project
- **`test/visual/helpers.js`**, **`test/visual/interactions.spec.js`** —
stub and match **both** hosts. This matters: the visual-regression job
diffs the candidate against a **v0.16.3 baseline** site that still
points at github-readme-stats, so both sides must be intercepted or the
parity comparison stops being deterministic.

## Testing

- `npm run lint:prettier` — *All matched files use Prettier code style!*
- `npm run lint:style-contract` — *Starter style contract check passed.*
- `bundle exec jekyll build --baseurl /al-folio` — succeeds; the
rendered `/repositories/` page emits the new host for all 9 example
repos and both user cards, e.g.

  ```

https://github-stats-extended.vercel.app/api/pin/?username=alshedivat&repo=al-folio&theme=default&locale=en&show_owner=false&description_lines_count=2

https://github-stats-extended.vercel.app/api/pin/?username=jekyll&repo=jekyll&theme=dark&locale=en&show_owner=true&description_lines_count=2

https://github-stats-extended.vercel.app/api/?username=alshedivat&theme=default&locale=en&show_icons=true
  ```

with `show_owner` correctly `true`/`false` per repo, both light
(`theme=default`) and dark (`theme=dark`) variants present, and trophy
URLs untouched.

(Three unrelated environment gaps had to be worked around for that build
— no `jupyter-nbconvert`, no ImageMagick `convert`, and no outbound
network for `al_ext_posts` — none of them related to this change.)

### Live service check — not possible here

**I could not obtain live HTTP status codes.** This session's egress
policy rejects both hosts at the proxy with `403` on `CONNECT`, before
anything reaches the service:

```
github-stats-extended.vercel.app  → curl: (56) CONNECT tunnel failed, response 403
github-readme-stats.vercel.app    → curl: (56) CONNECT tunnel failed, response 403
```

The **old** host is blocked identically, so this is a sandbox
restriction and is not evidence about either service. **The 403s are the
proxy's, not the service's — please open one of the URLs above before
merging to confirm a card actually renders.**

## Dependency between the two PRs

They are **independent** — neither blocks the other:

- **This PR alone** already switches the starter site, because the
includes read the URL from `_config.yml` and that works on the currently
pinned `al_folio_core = 1.0.11`.
- **al-org-dev/al-folio-core#29** changes the built-in *default* (for
sites with no `external_services:` block, which previously got a broken
relative URL) and repoints the in-template doc links.

The `Gemfile` pin is deliberately left at `= 1.0.11` here, since 1.0.12
is not published yet. Once core#29 is released, bump it to `= 1.0.12` in
a follow-up.

## Not addressed

alshedivat#3629 also floats a second idea — an optional integration with
[github-readme-stats-action](https://github.com/stats-organization/github-readme-stats-action),
which commits generated SVGs from a workflow instead of hotlinking a
live service. That is a separate feature and is not part of this PR; the
issue is worth keeping open for it.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01J5uhLakE68MtxJhRxpYL7C)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Replaces the dead `api.star-history.com` hotlink with a chart generated
in-repo and refreshed automatically.

## Why

**1. The service is down for everyone.**

```
$ curl "https://api.star-history.com/svg?repos=alshedivat/al-folio&type=Date"
HTTP 500 — Repo alshedivat/al-folio: timeout of 10000ms exceeded
```

5/5 attempts failed, and it reproduces on unrelated repos including
`octocat/Hello-World` (2 stars) — so it's a service-wide backend
failure, not our repo or its size. Their website root returns 200;
specifically the SVG endpoint is broken.

**2. It now asks visitors for a token that can push code.**

star-history.com prompts for a GitHub token with **`Contents: read and
write`**, claiming "the stargazers endpoint now requires contents
write". That claim is false. Unauthenticated, no headers beyond
`Accept`:

```
GET /repos/alshedivat/al-folio/stargazers            -> 200
     Accept: application/vnd.github.star+json        -> 200, with starred_at timestamps
GET /repos/alshedivat/al-folio                       -> stargazers_count = 15931
```

`Contents: write` is the permission to **push code**. For a template
this widely forked, that's not a dependency worth keeping even if the
backend recovers.

## What this does

- **`bin/generate_star_history.py`** — fetches the public stargazer
timestamps and renders light + dark SVGs. No third-party services, no
runtime dependencies, stdlib only.
- Samples ~28 pages across the history instead of fetching all ~160, so
a refresh is ~29 requests.
- Anchors the final point at the **most recent star**, not "now", so
repeated runs are byte-identical rather than producing a daily no-op
commit. Verified: two consecutive runs → same md5.
- **`.github/workflows/star-history.yml`** — regenerates on every push
to `main`, weekly on a schedule, or on demand; commits only when the
chart actually changed.
- **`README.md`** — serves the committed assets via the existing
`<picture>` + `prefers-color-scheme` pattern, so it can't 500 and can't
prompt anyone for anything. Links to the stargazers page instead of
star-history.com.

## Loop and blast-radius guards

Two things I was careful about, since this workflow commits to the
branch that triggers it:

- **No self-retrigger.** `paths-ignore` on the generated SVGs means the
bot's own commit — which touches nothing else — can't retrigger the
workflow. (GitHub also declines to raise `push` events for commits made
with `GITHUB_TOKEN`, so there are two independent guards.) Plus
`concurrency` so two runs can't race to commit.
- **Doesn't leak to template users.** Gated on `github.repository ==
'alshedivat/al-folio'`, matching the existing convention in
`broken-links.yml`. Without it, every site generated from this template
would spend Actions minutes charting someone else's repo and committing
files they never asked for.

`GITHUB_TOKEN` is passed only to lift the API rate limit from 60/hr to
5000/hr — the data itself is public, and no personal or scoped token is
involved.

## Result

15,931 stars, 29 sampled points, 2016-09-21 → 2026-07-28, styled with
al-folio's own palette (`#b509ac`, and a lightened `#d94fd0` on dark for
contrast against `#1c1c1d`).

## Verified

- Rendered both SVGs in headless Chromium and reviewed them; fixed one
real defect found that way — year ticks were derived from sampled data
points, so the sparse early years never appeared and the axis jumped
2016 → 2020. Ticks are now calendar-based.
- Both files parse as valid XML.
- `npm run lint:style-contract` → passed.
- `npm run lint:prettier` → the repo currently fails on three unrelated
docs files; that is **pre-existing on `main`** and fixed separately in
alshedivat#3683. This branch adds no new Prettier failures.

## Note

`main` is protected, so if the Actions bot can't push directly the
workflow will fail loudly rather than silently. If you'd rather it
opened a PR per refresh instead of committing, say so and I'll switch
it.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01J5uhLakE68MtxJhRxpYL7C)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
…at#3685)

The first real run of the star-history workflow (from the alshedivat#3684 merge)
**failed**. Fixing it.

## Not what I expected

I'd flagged branch protection as the likely failure mode. It wasn't —
the chart generated fine (61s, exit 0) and the push was rejected as a
plain non-fast-forward:

```
error: failed to push some refs to 'https://github.com/alshedivat/al-folio'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally.
```

## It's a race between two workflows that both commit to main

```
03:28:52  star-history checks out ffee0cd
03:29:05  update-tocs pushes 5808e06 "Auto update markdown TOC"   ← main moves
03:29:55  star-history finishes generating (61s of API sampling)
03:29:56  push rejected — main had moved 51 seconds earlier
```

`update-tocs.yml` triggers on the same push and finishes in ~15s; chart
generation takes ~61s because it samples 29 pages of the stargazers API.
Any merge touching markdown fires both, so **this would recur
routinely** — it isn't a one-off.

Worth noting the two guards I built in did work as designed:
`paths-ignore` and the `GITHUB_TOKEN` rule prevent the workflow
retriggering *itself*. Neither addresses a *sibling* workflow moving the
ref, which is what happened.

## Fix

Rebase onto the new tip and retry, up to three attempts:

```bash
for attempt in 1 2 3; do
  if git push; then
    echo "Pushed on attempt ${attempt}."
    exit 0
  fi
  echo "Push rejected (main moved); rebasing onto origin/main and retrying."
  git pull --rebase origin main
done
echo "::error::Could not push the refreshed chart after 3 attempts."
exit 1
```

Only the two generated SVGs are ever in flight, and nothing else writes
them, so the rebase has no realistic conflict. A genuine failure after
three attempts still fails the run loudly rather than silently skipping
the refresh.

## Note on the current chart

`main`'s committed SVGs are from the PR branch and are slightly stale
(they were generated before the last few stars). The next successful run
— this merge will trigger one — refreshes them. Nothing is broken in the
meantime: the README renders the committed assets either way, which was
the point of self-hosting.

`prettier --check` clean; workflow YAML parses.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01J5uhLakE68MtxJhRxpYL7C)_

Co-authored-by: Claude <noreply@anthropic.com>
…ader (alshedivat#3682)

All eight gems that had unreleased work sitting on `main` are now
published, so the starter can move off the pins it has been stuck on.
They bump together here because one of them changes behaviour that
`_config.yml` gates.

| gem | from | to |
| --- | --- | --- |
| `al_folio_core` | 1.0.11 | **1.0.12** |
| `al_folio_cv` | 1.0.0 | **1.0.1** |
| `al_folio_distill` | 1.0.2 | **1.0.3** |
| `al_analytics` | 1.0.0 | **1.0.1** |
| `al_ext_posts` | 1.0.1 | **1.0.3** (1.0.2 was never published either)
|
| `al_img_tools` | 1.0.2 | **1.0.3** |
| `al_search` | 1.0.2 | **1.0.3** |
| `al_math` | 1.0.1 | **1.0.2** |

## The Distill loader, and why it is in this PR

`_config.yml` shipped `al_folio.distill.allow_remote_loader: true`.
Under 1.0.2 that flag only gated a log line, so it was inert. **1.0.3
turns it into a real switch**: `true` opts the site out of the vendored,
hash-pinned Distill runtime and back onto
`https://distill.pub/template.v2.js`, fetched with **no subresource
integrity**.

Bumping the pin without flipping the flag would ship that gem's entire
hardening with its protection turned off — for this site, and for every
site generated from this template. So the flag flips here, in the same
change as the pin.

This is not a stylistic preference: `al-folio upgrade audit` enforces
the pairing. `check_distill_runtime` returns early while the flag is
`true`, so splitting the two produces a **blocking** finding. That is
also the correction to what I said earlier about alshedivat#3682 being mergeable
on its own — it was not.

Verified on the rendered post at `/blog/2021/distill/`:

```html
<script src="/al-folio/assets/js/distillpub/template.v2.js"   integrity="sha256-R5CDHO0C98TyAJss32l4ztqDUfAGDTtZ3Zs6qxMuJxo=">
<script src="/al-folio/assets/js/distillpub/transforms.v2.js" integrity="sha256-XYVZD1ZSuRCrJBEBl0nIPvWlo/u5tzmtyStFV7a/PTk=">
```

Both local, both integrity-pinned, and no page in the built site
references `distill.pub/template`.

## Also here

- **`test/integration_distill.sh`** asserted the 1.0.2 transforms
runtime hash. Rehashed against the *published* 1.0.3 gem rather than a
computed guess: `70e3f488…` → `5d85590f…`.
- **Dropped the dead `third_party_libraries.polyfill` entry.** `al_math`
1.0.2 stopped emitting the polyfill.io tag, and no gem reads that config
key. Confirmed absent from the built site.
- **`test/style_contract.js` hard-coded `al_math '= 1.0.1'`**, so this
bump would have failed the style contract. Relaxed to assert an exact
released pin of *any* version — the boundary the check actually exists
to protect — keeping the separate check that rejects a git-branch pin.
Otherwise every routine version bump trips a gate that is meant to guard
the thin-starter contract, not the version number.

Left alone deliberately: the `jquery` and `mdb` entries are also unread
by any gem, but `al_folio_upgrade` carries a `legacy_jquery_usage` audit
rule keyed on `third_party_libraries.jquery`, so removing those wants
its own pass.

## Verification

- `bundle install` — all eight resolve from RubyGems
- all six `test/integration_*.sh` — pass
- `npm run lint:style-contract`, `npm run lint:prettier` — pass
- `bundle exec al-folio upgrade audit` — **Blocking: 0**, Non-blocking:
6
- built site smoke-checked: MathJax present, `swiper@12.1.2` (the CVE
fix), repo cards on `github-stats-extended` with zero remaining
`github-readme-stats` references, CV page renders all sections

Co-authored-by: Claude <noreply@anthropic.com>
…lytics providers (alshedivat#3687)

Both gems published after al-org-dev/al-folio-cv#7 and
al-org-dev/al-analytics#14 merged.

| gem | from | to |
| --- | --- | --- |
| `al_folio_cv` | 1.0.1 | **1.0.2** |
| `al_analytics` | 1.0.1 | **1.0.2** |

`al_folio_cv` 1.0.2 fixes CV entries with a bare `date` rendering no
badge (alshedivat#3339), plus empty date badges in the awards and publications
sections.

## Why the config changes ship with the pins

A provider that exists in the gem but is absent from `_config.yml` and
the docs is invisible — the second of the three silent failure modes in
`AGENTS.md`. **Two** providers were in that state:

- **Cloudflare Web Analytics** — new in `al_analytics` 1.0.2, fixes
alshedivat#3351
- **Simple Analytics** — shipped in `al_analytics` **1.0.1**, pinned
since the last release, and never documented. It has been reachable but
undiscoverable this whole time.

Both are now in the `analytics:` block and in `docs/ANALYTICS.md`.

Cloudflare follows the existing convention exactly: set
`analytics.cloudflare` to the beacon token and it turns on, with
`enable_cloudflare_analytics` as an optional off-switch, same as every
other provider.

Simple Analytics **cannot** follow it, and that is worth being explicit
about. It identifies a site by its domain, so there is no ID to put in
the block and therefore nothing for the plugin to infer intent from —
the flag alone controls it. A user who expects the usual "set the ID and
it works" pattern gets silence. The asymmetry is called out both in
`docs/ANALYTICS.md` and in the config comment.

`enable_simple_analytics: false` is written out explicitly rather than
left unset. Both mean off; the explicit form puts the option in the file
where users actually go looking.

## Verified

Built the site both ways rather than trusting the templates:

**No token, flag false** — zero occurrences of `cloudflareinsights` or
`simpleanalyticscdn` anywhere in the output. No beacon tag with an empty
token.

**Token set, flag true:**

```html
<script defer src="https://static.cloudflareinsights.com/beacon.min.js" data-cf-beacon='{"token": "0123456789abcdef0123456789abcdef"}'>
<script async src="https://scripts.simpleanalyticscdn.com/latest.js">
```

The Cloudflare markup matches the snippet in Cloudflare's dashboard byte
for byte. (Test token used only for the build; the committed config
ships empty.)

Also: all six `test/integration_*.sh` pass, `lint:prettier` and
`lint:style-contract` pass, and `al-folio upgrade audit` reports
**Blocking: 0**.

## Deliberately not included

The `apple_touch_icon` documentation and asset, which depend on
al-org-dev/al-folio-core#36 and `al_folio_core` 1.0.13. Documenting that
key now would describe something that does nothing — the same failure
this PR is fixing for the two analytics providers. It follows once
core#36 merges and the gem publishes.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01J5uhLakE68MtxJhRxpYL7C)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
…edivat#3688)

Merging this makes cutting v1.1 a one-click dispatch instead of a manual
step.

## Why

Creating a release means creating a tag, and pushing to `refs/tags/*`
fails with **HTTP 403** from my environment — I retried with three
different refspec forms (`refs/tags/v1.1`, a lightweight local tag, and
`origin/main:refs/tags/v1.1`); all rejected, and the ref never lands.
Branch pushes are fine. So releases have been a step only you could
perform.

This moves tag creation onto the runner, where `GITHUB_TOKEN` already
has `contents: write` and `gh release create` creates the tag as part of
publishing.

## How notes work

Read from `docs/releases/<tag>.md`, **not** a dispatch input. That
means:

- they get reviewed in a PR before they can ever be published
- the repo keeps a record of what each release claimed
- a release can't be cut with hastily typed or missing notes

## Guards

Publishing is hard to walk back once people have fetched the tag, so:

- the tag must look like a version (`v1.1` or `v1.1.0`)
- **refuses if the tag already exists**, rather than moving it
- refuses if the notes file is missing or empty
- `draft: true` by default, so the normal path is to read it before it
goes public
- `workflow_dispatch` only — nothing fires on a push
- gated on `github.repository == 'alshedivat/al-folio'`, matching
`star-history.yml`, so sites generated from this template don't carry a
workflow that cuts releases of *your* project

## Also here

**`docs/releases/v1.1.md`** — the v1.1 notes. Headline is that this is a
security release: the Swiper prototype-pollution CVE (CVSS 9.4), the
polyfill.io supply-chain tag, and the Distill runtime that was silently
discarding its own hash-pinned copy to load from `distill.pub` with no
SRI. Plus blank repo cards, off-screen mobile submenus, relative
`og:image`, the CV ordering fix, empty external-post titles, the docs
pass, and the release automation. Gem versions were checked against the
actual `Gemfile` at the `v1.0` tag rather than the v1.0 release prose.

**`broken-links.yml` excludes `docs/releases`** — release notes link to
the compare range for the tag they're about to create, which can't
resolve until the release exists. I confirmed `compare/v1.0...v1.1`
returns 404 today, so without this the link checker fails on every
release PR.

(`update-tocs.yml` matches `docs/*.md`, not `docs/**/*.md`, so notes
files don't get a TOC — verified.)

## After merge

I dispatch `Create release` with `tag: v1.1` and `draft: false`, and
v1.1 is out. No tag push needed from either of us.

## One thing to decide

**alshedivat#3687 is green and unmerged.** It pins `al_folio_cv 1.0.2` (the CV
bare-`date` fix, alshedivat#3339) and `al_analytics 1.0.2` (Cloudflare Web
Analytics, alshedivat#3351). As written, these notes describe `main` *without* it,
so v1.1 would ship without those two.

If you'd rather they were in v1.1, merge alshedivat#3687 as well and I'll update
the notes before dispatching. Either is fine — just don't want to
release notes that understate what shipped.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01J5uhLakE68MtxJhRxpYL7C)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
The fork was last synced against a pre-v1.0 al-folio, where layouts, includes
and styles lived in this repo. al-folio v1.x moves all of that into the
al_folio_core / al_* gem family, so this merge deletes the local copies and
keeps only files we intentionally customise as overrides.

Overrides kept (gem-owned paths):
  _includes/figure.liquid       skip webp srcset for GIFs; pass `style` through
  _includes/footer.liquid       Umami analytics (al_analytics has no Umami provider)
  _includes/header.liquid       navbar wordmark via site.logo.*
  _includes/repository/repo.liquid  pin show_owner=false across our three orgs
  _layouts/about.liquid         hide title/subtitle, capitalised section headings
  _layouts/bib.liquid           publications/ preview dir, DOI button suppressed
  _layouts/page.liquid          team profile portraits + GitHub README embed
  assets/css/main.scss          adds `@use "custom"`

Overrides dropped, now covered upstream or by config:
  _includes/repository/repo_user.liquid  stats host is now external_services.*
  _includes/social.liquid       replaced by a jekyll-socials custom entry
                                (linkedin_company) in _data/socials.yml
  _sass/_base.scss              pre-v1 monolith; the two site rules moved to
  _sass/_themes.scss            _sass/_custom.scss (theme-aware-logo was dead CSS,
                                and v1 handles the tri-state theme toggle natively)

Also: _pages/code.md passes repository=repo.id so the gem include works with our
object-form _data/repositories.yml; upstream demo content this fork had already
removed stays removed; feedjira/httparty dropped (unused - the profile-readme
plugin uses stdlib open-uri).

Picks up the v1.1 security fixes: Swiper 12.1.2 (CVE-2026-27212, CVSS 9.4),
polyfill.io removed from MathJax, and Distill's remote loader disabled
(allow_remote_loader: false).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three follow-ups from verifying the v1.1 build:

- `_includes/header.liquid`: the logo `alt` chained `site.title | default: ... |
  append: site.middle_name | append: site.last_name`, so with a non-blank
  `site.title` it appended the name parts anyway and rendered "Sustainable Urban
  Systems Lab Urban Systems Lab". Now it picks one branch or the other. This bug
  predates the migration; fixing it here since the file was being rewritten.

- `_config.yml`: exclude `test/`. v1.1 ships a Playwright/integration harness in
  the starter but does not exclude it, so the specs and shell scripts were being
  published to the live site.

- `.al-folio-overrides.yml`: records the 8 intentional overrides with the upstream
  checksums they were reviewed against, so `al-folio upgrade overrides audit` can
  flag drift on future gem bumps.

Verified in Docker (ruby 3.3.12): jekyll build clean, `al-folio upgrade audit`
reports 0 blocking findings, and the resolved gems include al_img_tools 1.0.3,
al_math 1.0.2 and al_folio_distill 1.0.3 — the three carrying the v1.1 security
fixes. Swiper resolves to 12.1.2 with matching SRI hashes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for sustainableurbansystems ready!

Name Link
🔨 Latest commit f3a8892
🔍 Latest deploy log https://app.netlify.com/projects/sustainableurbansystems/deploys/6a6af52d3828330008501631
😎 Deploy Preview https://deploy-preview-50--sustainableurbansystems.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 81
Accessibility: 98
Best Practices: 83
SEO: 100
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@kastnerp
kastnerp marked this pull request as ready for review July 30, 2026 06:56
@kastnerp
kastnerp merged commit af53bd8 into dev Jul 30, 2026
6 checks passed
@kastnerp
kastnerp deleted the chore/al-folio-v1.1 branch July 30, 2026 06:56
kastnerp added a commit that referenced this pull request Jul 30, 2026
* Update dogan.md

* Team Updates

* Team Updates

* Update thach.md

* Update gomez.md

* GitHub profile autoinclude

Update page.liquid

.

* GitHub autoinclude

* Update yang.md

* fixed run files

* Update gt-arch-7014.md

* Update gt-arch-7014.md

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* feat: add Code tab and GitHub repo cards

* feat: add Code tab and GitHub repo cards

* Update li.md

* Update join.md

* Update Google Scholar citations

* Add news posts for Sina defense and CHHS talk

* Update Google Scholar citations

* Update Google Scholar citations

* Update remote_include URL in thach.md (#37)

* Fix repository page layout

* Improve repository card title overflow

* Restore repository card design

* Update almaian.md

* Update _base.scss

* Update almaian.md

* .

* Update repo.liquid

* Update karadag.md

* Add Shen visit news post

* Normalize image asset paths

* Prevent team avatar footer overlap

* Add Cypress thesis defense news post

* Add Jimmy team profile (#39)

* Jimmy Miao Zhang

* Jimmy Miao Zhang Profile Photo

* Revise Jimmy's profile details and image

Updated profile information for Jimmy Miao.

* Update and rename jimmy.md to miao.md

* Update miao.md

* Update Google Scholar citations

* Update Google Scholar citations

* Create announcement_43.md

* Add MT projects for Benjamin Shih and Joseph Aerathu

* Fix video rendering on Joseph Aerathu project page

* Add project links to team pages

* Add CP-GNI2024-Symposium-Enriching-geospatial-building-datasets project (#41)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update title to 'Jimmy Miao Zhang' (#40)

* Update Google Scholar citations

* Update papers.bib with missing code links (#43)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update Google Scholar citations

* Update about.liquid

* Add Karadag 2026 publication (#44)

* Add Karadag 2026 urban wind simulation publication

- Added the BibTeX entry for `KARADAG2026107614` to `_bibliography/papers.bib`.
- Associated the publication with the `cfdgan-compressed.gif` preview image.
- Added the `bibtex_show` field to the new entry.
- Added `2026` to `years_papers` in `_pages/research/children/publications.md` so the newly added publication is rendered on the website.

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Add specific karadag image to publication

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Change publication preview image to abstract screenshot

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update karadag_abstract.png

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Fix formatting of year fields in _bibliography/papers.bib (#46)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update Google Scholar citations

* Dynamically pull Sina Rahimi's PhD README in project page (#47)

Replaced the hardcoded source link in `_projects/PhD-SinaRahimi.md` with a Liquid remote_include block that fetches and displays the actual GitHub README.md content.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update Google Scholar citations

* Update Google Scholar citations

* fix: switch repo cards to working github-readme-stats deployment (#49)

Public instance github-readme-stats.vercel.app returns 503
DEPLOYMENT_PAUSED, breaking all repo card images on /code/.
Point at the author's working deployment alias instead.

Co-authored-by: Patrick Kastner <1919773+kastnerp@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Add new display categories in theses.md (#48)

* Add new display categories in theses.md

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Add new display categories in theses.md

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Integrate new projects and update bibtex

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Integrate new projects and update bibtex

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update bibtex fields and add macadThesis24

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Remove macadThesis24

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update Google Scholar citations

* Add Best Poster Award details to Maryam SimBuild 2026 post

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Add SimBuild 2026 award photo and certificate to Maryam post

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Update Google Scholar citations

* Update socials.yml

* Update Google Scholar citations

* Update to al-folio v1.1 (v0 → v1 gem architecture migration) (#50)

* Added support for helping agents (#3379)

Since a lot of our users don't have a coding background and given
recently development with AI agents, I decided to try to add support for
specialized agents in our repository. They were created following
[agents.md](https://agents.md/) "specifications" and are currently 2:
- `customize-agent` - to help new users with access to GitHub Copilot
customize their site
- `docs-agent` - to help us keep the documentation always updated with
the latest changes in our code

I don't really know how useful they'll actually be, but I think most of
our users might actually benefit from the `customize-agent`, so it is
worth a shot.

<img width="852" height="1043" alt="image"
src="https://github.com/user-attachments/assets/e8390f1a-cec3-42a8-b01e-26d658ea78e8"
/>

Edit: also added a link to a [Code Wiki to our
repository](https://codewiki.google/github.com/alshedivat/al-folio) and
[DeepWiki](https://deepwiki.com/alshedivat/al-folio). This allows any
user to chat online with AIs (Gemini and Devin) about our repository.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Auto update markdown TOC

* Fix bib / code layout bug (#3387)

Resolve #3370
Resolve #3380

Based on the
[comment](https://github.com/alshedivat/al-folio/issues/3370#issuecomment-3565962058)
of @MarkusThill, I created a bugfix that solved the issue on my website.
Hope that fixes it in general; thus the PR :) However, I'm not an expert
for scss .. so handle with care :)

* Fix: bibliography month persists to subsequent entries without month (#3391)

Fixes #3386 (the part about the wrong months; the other part (layouting
of bibtex) is fixed in #3387)

## Summary
- Fixes incorrect month shown for bibliography entries that do not
specify a `month` in BibTeX.
- Ensures `month`/`year` do not persist between entries in
`_layouts/bib.liquid`.

## Root Cause
- In Liquid, captured variables persist across iterations if not
reinitialized.
- `entrymonth` and `entryyear` were only set when
`entry.month`/`entry.year` existed, causing values from a previous entry
to leak into the next one when those fields were missing.

## Changes
- Reinitialize date-related variables per entry before conditional
captures:

## Behavior
- Before: Entries without a `month` could display the previous entry's
month.
- After: Entries without a `month` display only the `year`; entries with
a `month` display the correct month and year.


<img width="1956" height="918" alt="image"
src="https://github.com/user-attachments/assets/7a9682e7-55ab-43b7-8f82-f638d14ce08e"
/>

* Fixed 1 px first load issue (#3416)

Fix #3164

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Added support for default categories and tags for external posts (#3417)

Based on discussion #3393.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Add link to personal GitHub page on academics section in README (#3400)

* Add auto-orient flag to Imagemagick config (#3409)

Currently, images generated by Imagemagick do not respect the
orientation of the source image. By adding the auto-orient flag, the
images are the correct orientation.

Before
<img width="920" height="562" alt="image"
src="https://github.com/user-attachments/assets/73f59d7f-b6c5-468a-9023-0f0457a53a3c"
/>

After
<img width="947" height="621" alt="image"
src="https://github.com/user-attachments/assets/2f24de99-2e84-4052-8d0f-945acdad81e4"
/>

* Update deps (#3418)

Closes #3402

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Added new line to README badges

* Changed maintainers urls to https

* Updated prettier (#3420)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Fix typo in Bootstrap small column class usage (#3421)

This PR fixes a recurring typo in multiple Liquid templates where the
Bootstrap class `cl-sm` is used instead of `col-sm`.

Because of this typo, the `col-sm` styling was not being applied. All
instances have been corrected.

* Update Google Scholar citations

* Make external service URLs configurable for repository page (#3422)

## Description

This PR makes the URLs for external services used on the repository page
configurable in `_config.yml`. This allows users to self-host these
services for better reliability, privacy, and customization.

## Changes

- Added `external_services` configuration section in `_config.yml` with:
- `github_readme_stats_url` (default:
`https://github-readme-stats.vercel.app`)
- `github_profile_trophy_url` (default:
`https://github-profile-trophy.vercel.app`)
- Updated repository template files to use configurable URLs:
  - `_includes/repository/repo_user.liquid`
  - `_includes/repository/repo.liquid`
  - `_includes/repository/repo_trophies.liquid`
- Added documentation in `CUSTOMIZE.md` explaining:
- Why self-hosting is recommended (default services may have
availability issues)
  - How to configure custom service URLs
  - Links to the service repositories for deployment instructions

## Resolves

Resolves #3388 - This makes it possible to configure self-hosted
versions of these services, giving users full control over the external
services used for displaying GitHub statistics and trophies.

## Testing

- Verified that default configuration still works with original service
URLs
- Confirmed that URLs are properly interpolated in all template files
- Documentation clearly explains the configuration options

* Auto update markdown TOC

* Remove link to sam-bieberich.github.io (#3425)

Removed a link to sam-bieberich.github.io from the README.

* Add link to personal GitHub page on academics section in README (#3424)

* Add j1yoo.github.io to User community (#3427)

Hi! I'd like to add my academic website to the User community section.

**Website:** https://j1yoo.github.io/

This PR adds a single star link to the Academics row in the User
community table.

Thank you for creating and maintaining this beautiful theme!

Co-authored-by: Jaewon Yoo <jwyoo4@gmail.com>

* add filtered BibTeX keywords (#3403)

add `dimensions, eprint` and `pmid` to the filtered keywords

* Add HAL button (#3404)

Adds a HAL button in the same spirit as the arXiv button.
- add HAL button to `_layouts/bib.liquid`
- add `hal` to the filtered keywords in `_config.yml`
- add `hal` to the documentation  in `CUSTOMIZE.md`

* Improved collections section in CUSTOMIZE guide (#3431)

Improved section based on comments from #2369.

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Add zhoji.github.io to User community in README.md (#3433)

Adding my personal website for the al-folio community :) Thanks for
creating such a cool template!

* Changed code to use plugin to handle 3rd party libraries downloads (#3435)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Changed to use cache bust plugin (#3436)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Update deps (#3437)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Changed to use jekyll-socials plugin (#3439)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Updated deps and deploy version (#3440)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Fixed dates in book-shelf (#3446)

Fixes #3443.

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Updated deps to fix issue with jekyll-socials (#3447)

Fixes #3445

Signed-off-by: George Araújo <george.gcac@gmail.com>

* ⚡ Optimize Google Scholar Citations Regex Definition (#3449)

💡 **What:** Moved the regex definition `/Cited by (\d+[,\d]*)/` from the
method scope to a class-level constant `CITED_BY_REGEX`.

🎯 **Why:** To improve code cleanliness and avoid potential re-definition
of the regex object in every method call (or loop), adhering to best
practices.

📊 **Measured Improvement:**
* **Baseline:** The regex was defined as a literal inside the `render`
method, which is called for each tag usage.
*   **Optimization:** The regex is now defined once as a constant.
* **Note:** Performance benchmarks were not possible in the current
environment due to missing Ruby runtime. However, this is a standard
Ruby optimization that improves maintainability and theoretically avoids
object allocation overhead in older Ruby versions or complex scenarios.
Modern Ruby optimizes literals well, but the constant approach is
cleaner and DRYer.

---
*PR created automatically by Jules for task
[10688912524063334698](https://jules.google.com/task/10688912524063334698)
started by @alshedivat*

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

* Refactor: Use Liquid filter to find home page title (#3448)

Refactored the script in _scripts/search.liquid.js to use a more
efficient Liquid 'where' filter to find the home page title. This
replaces an inefficient for loop that iterated through all site pages.

---
*PR created automatically by Jules for task
[5748098109809984605](https://jules.google.com/task/5748098109809984605)
started by @alshedivat*

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

* Revert "Refactor: Use Liquid filter to find home page title" (#3451)

Reverts alshedivat/al-folio#3448

* Updated jekyll-archives-v2 (#3460)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Add course schedule feature to teaching page (#2258) (#3147)

Implements the course schedule feature requested in issue
#[2258](https://github.com/alshedivat/al-folio/issues/2258).

This PR adds a new course schedule feature to the al-folio theme,
allowing academics to easily create and display structured course
information.

**Changes:**
- Added a `courses` collection to organize and display academic courses
- Created course layout and display templates with responsive design
- Implemented organization by year and term with automatic sorting
- Added support for weekly schedule with topics and course materials
- Simplified documentation with a README for course creation

This feature makes it easier for academics to showcase their teaching
materials with a consistent, organized display of course schedules,
helping users create professional teaching pages without custom
implementation.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Add calendar iframe and togglAdd calendar iframe and toggle buttone button (#3144)

### Description

This PR adds a Google Calendar integration feature as described in issue
#872. Users can embed their own calendar using an iframe configured via
`_config.yml`, and the calendar is toggleable through a responsive
button. This component is styled to visually blend into the theme and
supports responsive display across desktop and mobile.

### Changes
- Added `calendar.liquid` in `_includes`
- Modified `about.md` to include the toggleable calendar block
- Introduced `calendar` config section in `_config.yml`
- Appended calendar-related styles in `_sass/_base.scss`

### Configuration
To enable this feature, add the following to `_config.yml`:
```yaml
calendar:
  enabled: true
  calendar_id: your_calendar_id@group.calendar.google.com
  timezone: UTC
  style: "border:0; width:100%; height:600px;"

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: dodo <349507644@qq.com>
Co-authored-by: George <31376482+george-gca@users.noreply.github.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>

* Update Google Scholar citations

* Updated jekyll-socials to latest version (#3464)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Add smsnoBin77 link to README (#3473)

Add a new link to the README for smsnoBin77.

* Unify jsonresume and RenderCV CVs solutions (#3462)

Fixes #2787 as an alternative to #2969. It was getting too cumbersome to
have 2 different data sources for CV and also a lot of different layout
files, so I decided to unify them all.
Main changes:
- synchronized the information inside RenderCV (`_data/cv.yml`) and
JSONResume (`assets/json/resume.json`)
- unified layout files for CV information
- added the option to set the "data source" in the CV page

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: render the latest CV

* Rendercv missing commits (#3475)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* chore: render the latest CV

* Update Google Scholar citations

* Update SASS syntax in base (non-font) files (#3281)

Partially fixes issue #3256 by updating SASS syntax in main SCSS files.

To fully address the issue, FontAwesome should be updated to `v7.x` and
Tabler to `v3.30` or higher (see Tabler fix
[here](https://github.com/tabler/tabler-icons/pull/1256)), where the
SCSS has been fixed.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Improve readme, add site-wide CSP (#3485)

This pull request significantly expands and clarifies the documentation
for the al-folio Jekyll theme, focusing on improved file structure
explanations, enhanced quick reference guides, and the addition of a
comprehensive analytics setup guide. The changes make it easier for
users and contributors to understand the project organization, available
features, and configuration options, especially regarding CV formats,
teaching pages, and analytics integration.

**Key documentation and structure improvements:**

*Expanded file and collection structure:*
- The file structure documentation in
`.github/agents/customize.agent.md` and `.github/agents/docs.agent.md`
now details all major directories, including new and existing
collections such as `_books/`, `_teachings/`, `_scripts/`, `_plugins/`,
and expanded `assets/` subdirectories. It also covers new configuration
and utility files, making it easier for users to locate and understand
the purpose of each file or folder.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)

*Documentation and quick reference enhancements:*
- The quick reference table in `.github/agents/customize.agent.md` has
been updated to include new actions like adding teaching pages, setting
up analytics, improving SEO, and ensuring accessibility, with more
precise documentation links.
- The documentation map now lists all major guides (e.g.,
`QUICKSTART.md`, `INSTALL.md`, `TROUBLESHOOTING.md`, `ACCESSIBILITY.md`,
`ANALYTICS.md`, `SEO.md`), providing a clearer overview of available
resources.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L58-R110)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)

**Feature and configuration documentation updates:**

*CV/resume format guidance:*
- The CV documentation now clarifies that users can maintain both
RenderCV and JSONResume formats simultaneously, with clear instructions
on switching between them and deleting unused files if desired.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L139-R185)
[[2]](diffhunk://#diff-52f2a9488bfe4177d1f1d01120859dad0b3e2d087283ded68f72d47b4f183391L291-R291)

*Teaching pages and new collections:*
- Adds documentation for the new `_teachings/` collection, including
required frontmatter and support for course materials, as well as
updates to enable/disable teaching and books pages via `_config.yml`.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)

*Analytics integration:*
- Introduces a new `ANALYTICS.md` guide with detailed setup instructions
for Google Analytics, privacy-friendly alternatives (Plausible, Pirsch,
Openpanel, GoAccess), GDPR considerations, and a comparison table to
help users choose the right analytics provider.
- The configuration documentation now references analytics setup and
related configuration options.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L479-R550)

These updates collectively make the documentation more comprehensive,
actionable, and user-friendly for both new and advanced users.

**References:**
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L58-R110)
[[3]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L139-R185)
[[4]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[5]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L479-R550)
[[6]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)
[[7]](diffhunk://#diff-0967e840631a541bb95e057e1c6d4884274cf56d5a217d7fee2eb7223b6b4c0dR1-R268)
[[8]](diffhunk://#diff-52f2a9488bfe4177d1f1d01120859dad0b3e2d087283ded68f72d47b4f183391L291-R291)

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Auto update markdown TOC

* Added copilot instructions, AGENTS.md, improved README files (#3486)

This pull request introduces several documentation improvements and adds
comprehensive Copilot and agent instruction files to the al-folio
repository. The most significant changes are the addition of
repository-wide and path-specific Copilot instructions, updates to agent
documentation to reference these instructions, and improvements to the
documentation structure and clarity regarding file purposes and
workflows.

**Copilot and Agent Instruction Enhancements:**

- Added a new `.github/copilot-instructions.md` file providing detailed,
repository-wide setup, build, CI/CD, troubleshooting, and file format
guidance for Copilot coding agents.
- Introduced `.github/instructions/bibtex-bibliography.instructions.md`
with specific instructions for editing and validating BibTeX files,
including custom keywords, formatting rules, and integration with
Jekyll-Scholar.
- Updated agent documentation files (`customize.agent.md`,
`docs.agent.md`) to reference the new Copilot instruction files and
explain their purpose and usage for both repository-wide and
path-specific scenarios.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L57-R65)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L107-R122)
[[3]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L49-R51)
[[4]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L106-R137)

**Documentation Structure and Clarity Improvements:**

- Clarified and reorganized the documentation file list in agent files,
removing references to deprecated or merged files (e.g.,
`MAINTENANCE.md`, `ACCESSIBILITY.md`) and updating descriptions to
reflect current usage.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L57-R65)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L21-R21)
[[3]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L106-R137)
- Enhanced documentation on the purpose and application of each
documentation file, and added detailed explanations of Copilot
instruction files and their role in project development.

**Workflow and Validation Updates:**

- Updated references and descriptions for GitHub Actions workflows in
agent documentation to include the Copilot environment setup and clarify
pre-commit and CI/CD requirements.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L57-R65)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L49-R51)
- Corrected references for accessibility guidance, now directing users
to `TROUBLESHOOTING.md` instead of the removed `ACCESSIBILITY.md`.

These changes collectively improve the onboarding experience for both
human contributors and AI agents, ensuring consistent adherence to
project conventions and reducing errors.

**References:**  

[[1]](diffhunk://#diff-227c2c26cb2ee0ce0f46a320fc48fbcbdf21801a57f59161b1d0861e8aad55f5R1-R253)
[[2]](diffhunk://#diff-6fd2827fb8d9c2dd6dc973572201853487ecbbd1120b00425d4f1c21dfdcf35fR1-R174)
[[3]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L57-R65)
[[4]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L107-R122)
[[5]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L550-R562)
[[6]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L21-R21)
[[7]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L49-R51)
[[8]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L106-R137)

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Auto update markdown TOC

* docs: correct email configuration location in QUICKSTART.md (#3489)

Fixes #3488

Updates `QUICKSTART.md` to correctly point to `_data/socials.yml` for
email configuration, as the `email` field is not present in
`_config.yml`.

* fix(devcontainer): remove broken yarn apt source to fix build (#3490)

This change introduces a Dockerfile to the devcontainer configuration
that removes the broken Yarn repository from `/etc/apt/sources.list.d/`.
This prevents `apt-get update` from failing due to an expired or missing
GPG key for the Yarn repository.

Fixes #3487

* Improve AGENTS.md structure

Removed duplicate quick links for coding agents and customization.

* fix: CV rendering failure without Volunteer field (#3479)

Fixes #3478

* fix tikzjax (#3477)

Fixes #3216 – TikZJax not working.

1. Changing SHA simply doesn't work, `window.tikzjax` is undefined and
it doesn't render anything.
2. I switched to the JS distributed by
[benrbray/tikzjax](https://github.com/benrbray/tikzjax/tree/develop),
added under `assets.js` to prevent future issues.
3. Documents now require to start with `\begin{document}`, should be a
simple fix.

<img width="789" height="341" alt="Screenshot 2026-01-24 at 1 10 39 PM"
src="https://github.com/user-attachments/assets/8272471d-df94-4118-a726-00ed09dcf1e8"
/>
<img width="780" height="380" alt="Screenshot 2026-01-24 at 1 06 13 PM"
src="https://github.com/user-attachments/assets/11284661-de15-4d57-a1d9-4959f562f826"
/>

* Fix #2598, shift to last_modified_at instead of last_updated. (#3493)

Use `last_modified_at` rather than `last_updated`. So that the
jekyll-sitemap plugin automatically looks for the standard
`last_modified_at` front matter field to generate the `<lastmod>` tag in
your `sitemap.xml`.

It fixes [#2598](https://github.com/alshedivat/al-folio/issues/2598) 

Also, it preserves backward compatibility, as the updated metadata logic
prioritizes the `page.last_modified_at`, and defaults to
`page.last_updated`.

* Making Gemini and Claude configuration files point to AGENTS.md (#3494)

This pull request updates project documentation to clarify and
standardize the development workflow, Git practices, and troubleshooting
resources. The main changes include adding a dedicated Git workflow
guide and reorganizing the `AGENTS.md` file for better clarity and
usability.

**Documentation and Workflow Improvements:**

* Added a new `.github/GIT_WORKFLOW.md` file detailing commit message
conventions, types, and best practices for staging and ignoring files.
* Reorganized and clarified the pre-commit checklist and local
development instructions in `AGENTS.md`, emphasizing Docker usage and
proper code formatting.
* Updated the section on configuration and troubleshooting in
`AGENTS.md` to better direct users to relevant resources and removed
redundant or outdated instructions.
[[1]](diffhunk://#diff-a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9L57-R58)
[[2]](diffhunk://#diff-a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9L100-R74)

**Configuration and Context Updates:**

* Added a `.gemini/settings.json` file to define context files for
Gemini agent operations, ensuring relevant documentation is available
for automation tools.
* Created `CLAUDE.md` file pointing to `AGENTS.md`.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Enhance documentation for GitHub Copilot agents

Added CLAUDE.md file for AI assistant integration and updated Copilot agents description.

* Fix Gemini settings

* Added information about creating custom metadata for collections

* Update Google Scholar citations

* Add GDPR-compliant cookie consent with analytics blocking (#3492)

Implements cookie consent using vanilla-cookieconsent v3 to comply with
GDPR requirements. Analytics scripts are blocked until user consent is
obtained.

## Changes

**Library Integration**
- Added `vanilla-cookieconsent@3.1.0` to `_config.yml` third-party
libraries with SRI hashes
- Created `_scripts/cookie-consent-setup.js` with consent modal and
settings configuration
- Added CSS/JS includes in `_includes/head.liquid` and
`_includes/scripts.liquid`

**Analytics Blocking**
- Modified analytics scripts in `scripts.liquid` and
`distill_scripts.liquid` to use conditional `type="text/plain"
data-category="analytics"` when consent is disabled
- Blocks Google Analytics, Cronitor, Pirsch, and OpenPanel until consent
granted
- Library automatically converts blocked scripts to executable on user
acceptance

**Configuration**
- Added `enable_cookie_consent` flag (default: `false`)
- Cookie categories: `necessary` (always on), `analytics` (optional)
- 182-day cookie expiration, auto-clear on rejection

## Implementation

```liquid
{% if site.enable_cookie_consent %}
  <script type="text/plain" data-category="analytics" async src="...gtag.js"></script>
{% else %}
  <script async src="...gtag.js"></script>
{% endif %}
```

Enable in `_config.yml`:
```yaml
enable_cookie_consent: true
```

## Screenshots

**Consent Modal**

![Cookie consent
modal](https://github.com/user-attachments/assets/9edcddad-6a54-49ca-a164-083157d98370)

**Settings Modal**

![Cookie
preferences](https://github.com/user-attachments/assets/cf2a58ea-68c0-4699-b401-38377b98b718)

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `cdn.jsdelivr.net`
>   - Triggering command: `/usr/bin/curl curl -s REDACTED` (dns block)
> - `cookieconsent.orestbida.com`
> - Triggering command:
`/home/REDACTED/work/_temp/ghcca-node/node/bin/node
/home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps
/home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js`
(dns block)
> - `medium.com`
> - Triggering command: `/usr/local/bin/ruby ruby
/usr/local/bundle/bin/bundle exec jekyll serve --watch --port=8080
--host=0.0.0.0 --livereload --verbose --trace --force_polling s
6_64-linux /etc/locale.gen by/backward -binutils_2.44-3grep .deb eb
/systemd-sysctl` (dns block)
> - `publish.twitter.com`
> - Triggering command: `/usr/local/bin/ruby ruby
/usr/local/bundle/bin/bundle exec jekyll serve --watch --port=8080
--host=0.0.0.0 --livereload --verbose --trace --force_polling lude��
lude/ruby-4.0.0//run/containerd/io.containerd.runtime.v2.task/moby/a4760212ce4eda97e32b6dfa4d3ea/usr/sbin/iptables
r/runc-log.json f8_range lude r-strong E r/wc7in709a54d7hshow` (dns
block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/alshedivat/al-folio/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>GDPR compliant cookie consent dialog</issue_title>
> <issue_description>Hi,
> 
> since I am from Europe and want my site to be accessed by EU citizens
I need to ask users if they are ok with the use of cookies. Adding a
dialogue by default that that asks the user before any cookies /
localStorage are used would be nice.
> 
> I have integrated the dialog from
[https://www.cookieconsent.com/](https://www.cookieconsent.com/) on [my
website](http://hschwane.github.io) and am happy to file a PR if you are
interested. However It is not shown directly at the top, but below the
menu bar for some reason. Not sure how to fix that.
> </issue_description>
> 
> <agent_instructions>Implement this using cookie consent dialog from
https://github.com/orestbida/cookieconsent. The documentation is
available at
https://cookieconsent.orestbida.com/essential/getting-started.html.</agent_instructions>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> <comment_new><author>@alshedivat</author><body>
> @hschwane, thanks for pointing this out. It's would be great if you
could send a PR.
> 
> To answer your question about positioning, the menu bar has the
absolute position at the top of the page and keeps moving with
scrolling. You can change that behavior in `_config.yml` by setting
`navbar_fixed: false` (see [line
27](https://github.com/alshedivat/al-folio/blob/master/_config.yml#L27)).
If you send a PR with basic functionality, I can help with adjusting the
styles a bit. Thanks!</body></comment_new>
> <comment_new><author>@alshedivat</author><body>
> Just catching up on this discussion.
> 
> @hschwane, thanks for providing an implementation based on
`ihavecookies`! I looked through alshedivat/al-folio#223. It seems like
to be able to correctly (un)block different types of cookies (all of
which are third-party cookies) requires adding quite a bit of extra
JavaScript (including adding it directly to posts or pages in some
cases, e.g., when posts embed youtube videos or other external content).
This approach will put some extra burden on contributors and maintainers
of al-folio down the line.
> 
> By the way, the dialog from https://www.cookieconsent.com/ is similar
in that sense as it requires to manually add ALL scripts that use
cookies. So, if someone contributes a new feature to al-folio that uses
cookies, the contributor would have to go and update the cookie consent
dialog as well (or edit quite a bit of JS if `ihavecookies` is used).
> 
> Thinking about this more, I currently see only three options:
> 1. If we want to have cookie consent as a core part of al-folio (which
can be easily enabled or disabled), it needs to be a service that
automatically identifies and blocks cookies, without putting an extra
burden on the contributors or maintainers. The hosted version of [Cookie
Consent by Osano](https://www.osano.com/features/consent-management) is
an example.
> 2. Another option is to provide a very minimalistic cookie consent
dialog which simply says that the website uses cookies, without an
option to opt-in or opt-out (e.g., see the open-source edition of
[Osano](https://www.osano.com/cookieconsent/download/)).
> 3. Finally, not have cookie consent as part of al-folio, and make the
user responsible for figuring out whether they need a consent dialog and
which service to use.
> 
> Let me know what you think.</body></comment_new>
> <comment_new><author>@alshedivat</author><body>
> the best way to add GDPR compliant cookie consent is using
https://github.com/orestbida/cookieconsent</body></comment_new>
> </comments>
> 


</details>


> **Custom agent used: customization_agent**
> Expert customization assistant for the al-folio Jekyll academic
website template



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes alshedivat/al-folio#199

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for
you](https://github.com/alshedivat/al-folio/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: george-gca <31376482+george-gca@users.noreply.github.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Auto update markdown TOC

* Improve explanation of create from this template (#3499)

This pull request improves the documentation to clarify the recommended
way to create a new site using the al-folio template, emphasizing the
use of the "Use this template" button instead of forking. It explains
the differences between the two approaches, highlights common pitfalls
with forking, and provides guidance for users who have already forked
the repository.

Documentation improvements regarding repository creation:

* Added a prominent section in `README.md` explaining why "Use this
template" is preferred over forking, including step-by-step instructions
and advice for users who have already forked.
* Updated `QUICKSTART.md` to strongly recommend using the "Use this
template" button, clarified the steps for creating a new repository, and
included tips for users who have already forked by mistake.
* Added a new section in `INSTALL.md` detailing the differences between
using the template and forking, common pitfalls, and best practices for
contributing.

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Update Google Scholar citations

* Added new research blog in README.md (#3522)

* Update Google Scholar citations

* Add link to personal page (laura wagner) in README (#3552)

Adding my personal academic website to the academics list

* Add Fukushima Lab to User community (Labs) (#3559)

This PR adds Fukushima Lab to the **User community** section in
`README.md` under **Labs**. Thank you for maintaining such a great and
inspiring website template.

Added link:
- https://kenji-fukushima-lab.github.io/

Co-authored-by: Kenji Fukushima <kf@MacBookPro.elecom>

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* add vud.org to community list (#3575)

Add vud.org to community list.

* Added website of B. Choi (Update README.md) (#3569)

Hello, please add my academic website to the community page. Thank you
for maintaining this project.

* [Update] add workshop to README.md (#3585)

Add new workshop to README.md

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Add pranavraj575 website to README

* Add deden.id website to README

Please let my website be on the growing list! I'm Deden Habibi Ali
Alfathimy, a researcher in outer space politics, with personal website
https://deden.id using al-folio.

* Upgrade al-folio to v1.0 (#2968)

## Overview

This PR delivers the `v1.0` architecture and runtime upgrade for
`al-folio`.

`al-folio` moves from a monolithic theme repo to a **thin starter +
plugin ecosystem** model, while preserving visual identity and core
behavior.

## What this PR changes

### 1) Starter becomes orchestration-only

`al-folio` is now responsible for:

- starter wiring (`Gemfile`, `_config.yml`)
- sample/demo content
- user-facing docs
- visual regression and cross-plugin integration tests

Component/runtime ownership is moved to dedicated gems.

### 2) Runtime and feature ownership split into plugins

`al_folio_core` now provides shared runtime/layout primitives and
contracts, and delegates feature modules to owning gems.

Key plugin ownership in v1:

- `al_folio_core`: core theme runtime/contracts
- `al_folio_distill`: Distill layouts/runtime
- `al_folio_cv`: CV rendering
- `al_search`: search runtime and modal behavior
- `al_icons`: icon runtime (Font Awesome, Academicons, Scholar Icons)
- `al_cookie`: cookie-consent runtime
- `al_img_tools`: image/gallery/lightbox tooling
- `al_math`: math/TikZ runtime integration
- additional `al-*` plugins for
analytics/charts/citations/comments/newsletter/external posts/upgrade
tooling

### 3) Styling/runtime modernization

- Tailwind-first v1 runtime is established.
- Legacy Bootstrap behavior is isolated behind optional
`al_folio_bootstrap_compat` for migration windows.
- jQuery-dependent runtime paths are removed/replaced in plugin-owned
implementations.

### 4) Test ownership policy is enforced

- `al-folio` keeps only starter-level integration and visual integrity
checks.
- Component correctness tests are owned by the corresponding plugin
repos.

This mirrors runtime ownership and reduces duplication/drift.

### 5) Upgrade and migration workflow

`al_folio_upgrade` is integrated for audit/apply/report migration flows,
including:

- config contract checks
- ownership drift detection
- local override drift audit/diff/acknowledgement workflow
- legacy marker detection
- plugin wiring validation

### 6) Documentation and contributor model for v1

Docs are updated to reflect modular v1 behavior and contribution
routing.

New governance additions include:

- plugin ownership/boundary guidance (`docs/BOUNDARIES.md`)
- plugin naming convention (theme-coupled vs reusable plugin tracks)
- featured-vs-bundled plugin distinction
- plugin catalog source + page (`_data/featured_plugins.yml`,
`_pages/plugins.md`)
- plugin feature proposal issue template
- PR template updates for ownership routing
- agent-facing setup and migration skills

## Compatibility and migration notes

- Plugin integration in starter is via `Gemfile` + `_config.yml`.
- `al-folio` starter intentionally does not use a gemspec in v1.
- Transitional Bootstrap compatibility remains available via
`al_folio_bootstrap_compat`.
- Existing front-matter contracts are preserved where possible; runtime
implementations are now plugin-owned.
- Customized sites can track local override drift with `bundle exec
al-folio upgrade overrides audit` and `.al-folio-overrides.yml`.

## Validation strategy in this PR

- visual parity checks against the v0.16.3 baseline
- starter integration suites (comments, plugin toggles, distill, compat,
upgrade CLI)
- style contract checks and repository linting

## Scope intent

This is the foundational v1 architecture PR.

Post-merge feature work should generally target owning plugin repos
first, with `al-folio` limited to starter wiring, docs, examples, and
integration/visual validation.

_Written by Codex on behalf of @alshedivat._

* Fix broken navbar: stop double-minifying Tailwind CSS in production (#3634)

## Summary

Fixes the broken navigation bar on the live demo
(https://alshedivat.github.io/al-folio/) introduced by the v1.0 upgrade
(#2968), plus two related production/deploy-only issues found while
auditing for the same class of bug.

## Root cause of the navbar break

The v1.0 upgrade made the site **Tailwind-first**. The deploy builds
with `JEKYLL_ENV=production`, which activates **jekyll-minifier**. Its
CSS compressor (`cssminify2`) mangles Tailwind v4 spacing tokens
**inside `calc()`**:

```
calc(var(--spacing)*0)   ->   calc(var( -  - spacing)*0)   // invalid
```

`cssminify2` treats the `--` inside `calc(var(--…))` as minus operators
and inserts spaces, producing an invalid custom-property name. This
silently breaks **every** spacing/positioning utility — most visibly
`.fixed-top`, so the fixed navbar is no longer pinned (`top/left/right`
drop out) and renders incorrectly. On the live site this affects 33
`var(--spacing)` references in `tailwind.css`.

It only manifests in **production**: a local `bundle exec jekyll serve`
is development mode (minifier off), and the `visual-regression` workflow
also serves in dev mode — so neither caught it.

### Why this fix

`tailwind.css` is already minified by al_folio_core's Tailwind build,
and `main.css` is compiled by Sass with `style: compressed`.
Re-minifying them with `cssminify2` adds nothing (it actually makes
`tailwind.css` ~315 bytes **larger**) and only introduces this
corruption. So we disable redundant CSS minification, mirroring the
existing `compress_javascript: false` (terser handles JS).

Verified end-to-end:
- The gem source `tailwind.css` has 82 intact `var(--spacing)`;
`cssminify2` corrupts all 82.
- jekyll-minifier (`lib/jekyll-minifier.rb:1061`): `return
output_file(path, content) unless config.compress_css?` — with
`compress_css: false`, `.css` files are written verbatim.
- A real `JEKYLL_ENV=production` build now emits `tailwind.css` with 82
intact `var(--spacing)`, 0 corrupted, and
`.fixed-top{...;position:fixed}` intact.
- PurgeCSS (the next deploy stage) preserves `calc(var(--spacing)*0)`
unchanged.

## Changes

1. **`_config.yml` — `jekyll-minifier.compress_css: false`** (the navbar
fix).
2. **`test/integration_css_minify.sh` + `unit-tests.yml`** — a
regression test that builds in **production mode** (the mode that
exposes this bug class) and asserts no `var( - - )` corruption, intact
`var(--spacing)`, a valid `.fixed-top`, and a non-empty `main.css`.
Passes with the fix; fails without it (83 corruptions). Closes the CI
blind spot that let this ship.
3. **`_config.yml` — drop dead `jekyll-minifier` exclude**
`assets/js/search/*.js`. That is a v0 path; in v1 the search runtime
ships under `assets/al_search/js/...`, so the glob matched nothing.
4. **`purgecss.config.js` — safelist `medium-zoom-overlay` /
`medium-zoom-image--opened`.** These classes are injected at runtime, so
they never appear in the static HTML PurgeCSS scans; their `z-index:999`
overlay rule was being purged on the deployed site, letting the
scroll-progress bar / ToC bleed through a zoomed image. Verified: the
rule survives purge with the safelist and is dropped without it.

## Broader audit — plugin fixes (released + pinned here)

I audited for the same bug class (regressions invisible to dev-mode
builds / leftovers from the v1 jQuery removal). The confirmed
plugin-owned issues were each fixed in their own repo, merged after
green CI, released to RubyGems, and pinned in this PR's `Gemfile`:

- **al_folio_core 1.0.10**
([#18](https://github.com/al-org-dev/al-folio-core/pull/18)) —
`main.css` cache-bust was permanently the empty-string MD5
(`bust_css_cache` globbed a non-existent `assets/_sass`) → stale CSS
after deploys; `bib.liquid` "N more authors" used `$(this)` → threw and
never expanded; `figure.liquid` `onerror` used `$()` → dead broken-image
fallback.
- **al_charts 1.0.1**
([#7](https://github.com/al-org-dev/al-charts/pull/7)) —
`chartjs-setup.js` was jQuery → `chartjs` charts threw `$ is not
defined` and never rendered.
- **al_folio_distill 1.0.2**
([#2](https://github.com/al-org-dev/al-folio-distill/pull/2)) —
`overrides.js` top-level `$(window).on("load")` → distill
footnote/citation theming never applied + console error.

Verified end-to-end with a production build after the pin bumps:
`main.css` now cache-busts to a real hash (`9278fad1…`, not
`d41d8cd9…`), zero jQuery `$(` in the built HTML, and the Tailwind
spacing utilities / `.fixed-top` navbar are intact.

Also noted (not fixed here): the `visual-regression` workflow only
renders in dev mode, so it can't catch production-only CSS regressions —
`test/integration_css_minify.sh` is the immediate guard; a production
screenshot leg would be a fuller backstop.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: expand CLAUDE.md with the v1 plugin-ecosystem architecture (#3635)

## Summary

Expands `CLAUDE.md` from a bare `@AGENTS.md` import into a useful entry
point for coding agents, while **keeping** that import so `AGENTS.md`'s
ownership boundaries, validated command set, and PR-routing rules still
flow in (and stay the short, ecosystem-neutral shared file).

The added content is the cross-repo "big picture" that no single file in
this repo currently documents — gathered by reading the starter
internals plus all 16 `al-*` / `al_folio_*` plugin gems:

- **al_folio_core hub + delegation map** — a `wrapper → tag → gem` table
for every bundled plugin, so a runtime change can be routed to the
owning repo in one lookup.
- **Sibling-repos-on-disk** layout and how to point the `Gemfile` at a
local gem checkout (`path:`) to test a gem fix against the site.
- **Cross-repo invariants** — two-layer feature gating (config flag
*and* front matter), `AssetsGenerator` build-time asset injection, the
`Gemfile` ↔ `_config.yml` plugin-list sync, the v1 config contract
(enforced by core's `:after_init` and `al-folio upgrade audit`),
`.al-folio-overrides.yml` drift tracking, and the time-boxed
bootstrap-compat path.
- **Daily dev loop** that `AGENTS.md` omits (`jekyll serve`, single
integration test, snapshot refresh, upgrade subcommands).
- The v1 Docker `/tmp/_site` rationale and the `style_contract.js`
boundary that fails CI if runtime/build files leak into the starter.

Every specific claim (gem versions, tag names, config keys) is grounded
in the actual repos. Prettier-clean.

> Split out from the navbar-fix PR (#3634) per request; this PR is
docs-only and independent.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix links (#3628)

## Summary

In the "User community" README section several links didn't work
anymore. I updated them where I was able to find a new link from the
same person, and removed the ones where I didn't find a new link.

## Ownership Routing

- [x] I confirmed this PR targets the correct repo based on
`docs/BOUNDARIES.md`.
- [x] This PR only changes starter-owned scope (`al-folio`) **or** I am
porting a routed change and linked the owning repo issue/PR.

## Plugin Ecosystem (if applicable)

- [x] Not applicable
- [ ] This PR proposes a plugin for **featured-only** listing.
- [ ] This PR proposes a plugin for **bundled** starter inclusion.

## Starter Wiring Changes

- [x] Not applicable
- [ ] Updated `Gemfile` dependency wiring.
- [ ] Updated `_config.yml` plugin activation/config.
- [ ] Updated `_data/featured_plugins.yml` metadata.

## Validation

- [x] `npm ci`
- [ ] `bundle exec jekyll build`
- [x] `npm run lint:prettier`
- [x] `npm run lint:style-contract`
- [ ] Integration tests (`test/integration_*.sh`) as needed
- [ ] Visual tests (`npm run test:visual`) as needed

* Fix visual regressions: broken repo stat cards and unstyled af-popover/tooltip (#3636)

## What's broken on the demo site

A full-page screenshot audit of every page on
https://alshedivat.github.io/al-folio/ surfaced two user-visible bugs
introduced or exposed by the v1 upgrade.

### Bug 1 — Repositories page: all stat cards show broken alt-text
(HIGH)

Both external services are currently unavailable:
- `github-readme-stats.vercel.app` → HTTP 503 `DEPLOYMENT_PAUSED`
- `github-profile-trophy.vercel.app` → HTTP 402

Every `<img>` on the repositories page fails to load, rendering as a
list of broken-image alt-text strings. The templates had no `onerror`
fallback.

**Fix (in al_folio_core):**
`onerror="this.closest('.repo').style.display='none'"` on every
stat-card image in `repo.liquid`, `repo_user.liquid`, and
`repo_trophies.liquid`. When a service is unavailable the entire card
hides gracefully; when it comes back up cards render normally.

### Bug 2 — `.af-popover` / `.af-tooltip` completely unstyled (MEDIUM)

`tooltips-setup.js` (active by default, since bootstrap-compat is
disabled) creates `.af-popover` and `.af-tooltip` elements as its
vanilla fallback — for example when hovering the author-info circle icon
(ⓘ) on the publications page. These class names had **no CSS rules at
all** in `al_folio_core`: no `position`, no styling, no `z-index`. The
tooltip/popover appeared as invisible, unpositioned text nodes appended
to `document.body`.

(The theme's `_utilities.scss` only defined `.popover` — Bootstrap's
class — which is irrelevant without bootstrap-compat loaded.)

**Fix (in al_folio_core):** Added `position: absolute`, `z-index:
1070/1080`, and theme-color styling to both classes. The purgecss
safelist in al-folio already protects both names so they survive the
deploy pipeline.

## Changes

- `Gemfile` / `Gemfile.lock`: bump `al_folio_core` 1.0.10 → 1.0.11 ([PR
#19](https://github.com/al-org-dev/al-folio-core/pull/19), now merged
and released)

## Scope

All other pages screenshotted look correct. No other CSS/layout
regressions were found beyond these two. The screenshot audit also
confirmed:
- The `var(--spacing)` Tailwind fix from #3634 is working correctly in
production.
- `main.css` cache-bust hash (`9278fad1…`) is stable and non-empty.
- All blog posts, CV, teaching, people, projects, books pages render as
expected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Add a link to my lab website in user community section (#3645)

Add a link to my lab website in the user community of README.

## Summary

Many thanks to the authors and contributors of this repo. I'm glad to
add my lab's website in the user community section of README.

## Ownership Routing

- [x] I confirmed this PR targets the correct repo based on
`docs/BOUNDARIES.md`.
- [ ] This PR only changes starter-owned scope (`al-folio`) **or** I am
porting a routed change and linked the owning repo issue/PR.

Owning repo (if not starter): <!-- e.g., al-org-dev/al-folio-core -->
Related issue/PR: <!-- link -->

## Plugin Ecosystem (if applicable)

- [x] Not applicable
- [ ] This PR proposes a plugin for **featured-only** listing.
- [ ] This PR proposes a plugin for **bundled** starter inclusion.

If plugin-related, provide:

- Plugin repo URL:
- Gem name:
- Jekyll plugin id:
- Compatibility (`al_folio_min`/`al_folio_max`):
- Demo page/post path:
- Maintainer contact:

## Starter Wiring Changes

- [x] Not applicable
- [ ] Updated `Gemfile` dependency wiring.
- [ ] Updated `_config.yml` plugin activation/config.
- [ ] Updated `_data/featured_plugins.yml` metadata.

## Validation

- [ ] `npm ci`
- [ ] `bundle exec jekyll build`
- [ ] `npm run lint:prettier`
- [ ] `npm run lint:style-contract`
- [ ] Integration tests (`test/integration_*.sh`) as needed
- [ ] Visual tests (`npm run test:visual`) as needed

## Notes

Compatibility, migration implications, and follow-ups:

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Bump nokogiri from 1.19.3 to 1.19.4 (#3653)

Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.19.3
to 1.19.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/sparklemotion/nokogiri/releases">nokogiri's
releases</a>.</em></p>
<blockquote>
<h2>v1.19.4 / 2026-06-18</h2>
<h3>Security</h3>
<ul>
<li>[CRuby] (Low) Fixed a possible invalid memory read when
<code>XML::Node#initialize_copy_with_args</code> is called with an
argument that is not a <code>Node</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-g9g8-vgvw-g3vf">GHSA-g9g8-vgvw-g3vf</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when an
<code>XML::XPathContext</code> is used after its source document has
been garbage collected. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-p67v-3w7g-wjg7">GHSA-p67v-3w7g-wjg7</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free during XInclude
processing via <code>Node#do_xinclude</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wfpw-mmfh-qq69">GHSA-wfpw-mmfh-qq69</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#root=</code> is assigned a non-element node. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wjv4-x9w8-wm3h">GHSA-wjv4-x9w8-wm3h</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when setting an
attribute value via <code>XML::Attr#value=</code> or
<code>#content=</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-phwj-rprq-35pp">GHSA-phwj-rprq-35pp</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a null pointer dereference when methods are
called on uninitialized wrapper objects (e.g. via
<code>allocate</code>); these now raise instead of crashing the process.
See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-9cv2-cfxc-v4v2">GHSA-9cv2-cfxc-v4v2</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#encoding=</code> raises an exception. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5v8h-3h3q-446p">GHSA-5v8h-3h3q-446p</a>
for more information.</li>
<li>[CRuby] (Medium) Fixed an out-of-bounds read in
<code>XML::NodeSet#[]</code> (alias <code>#slice</code>) when given a
large negative index. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5prr-v3j2-97mh">GHSA-5prr-v3j2-97mh</a>
for more information.</li>
<li>[JRuby] (Low) <code>XML::Schema</code> now enforces the
<code>NONET</code> parse option, which Nokogiri enables by default. It
was not enforced on JRuby, so a schema parsed with default options could
still fetch external resources over the network, potentially enabling
SSRF or XXE attacks and bypassing the mitigation for CVE-2020-26247. See
<a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-8678-w3jw-xfc2">GHSA-8678-w3jw-xfc2</a>
for more information.</li>
</ul>
<!-- raw HTML omitted -->

<pre><code>1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f
nokogiri-1.19.4-aarch64-linux-gnu.gem
35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af
nokogiri-1.19.4-aarch64-linux-musl.gem
a301313e38bb065d68239e79734bcd6f56fb6efaacebde29e9abf2a4735340ca
nokogiri-1.19.4-arm-linux-gnu.gem
588923c101bcfa78869734d247d25b598674323e7f22474fc468f6e5647311eb
nokogiri-1.19.4-arm-linux-musl.gem
a46db9853286e6597b36ebc6953817d15acf3a299583eb3f89fdc6f91dd63527
nokogiri-1.19.4-arm64-darwin.gem
ce04b9e268c9626852231a48b49128ed52034f1ccb39484a6da3875491cd709e
nokogiri-1.19.4-java.gem
051da97b8eccfdb5444fed40246a35e10d7298b9efe759b4cd25455ea04c587e
nokogiri-1.19.4-x64-mingw-ucrt.gem
7fd17057d3e1f00e9954a74b3cd76595d3d4a5ef233b7ed9599047c204f70551
nokogiri-1.19.4-x86_64-darwin.gem
379fae440b28915e3f19d752ce2dcf8465ed2b2fbefd2a7ca0dd497bc981a06a
nokogiri-1.19.4-x86_64-linux-gnu.gem
17dfb7c1fa194ae02fbf7c51a7afc8d278045ab3fdacfd86f91d02d7b274470b
nokogiri-1.19.4-x86_64-linux-musl.gem
50c951611c92bca05c51411aef45f1cbc50f2821c4802758c5c6d34696533ab5
nokogiri-1.19.4.gem
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md">nokogiri's
changelog</a>.</em></p>
<blockquote>
<h2>v1.19.4 / 2026-06-18</h2>
<h3>Security</h3>
<ul>
<li>[CRuby] (Low) Fixed a possible invalid memory read when
<code>XML::Node#initialize_copy_with_args</code> is called with an
argument that is not a <code>Node</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-g9g8-vgvw-g3vf">GHSA-g9g8-vgvw-g3vf</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when an
<code>XML::XPathContext</code> is used after its source document has
been garbage collected. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-p67v-3w7g-wjg7">GHSA-p67v-3w7g-wjg7</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free during XInclude
processing via <code>Node#do_xinclude</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wfpw-mmfh-qq69">GHSA-wfpw-mmfh-qq69</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#root=</code> is assigned a non-element node. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wjv4-x9w8-wm3h">GHSA-wjv4-x9w8-wm3h</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when setting an
attribute value via <code>XML::Attr#value=</code> or
<code>#content=</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-phwj-rprq-35pp">GHSA-phwj-rprq-35pp</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a null pointer dereference when methods are
called on uninitialized wrapper objects (e.g. via
<code>allocate</code>); these now raise instead of crashing the process.
See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-9cv2-cfxc-v4v2">GHSA-9cv2-cfxc-v4v2</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#encoding=</code> raises an exception. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5v8h-3h3q-446p">GHSA-5v8h-3h3q-446p</a>
for more information.</li>
<li>[CRuby] (Medium) Fixed an out-of-bounds read in
<code>XML::NodeSet#[]</code> (alias <code>#slice</code>) when given a
large negative index. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5prr-v3j2-97mh">GHSA-5prr-v3j2-97mh</a>
for more information.</li>
<li>[JRuby] (Low) <code>XML::Schema</code> now enforces the
<code>NONET</code> parse option, which Nokogiri enables by default. It
was not enforced on JRuby, so a schema parsed with default options could
still fetch external resources over the network, potentially enabling
SSRF or XXE attacks and bypassing the mitigation for CVE-2020-26247. See
<a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-8678-w3jw-xfc2">GHSA-8678-w3jw-xfc2</a>
for more information.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/8cfb9daae9ee4a0837508eab43c40fbc8c4138c9"><code>8cfb9da</code></a>
version bump to v1.19.4</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/a856d1e46bda04ef47a0bd2b9eefe86df1eb0bb2"><code>a856d1e</code></a>
fix: JRuby NONET bypass in XML::Schema (v1.19.x) (<a
href="https://redirect.github.com/sparklemotion/nokogiri/issues/3639">#3639</a>)</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/6a0aa1e7042ea58e10db713d498…
kastnerp added a commit that referenced this pull request Sep 9, 2026
* Update dogan.md

* Team Updates

* Team Updates

* Update thach.md

* Update gomez.md

* GitHub profile autoinclude

Update page.liquid

.

* GitHub autoinclude

* Update yang.md

* fixed run files

* Update gt-arch-7014.md

* Update gt-arch-7014.md

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* feat: add Code tab and GitHub repo cards

* feat: add Code tab and GitHub repo cards

* Update li.md

* Update join.md

* Update Google Scholar citations

* Add news posts for Sina defense and CHHS talk

* Update Google Scholar citations

* Update Google Scholar citations

* Update remote_include URL in thach.md (#37)

* Fix repository page layout

* Improve repository card title overflow

* Restore repository card design

* Update almaian.md

* Update _base.scss

* Update almaian.md

* .

* Update repo.liquid

* Update karadag.md

* Add Shen visit news post

* Normalize image asset paths

* Prevent team avatar footer overlap

* Add Cypress thesis defense news post

* Add Jimmy team profile (#39)

* Jimmy Miao Zhang

* Jimmy Miao Zhang Profile Photo

* Revise Jimmy's profile details and image

Updated profile information for Jimmy Miao.

* Update and rename jimmy.md to miao.md

* Update miao.md

* Update Google Scholar citations

* Update Google Scholar citations

* Create announcement_43.md

* Add MT projects for Benjamin Shih and Joseph Aerathu

* Fix video rendering on Joseph Aerathu project page

* Add project links to team pages

* Add CP-GNI2024-Symposium-Enriching-geospatial-building-datasets project (#41)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update title to 'Jimmy Miao Zhang' (#40)

* Update Google Scholar citations

* Update papers.bib with missing code links (#43)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update Google Scholar citations

* Update about.liquid

* Add Karadag 2026 publication (#44)

* Add Karadag 2026 urban wind simulation publication

- Added the BibTeX entry for `KARADAG2026107614` to `_bibliography/papers.bib`.
- Associated the publication with the `cfdgan-compressed.gif` preview image.
- Added the `bibtex_show` field to the new entry.
- Added `2026` to `years_papers` in `_pages/research/children/publications.md` so the newly added publication is rendered on the website.

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Add specific karadag image to publication

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Change publication preview image to abstract screenshot

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update karadag_abstract.png

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Fix formatting of year fields in _bibliography/papers.bib (#46)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update Google Scholar citations

* Dynamically pull Sina Rahimi's PhD README in project page (#47)

Replaced the hardcoded source link in `_projects/PhD-SinaRahimi.md` with a Liquid remote_include block that fetches and displays the actual GitHub README.md content.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update Google Scholar citations

* Update Google Scholar citations

* fix: switch repo cards to working github-readme-stats deployment (#49)

Public instance github-readme-stats.vercel.app returns 503
DEPLOYMENT_PAUSED, breaking all repo card images on /code/.
Point at the author's working deployment alias instead.

Co-authored-by: Patrick Kastner <1919773+kastnerp@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Add new display categories in theses.md (#48)

* Add new display categories in theses.md

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Add new display categories in theses.md

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Integrate new projects and update bibtex

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Integrate new projects and update bibtex

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update bibtex fields and add macadThesis24

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Remove macadThesis24

Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: kastnerp <1919773+kastnerp@users.noreply.github.com>

* Update Google Scholar citations

* Add Best Poster Award details to Maryam SimBuild 2026 post

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Add SimBuild 2026 award photo and certificate to Maryam post

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Update Google Scholar citations

* Update socials.yml

* Update Google Scholar citations

* Update to al-folio v1.1 (v0 → v1 gem architecture migration) (#50)

* Added support for helping agents (#3379)

Since a lot of our users don't have a coding background and given
recently development with AI agents, I decided to try to add support for
specialized agents in our repository. They were created following
[agents.md](https://agents.md/) "specifications" and are currently 2:
- `customize-agent` - to help new users with access to GitHub Copilot
customize their site
- `docs-agent` - to help us keep the documentation always updated with
the latest changes in our code

I don't really know how useful they'll actually be, but I think most of
our users might actually benefit from the `customize-agent`, so it is
worth a shot.

<img width="852" height="1043" alt="image"
src="https://github.com/user-attachments/assets/e8390f1a-cec3-42a8-b01e-26d658ea78e8"
/>

Edit: also added a link to a [Code Wiki to our
repository](https://codewiki.google/github.com/alshedivat/al-folio) and
[DeepWiki](https://deepwiki.com/alshedivat/al-folio). This allows any
user to chat online with AIs (Gemini and Devin) about our repository.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Auto update markdown TOC

* Fix bib / code layout bug (#3387)

Resolve #3370
Resolve #3380

Based on the
[comment](https://github.com/alshedivat/al-folio/issues/3370#issuecomment-3565962058)
of @MarkusThill, I created a bugfix that solved the issue on my website.
Hope that fixes it in general; thus the PR :) However, I'm not an expert
for scss .. so handle with care :)

* Fix: bibliography month persists to subsequent entries without month (#3391)

Fixes #3386 (the part about the wrong months; the other part (layouting
of bibtex) is fixed in #3387)

## Summary
- Fixes incorrect month shown for bibliography entries that do not
specify a `month` in BibTeX.
- Ensures `month`/`year` do not persist between entries in
`_layouts/bib.liquid`.

## Root Cause
- In Liquid, captured variables persist across iterations if not
reinitialized.
- `entrymonth` and `entryyear` were only set when
`entry.month`/`entry.year` existed, causing values from a previous entry
to leak into the next one when those fields were missing.

## Changes
- Reinitialize date-related variables per entry before conditional
captures:

## Behavior
- Before: Entries without a `month` could display the previous entry's
month.
- After: Entries without a `month` display only the `year`; entries with
a `month` display the correct month and year.


<img width="1956" height="918" alt="image"
src="https://github.com/user-attachments/assets/7a9682e7-55ab-43b7-8f82-f638d14ce08e"
/>

* Fixed 1 px first load issue (#3416)

Fix #3164

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Added support for default categories and tags for external posts (#3417)

Based on discussion #3393.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Add link to personal GitHub page on academics section in README (#3400)

* Add auto-orient flag to Imagemagick config (#3409)

Currently, images generated by Imagemagick do not respect the
orientation of the source image. By adding the auto-orient flag, the
images are the correct orientation.

Before
<img width="920" height="562" alt="image"
src="https://github.com/user-attachments/assets/73f59d7f-b6c5-468a-9023-0f0457a53a3c"
/>

After
<img width="947" height="621" alt="image"
src="https://github.com/user-attachments/assets/2f24de99-2e84-4052-8d0f-945acdad81e4"
/>

* Update deps (#3418)

Closes #3402

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Added new line to README badges

* Changed maintainers urls to https

* Updated prettier (#3420)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Fix typo in Bootstrap small column class usage (#3421)

This PR fixes a recurring typo in multiple Liquid templates where the
Bootstrap class `cl-sm` is used instead of `col-sm`.

Because of this typo, the `col-sm` styling was not being applied. All
instances have been corrected.

* Update Google Scholar citations

* Make external service URLs configurable for repository page (#3422)

## Description

This PR makes the URLs for external services used on the repository page
configurable in `_config.yml`. This allows users to self-host these
services for better reliability, privacy, and customization.

## Changes

- Added `external_services` configuration section in `_config.yml` with:
- `github_readme_stats_url` (default:
`https://github-readme-stats.vercel.app`)
- `github_profile_trophy_url` (default:
`https://github-profile-trophy.vercel.app`)
- Updated repository template files to use configurable URLs:
  - `_includes/repository/repo_user.liquid`
  - `_includes/repository/repo.liquid`
  - `_includes/repository/repo_trophies.liquid`
- Added documentation in `CUSTOMIZE.md` explaining:
- Why self-hosting is recommended (default services may have
availability issues)
  - How to configure custom service URLs
  - Links to the service repositories for deployment instructions

## Resolves

Resolves #3388 - This makes it possible to configure self-hosted
versions of these services, giving users full control over the external
services used for displaying GitHub statistics and trophies.

## Testing

- Verified that default configuration still works with original service
URLs
- Confirmed that URLs are properly interpolated in all template files
- Documentation clearly explains the configuration options

* Auto update markdown TOC

* Remove link to sam-bieberich.github.io (#3425)

Removed a link to sam-bieberich.github.io from the README.

* Add link to personal GitHub page on academics section in README (#3424)

* Add j1yoo.github.io to User community (#3427)

Hi! I'd like to add my academic website to the User community section.

**Website:** https://j1yoo.github.io/

This PR adds a single star link to the Academics row in the User
community table.

Thank you for creating and maintaining this beautiful theme!

Co-authored-by: Jaewon Yoo <jwyoo4@gmail.com>

* add filtered BibTeX keywords (#3403)

add `dimensions, eprint` and `pmid` to the filtered keywords

* Add HAL button (#3404)

Adds a HAL button in the same spirit as the arXiv button.
- add HAL button to `_layouts/bib.liquid`
- add `hal` to the filtered keywords in `_config.yml`
- add `hal` to the documentation  in `CUSTOMIZE.md`

* Improved collections section in CUSTOMIZE guide (#3431)

Improved section based on comments from #2369.

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Add zhoji.github.io to User community in README.md (#3433)

Adding my personal website for the al-folio community :) Thanks for
creating such a cool template!

* Changed code to use plugin to handle 3rd party libraries downloads (#3435)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Changed to use cache bust plugin (#3436)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Update deps (#3437)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Changed to use jekyll-socials plugin (#3439)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Updated deps and deploy version (#3440)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Fixed dates in book-shelf (#3446)

Fixes #3443.

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Updated deps to fix issue with jekyll-socials (#3447)

Fixes #3445

Signed-off-by: George Araújo <george.gcac@gmail.com>

* ⚡ Optimize Google Scholar Citations Regex Definition (#3449)

💡 **What:** Moved the regex definition `/Cited by (\d+[,\d]*)/` from the
method scope to a class-level constant `CITED_BY_REGEX`.

🎯 **Why:** To improve code cleanliness and avoid potential re-definition
of the regex object in every method call (or loop), adhering to best
practices.

📊 **Measured Improvement:**
* **Baseline:** The regex was defined as a literal inside the `render`
method, which is called for each tag usage.
*   **Optimization:** The regex is now defined once as a constant.
* **Note:** Performance benchmarks were not possible in the current
environment due to missing Ruby runtime. However, this is a standard
Ruby optimization that improves maintainability and theoretically avoids
object allocation overhead in older Ruby versions or complex scenarios.
Modern Ruby optimizes literals well, but the constant approach is
cleaner and DRYer.

---
*PR created automatically by Jules for task
[10688912524063334698](https://jules.google.com/task/10688912524063334698)
started by @alshedivat*

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

* Refactor: Use Liquid filter to find home page title (#3448)

Refactored the script in _scripts/search.liquid.js to use a more
efficient Liquid 'where' filter to find the home page title. This
replaces an inefficient for loop that iterated through all site pages.

---
*PR created automatically by Jules for task
[5748098109809984605](https://jules.google.com/task/5748098109809984605)
started by @alshedivat*

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

* Revert "Refactor: Use Liquid filter to find home page title" (#3451)

Reverts alshedivat/al-folio#3448

* Updated jekyll-archives-v2 (#3460)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Add course schedule feature to teaching page (#2258) (#3147)

Implements the course schedule feature requested in issue
#[2258](https://github.com/alshedivat/al-folio/issues/2258).

This PR adds a new course schedule feature to the al-folio theme,
allowing academics to easily create and display structured course
information.

**Changes:**
- Added a `courses` collection to organize and display academic courses
- Created course layout and display templates with responsive design
- Implemented organization by year and term with automatic sorting
- Added support for weekly schedule with topics and course materials
- Simplified documentation with a README for course creation

This feature makes it easier for academics to showcase their teaching
materials with a consistent, organized display of course schedules,
helping users create professional teaching pages without custom
implementation.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Add calendar iframe and togglAdd calendar iframe and toggle buttone button (#3144)

### Description

This PR adds a Google Calendar integration feature as described in issue
#872. Users can embed their own calendar using an iframe configured via
`_config.yml`, and the calendar is toggleable through a responsive
button. This component is styled to visually blend into the theme and
supports responsive display across desktop and mobile.

### Changes
- Added `calendar.liquid` in `_includes`
- Modified `about.md` to include the toggleable calendar block
- Introduced `calendar` config section in `_config.yml`
- Appended calendar-related styles in `_sass/_base.scss`

### Configuration
To enable this feature, add the following to `_config.yml`:
```yaml
calendar:
  enabled: true
  calendar_id: your_calendar_id@group.calendar.google.com
  timezone: UTC
  style: "border:0; width:100%; height:600px;"

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: dodo <349507644@qq.com>
Co-authored-by: George <31376482+george-gca@users.noreply.github.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>

* Update Google Scholar citations

* Updated jekyll-socials to latest version (#3464)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Add smsnoBin77 link to README (#3473)

Add a new link to the README for smsnoBin77.

* Unify jsonresume and RenderCV CVs solutions (#3462)

Fixes #2787 as an alternative to #2969. It was getting too cumbersome to
have 2 different data sources for CV and also a lot of different layout
files, so I decided to unify them all.
Main changes:
- synchronized the information inside RenderCV (`_data/cv.yml`) and
JSONResume (`assets/json/resume.json`)
- unified layout files for CV information
- added the option to set the "data source" in the CV page

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: render the latest CV

* Rendercv missing commits (#3475)

Signed-off-by: George Araújo <george.gcac@gmail.com>

* chore: render the latest CV

* Update Google Scholar citations

* Update SASS syntax in base (non-font) files (#3281)

Partially fixes issue #3256 by updating SASS syntax in main SCSS files.

To fully address the issue, FontAwesome should be updated to `v7.x` and
Tabler to `v3.30` or higher (see Tabler fix
[here](https://github.com/tabler/tabler-icons/pull/1256)), where the
SCSS has been fixed.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Improve readme, add site-wide CSP (#3485)

This pull request significantly expands and clarifies the documentation
for the al-folio Jekyll theme, focusing on improved file structure
explanations, enhanced quick reference guides, and the addition of a
comprehensive analytics setup guide. The changes make it easier for
users and contributors to understand the project organization, available
features, and configuration options, especially regarding CV formats,
teaching pages, and analytics integration.

**Key documentation and structure improvements:**

*Expanded file and collection structure:*
- The file structure documentation in
`.github/agents/customize.agent.md` and `.github/agents/docs.agent.md`
now details all major directories, including new and existing
collections such as `_books/`, `_teachings/`, `_scripts/`, `_plugins/`,
and expanded `assets/` subdirectories. It also covers new configuration
and utility files, making it easier for users to locate and understand
the purpose of each file or folder.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)

*Documentation and quick reference enhancements:*
- The quick reference table in `.github/agents/customize.agent.md` has
been updated to include new actions like adding teaching pages, setting
up analytics, improving SEO, and ensuring accessibility, with more
precise documentation links.
- The documentation map now lists all major guides (e.g.,
`QUICKSTART.md`, `INSTALL.md`, `TROUBLESHOOTING.md`, `ACCESSIBILITY.md`,
`ANALYTICS.md`, `SEO.md`), providing a clearer overview of available
resources.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L58-R110)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)

**Feature and configuration documentation updates:**

*CV/resume format guidance:*
- The CV documentation now clarifies that users can maintain both
RenderCV and JSONResume formats simultaneously, with clear instructions
on switching between them and deleting unused files if desired.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L139-R185)
[[2]](diffhunk://#diff-52f2a9488bfe4177d1f1d01120859dad0b3e2d087283ded68f72d47b4f183391L291-R291)

*Teaching pages and new collections:*
- Adds documentation for the new `_teachings/` collection, including
required frontmatter and support for course materials, as well as
updates to enable/disable teaching and books pages via `_config.yml`.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)

*Analytics integration:*
- Introduces a new `ANALYTICS.md` guide with detailed setup instructions
for Google Analytics, privacy-friendly alternatives (Plausible, Pirsch,
Openpanel, GoAccess), GDPR considerations, and a comparison table to
help users choose the right analytics provider.
- The configuration documentation now references analytics setup and
related configuration options.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L479-R550)

These updates collectively make the documentation more comprehensive,
actionable, and user-friendly for both new and advanced users.

**References:**
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L58-R110)
[[3]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L139-R185)
[[4]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[5]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L479-R550)
[[6]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)
[[7]](diffhunk://#diff-0967e840631a541bb95e057e1c6d4884274cf56d5a217d7fee2eb7223b6b4c0dR1-R268)
[[8]](diffhunk://#diff-52f2a9488bfe4177d1f1d01120859dad0b3e2d087283ded68f72d47b4f183391L291-R291)

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Auto update markdown TOC

* Added copilot instructions, AGENTS.md, improved README files (#3486)

This pull request introduces several documentation improvements and adds
comprehensive Copilot and agent instruction files to the al-folio
repository. The most significant changes are the addition of
repository-wide and path-specific Copilot instructions, updates to agent
documentation to reference these instructions, and improvements to the
documentation structure and clarity regarding file purposes and
workflows.

**Copilot and Agent Instruction Enhancements:**

- Added a new `.github/copilot-instructions.md` file providing detailed,
repository-wide setup, build, CI/CD, troubleshooting, and file format
guidance for Copilot coding agents.
- Introduced `.github/instructions/bibtex-bibliography.instructions.md`
with specific instructions for editing and validating BibTeX files,
including custom keywords, formatting rules, and integration with
Jekyll-Scholar.
- Updated agent documentation files (`customize.agent.md`,
`docs.agent.md`) to reference the new Copilot instruction files and
explain their purpose and usage for both repository-wide and
path-specific scenarios.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L57-R65)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L107-R122)
[[3]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L49-R51)
[[4]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L106-R137)

**Documentation Structure and Clarity Improvements:**

- Clarified and reorganized the documentation file list in agent files,
removing references to deprecated or merged files (e.g.,
`MAINTENANCE.md`, `ACCESSIBILITY.md`) and updating descriptions to
reflect current usage.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L57-R65)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L21-R21)
[[3]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L106-R137)
- Enhanced documentation on the purpose and application of each
documentation file, and added detailed explanations of Copilot
instruction files and their role in project development.

**Workflow and Validation Updates:**

- Updated references and descriptions for GitHub Actions workflows in
agent documentation to include the Copilot environment setup and clarify
pre-commit and CI/CD requirements.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L57-R65)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L49-R51)
- Corrected references for accessibility guidance, now directing users
to `TROUBLESHOOTING.md` instead of the removed `ACCESSIBILITY.md`.

These changes collectively improve the onboarding experience for both
human contributors and AI agents, ensuring consistent adherence to
project conventions and reducing errors.

**References:**  

[[1]](diffhunk://#diff-227c2c26cb2ee0ce0f46a320fc48fbcbdf21801a57f59161b1d0861e8aad55f5R1-R253)
[[2]](diffhunk://#diff-6fd2827fb8d9c2dd6dc973572201853487ecbbd1120b00425d4f1c21dfdcf35fR1-R174)
[[3]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L57-R65)
[[4]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L107-R122)
[[5]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L550-R562)
[[6]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L21-R21)
[[7]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L49-R51)
[[8]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L106-R137)

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Auto update markdown TOC

* docs: correct email configuration location in QUICKSTART.md (#3489)

Fixes #3488

Updates `QUICKSTART.md` to correctly point to `_data/socials.yml` for
email configuration, as the `email` field is not present in
`_config.yml`.

* fix(devcontainer): remove broken yarn apt source to fix build (#3490)

This change introduces a Dockerfile to the devcontainer configuration
that removes the broken Yarn repository from `/etc/apt/sources.list.d/`.
This prevents `apt-get update` from failing due to an expired or missing
GPG key for the Yarn repository.

Fixes #3487

* Improve AGENTS.md structure

Removed duplicate quick links for coding agents and customization.

* fix: CV rendering failure without Volunteer field (#3479)

Fixes #3478

* fix tikzjax (#3477)

Fixes #3216 – TikZJax not working.

1. Changing SHA simply doesn't work, `window.tikzjax` is undefined and
it doesn't render anything.
2. I switched to the JS distributed by
[benrbray/tikzjax](https://github.com/benrbray/tikzjax/tree/develop),
added under `assets.js` to prevent future issues.
3. Documents now require to start with `\begin{document}`, should be a
simple fix.

<img width="789" height="341" alt="Screenshot 2026-01-24 at 1 10 39 PM"
src="https://github.com/user-attachments/assets/8272471d-df94-4118-a726-00ed09dcf1e8"
/>
<img width="780" height="380" alt="Screenshot 2026-01-24 at 1 06 13 PM"
src="https://github.com/user-attachments/assets/11284661-de15-4d57-a1d9-4959f562f826"
/>

* Fix #2598, shift to last_modified_at instead of last_updated. (#3493)

Use `last_modified_at` rather than `last_updated`. So that the
jekyll-sitemap plugin automatically looks for the standard
`last_modified_at` front matter field to generate the `<lastmod>` tag in
your `sitemap.xml`.

It fixes [#2598](https://github.com/alshedivat/al-folio/issues/2598) 

Also, it preserves backward compatibility, as the updated metadata logic
prioritizes the `page.last_modified_at`, and defaults to
`page.last_updated`.

* Making Gemini and Claude configuration files point to AGENTS.md (#3494)

This pull request updates project documentation to clarify and
standardize the development workflow, Git practices, and troubleshooting
resources. The main changes include adding a dedicated Git workflow
guide and reorganizing the `AGENTS.md` file for better clarity and
usability.

**Documentation and Workflow Improvements:**

* Added a new `.github/GIT_WORKFLOW.md` file detailing commit message
conventions, types, and best practices for staging and ignoring files.
* Reorganized and clarified the pre-commit checklist and local
development instructions in `AGENTS.md`, emphasizing Docker usage and
proper code formatting.
* Updated the section on configuration and troubleshooting in
`AGENTS.md` to better direct users to relevant resources and removed
redundant or outdated instructions.
[[1]](diffhunk://#diff-a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9L57-R58)
[[2]](diffhunk://#diff-a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9L100-R74)

**Configuration and Context Updates:**

* Added a `.gemini/settings.json` file to define context files for
Gemini agent operations, ensuring relevant documentation is available
for automation tools.
* Created `CLAUDE.md` file pointing to `AGENTS.md`.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Enhance documentation for GitHub Copilot agents

Added CLAUDE.md file for AI assistant integration and updated Copilot agents description.

* Fix Gemini settings

* Added information about creating custom metadata for collections

* Update Google Scholar citations

* Add GDPR-compliant cookie consent with analytics blocking (#3492)

Implements cookie consent using vanilla-cookieconsent v3 to comply with
GDPR requirements. Analytics scripts are blocked until user consent is
obtained.

## Changes

**Library Integration**
- Added `vanilla-cookieconsent@3.1.0` to `_config.yml` third-party
libraries with SRI hashes
- Created `_scripts/cookie-consent-setup.js` with consent modal and
settings configuration
- Added CSS/JS includes in `_includes/head.liquid` and
`_includes/scripts.liquid`

**Analytics Blocking**
- Modified analytics scripts in `scripts.liquid` and
`distill_scripts.liquid` to use conditional `type="text/plain"
data-category="analytics"` when consent is disabled
- Blocks Google Analytics, Cronitor, Pirsch, and OpenPanel until consent
granted
- Library automatically converts blocked scripts to executable on user
acceptance

**Configuration**
- Added `enable_cookie_consent` flag (default: `false`)
- Cookie categories: `necessary` (always on), `analytics` (optional)
- 182-day cookie expiration, auto-clear on rejection

## Implementation

```liquid
{% if site.enable_cookie_consent %}
  <script type="text/plain" data-category="analytics" async src="...gtag.js"></script>
{% else %}
  <script async src="...gtag.js"></script>
{% endif %}
```

Enable in `_config.yml`:
```yaml
enable_cookie_consent: true
```

## Screenshots

**Consent Modal**

![Cookie consent
modal](https://github.com/user-attachments/assets/9edcddad-6a54-49ca-a164-083157d98370)

**Settings Modal**

![Cookie
preferences](https://github.com/user-attachments/assets/cf2a58ea-68c0-4699-b401-38377b98b718)

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `cdn.jsdelivr.net`
>   - Triggering command: `/usr/bin/curl curl -s REDACTED` (dns block)
> - `cookieconsent.orestbida.com`
> - Triggering command:
`/home/REDACTED/work/_temp/ghcca-node/node/bin/node
/home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps
/home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js`
(dns block)
> - `medium.com`
> - Triggering command: `/usr/local/bin/ruby ruby
/usr/local/bundle/bin/bundle exec jekyll serve --watch --port=8080
--host=0.0.0.0 --livereload --verbose --trace --force_polling s
6_64-linux /etc/locale.gen by/backward -binutils_2.44-3grep .deb eb
/systemd-sysctl` (dns block)
> - `publish.twitter.com`
> - Triggering command: `/usr/local/bin/ruby ruby
/usr/local/bundle/bin/bundle exec jekyll serve --watch --port=8080
--host=0.0.0.0 --livereload --verbose --trace --force_polling lude��
lude/ruby-4.0.0//run/containerd/io.containerd.runtime.v2.task/moby/a4760212ce4eda97e32b6dfa4d3ea/usr/sbin/iptables
r/runc-log.json f8_range lude r-strong E r/wc7in709a54d7hshow` (dns
block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/alshedivat/al-folio/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>GDPR compliant cookie consent dialog</issue_title>
> <issue_description>Hi,
> 
> since I am from Europe and want my site to be accessed by EU citizens
I need to ask users if they are ok with the use of cookies. Adding a
dialogue by default that that asks the user before any cookies /
localStorage are used would be nice.
> 
> I have integrated the dialog from
[https://www.cookieconsent.com/](https://www.cookieconsent.com/) on [my
website](http://hschwane.github.io) and am happy to file a PR if you are
interested. However It is not shown directly at the top, but below the
menu bar for some reason. Not sure how to fix that.
> </issue_description>
> 
> <agent_instructions>Implement this using cookie consent dialog from
https://github.com/orestbida/cookieconsent. The documentation is
available at
https://cookieconsent.orestbida.com/essential/getting-started.html.</agent_instructions>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> <comment_new><author>@alshedivat</author><body>
> @hschwane, thanks for pointing this out. It's would be great if you
could send a PR.
> 
> To answer your question about positioning, the menu bar has the
absolute position at the top of the page and keeps moving with
scrolling. You can change that behavior in `_config.yml` by setting
`navbar_fixed: false` (see [line
27](https://github.com/alshedivat/al-folio/blob/master/_config.yml#L27)).
If you send a PR with basic functionality, I can help with adjusting the
styles a bit. Thanks!</body></comment_new>
> <comment_new><author>@alshedivat</author><body>
> Just catching up on this discussion.
> 
> @hschwane, thanks for providing an implementation based on
`ihavecookies`! I looked through alshedivat/al-folio#223. It seems like
to be able to correctly (un)block different types of cookies (all of
which are third-party cookies) requires adding quite a bit of extra
JavaScript (including adding it directly to posts or pages in some
cases, e.g., when posts embed youtube videos or other external content).
This approach will put some extra burden on contributors and maintainers
of al-folio down the line.
> 
> By the way, the dialog from https://www.cookieconsent.com/ is similar
in that sense as it requires to manually add ALL scripts that use
cookies. So, if someone contributes a new feature to al-folio that uses
cookies, the contributor would have to go and update the cookie consent
dialog as well (or edit quite a bit of JS if `ihavecookies` is used).
> 
> Thinking about this more, I currently see only three options:
> 1. If we want to have cookie consent as a core part of al-folio (which
can be easily enabled or disabled), it needs to be a service that
automatically identifies and blocks cookies, without putting an extra
burden on the contributors or maintainers. The hosted version of [Cookie
Consent by Osano](https://www.osano.com/features/consent-management) is
an example.
> 2. Another option is to provide a very minimalistic cookie consent
dialog which simply says that the website uses cookies, without an
option to opt-in or opt-out (e.g., see the open-source edition of
[Osano](https://www.osano.com/cookieconsent/download/)).
> 3. Finally, not have cookie consent as part of al-folio, and make the
user responsible for figuring out whether they need a consent dialog and
which service to use.
> 
> Let me know what you think.</body></comment_new>
> <comment_new><author>@alshedivat</author><body>
> the best way to add GDPR compliant cookie consent is using
https://github.com/orestbida/cookieconsent</body></comment_new>
> </comments>
> 


</details>


> **Custom agent used: customization_agent**
> Expert customization assistant for the al-folio Jekyll academic
website template



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes alshedivat/al-folio#199

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for
you](https://github.com/alshedivat/al-folio/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: george-gca <31376482+george-gca@users.noreply.github.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Auto update markdown TOC

* Improve explanation of create from this template (#3499)

This pull request improves the documentation to clarify the recommended
way to create a new site using the al-folio template, emphasizing the
use of the "Use this template" button instead of forking. It explains
the differences between the two approaches, highlights common pitfalls
with forking, and provides guidance for users who have already forked
the repository.

Documentation improvements regarding repository creation:

* Added a prominent section in `README.md` explaining why "Use this
template" is preferred over forking, including step-by-step instructions
and advice for users who have already forked.
* Updated `QUICKSTART.md` to strongly recommend using the "Use this
template" button, clarified the steps for creating a new repository, and
included tips for users who have already forked by mistake.
* Added a new section in `INSTALL.md` detailing the differences between
using the template and forking, common pitfalls, and best practices for
contributing.

Signed-off-by: George Araújo <george.gcac@gmail.com>

* Auto update markdown TOC

* Update Google Scholar citations

* Added new research blog in README.md (#3522)

* Update Google Scholar citations

* Add link to personal page (laura wagner) in README (#3552)

Adding my personal academic website to the academics list

* Add Fukushima Lab to User community (Labs) (#3559)

This PR adds Fukushima Lab to the **User community** section in
`README.md` under **Labs**. Thank you for maintaining such a great and
inspiring website template.

Added link:
- https://kenji-fukushima-lab.github.io/

Co-authored-by: Kenji Fukushima <kf@MacBookPro.elecom>

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* add vud.org to community list (#3575)

Add vud.org to community list.

* Added website of B. Choi (Update README.md) (#3569)

Hello, please add my academic website to the community page. Thank you
for maintaining this project.

* [Update] add workshop to README.md (#3585)

Add new workshop to README.md

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Add pranavraj575 website to README

* Add deden.id website to README

Please let my website be on the growing list! I'm Deden Habibi Ali
Alfathimy, a researcher in outer space politics, with personal website
https://deden.id using al-folio.

* Upgrade al-folio to v1.0 (#2968)

## Overview

This PR delivers the `v1.0` architecture and runtime upgrade for
`al-folio`.

`al-folio` moves from a monolithic theme repo to a **thin starter +
plugin ecosystem** model, while preserving visual identity and core
behavior.

## What this PR changes

### 1) Starter becomes orchestration-only

`al-folio` is now responsible for:

- starter wiring (`Gemfile`, `_config.yml`)
- sample/demo content
- user-facing docs
- visual regression and cross-plugin integration tests

Component/runtime ownership is moved to dedicated gems.

### 2) Runtime and feature ownership split into plugins

`al_folio_core` now provides shared runtime/layout primitives and
contracts, and delegates feature modules to owning gems.

Key plugin ownership in v1:

- `al_folio_core`: core theme runtime/contracts
- `al_folio_distill`: Distill layouts/runtime
- `al_folio_cv`: CV rendering
- `al_search`: search runtime and modal behavior
- `al_icons`: icon runtime (Font Awesome, Academicons, Scholar Icons)
- `al_cookie`: cookie-consent runtime
- `al_img_tools`: image/gallery/lightbox tooling
- `al_math`: math/TikZ runtime integration
- additional `al-*` plugins for
analytics/charts/citations/comments/newsletter/external posts/upgrade
tooling

### 3) Styling/runtime modernization

- Tailwind-first v1 runtime is established.
- Legacy Bootstrap behavior is isolated behind optional
`al_folio_bootstrap_compat` for migration windows.
- jQuery-dependent runtime paths are removed/replaced in plugin-owned
implementations.

### 4) Test ownership policy is enforced

- `al-folio` keeps only starter-level integration and visual integrity
checks.
- Component correctness tests are owned by the corresponding plugin
repos.

This mirrors runtime ownership and reduces duplication/drift.

### 5) Upgrade and migration workflow

`al_folio_upgrade` is integrated for audit/apply/report migration flows,
including:

- config contract checks
- ownership drift detection
- local override drift audit/diff/acknowledgement workflow
- legacy marker detection
- plugin wiring validation

### 6) Documentation and contributor model for v1

Docs are updated to reflect modular v1 behavior and contribution
routing.

New governance additions include:

- plugin ownership/boundary guidance (`docs/BOUNDARIES.md`)
- plugin naming convention (theme-coupled vs reusable plugin tracks)
- featured-vs-bundled plugin distinction
- plugin catalog source + page (`_data/featured_plugins.yml`,
`_pages/plugins.md`)
- plugin feature proposal issue template
- PR template updates for ownership routing
- agent-facing setup and migration skills

## Compatibility and migration notes

- Plugin integration in starter is via `Gemfile` + `_config.yml`.
- `al-folio` starter intentionally does not use a gemspec in v1.
- Transitional Bootstrap compatibility remains available via
`al_folio_bootstrap_compat`.
- Existing front-matter contracts are preserved where possible; runtime
implementations are now plugin-owned.
- Customized sites can track local override drift with `bundle exec
al-folio upgrade overrides audit` and `.al-folio-overrides.yml`.

## Validation strategy in this PR

- visual parity checks against the v0.16.3 baseline
- starter integration suites (comments, plugin toggles, distill, compat,
upgrade CLI)
- style contract checks and repository linting

## Scope intent

This is the foundational v1 architecture PR.

Post-merge feature work should generally target owning plugin repos
first, with `al-folio` limited to starter wiring, docs, examples, and
integration/visual validation.

_Written by Codex on behalf of @alshedivat._

* Fix broken navbar: stop double-minifying Tailwind CSS in production (#3634)

## Summary

Fixes the broken navigation bar on the live demo
(https://alshedivat.github.io/al-folio/) introduced by the v1.0 upgrade
(#2968), plus two related production/deploy-only issues found while
auditing for the same class of bug.

## Root cause of the navbar break

The v1.0 upgrade made the site **Tailwind-first**. The deploy builds
with `JEKYLL_ENV=production`, which activates **jekyll-minifier**. Its
CSS compressor (`cssminify2`) mangles Tailwind v4 spacing tokens
**inside `calc()`**:

```
calc(var(--spacing)*0)   ->   calc(var( -  - spacing)*0)   // invalid
```

`cssminify2` treats the `--` inside `calc(var(--…))` as minus operators
and inserts spaces, producing an invalid custom-property name. This
silently breaks **every** spacing/positioning utility — most visibly
`.fixed-top`, so the fixed navbar is no longer pinned (`top/left/right`
drop out) and renders incorrectly. On the live site this affects 33
`var(--spacing)` references in `tailwind.css`.

It only manifests in **production**: a local `bundle exec jekyll serve`
is development mode (minifier off), and the `visual-regression` workflow
also serves in dev mode — so neither caught it.

### Why this fix

`tailwind.css` is already minified by al_folio_core's Tailwind build,
and `main.css` is compiled by Sass with `style: compressed`.
Re-minifying them with `cssminify2` adds nothing (it actually makes
`tailwind.css` ~315 bytes **larger**) and only introduces this
corruption. So we disable redundant CSS minification, mirroring the
existing `compress_javascript: false` (terser handles JS).

Verified end-to-end:
- The gem source `tailwind.css` has 82 intact `var(--spacing)`;
`cssminify2` corrupts all 82.
- jekyll-minifier (`lib/jekyll-minifier.rb:1061`): `return
output_file(path, content) unless config.compress_css?` — with
`compress_css: false`, `.css` files are written verbatim.
- A real `JEKYLL_ENV=production` build now emits `tailwind.css` with 82
intact `var(--spacing)`, 0 corrupted, and
`.fixed-top{...;position:fixed}` intact.
- PurgeCSS (the next deploy stage) preserves `calc(var(--spacing)*0)`
unchanged.

## Changes

1. **`_config.yml` — `jekyll-minifier.compress_css: false`** (the navbar
fix).
2. **`test/integration_css_minify.sh` + `unit-tests.yml`** — a
regression test that builds in **production mode** (the mode that
exposes this bug class) and asserts no `var( - - )` corruption, intact
`var(--spacing)`, a valid `.fixed-top`, and a non-empty `main.css`.
Passes with the fix; fails without it (83 corruptions). Closes the CI
blind spot that let this ship.
3. **`_config.yml` — drop dead `jekyll-minifier` exclude**
`assets/js/search/*.js`. That is a v0 path; in v1 the search runtime
ships under `assets/al_search/js/...`, so the glob matched nothing.
4. **`purgecss.config.js` — safelist `medium-zoom-overlay` /
`medium-zoom-image--opened`.** These classes are injected at runtime, so
they never appear in the static HTML PurgeCSS scans; their `z-index:999`
overlay rule was being purged on the deployed site, letting the
scroll-progress bar / ToC bleed through a zoomed image. Verified: the
rule survives purge with the safelist and is dropped without it.

## Broader audit — plugin fixes (released + pinned here)

I audited for the same bug class (regressions invisible to dev-mode
builds / leftovers from the v1 jQuery removal). The confirmed
plugin-owned issues were each fixed in their own repo, merged after
green CI, released to RubyGems, and pinned in this PR's `Gemfile`:

- **al_folio_core 1.0.10**
([#18](https://github.com/al-org-dev/al-folio-core/pull/18)) —
`main.css` cache-bust was permanently the empty-string MD5
(`bust_css_cache` globbed a non-existent `assets/_sass`) → stale CSS
after deploys; `bib.liquid` "N more authors" used `$(this)` → threw and
never expanded; `figure.liquid` `onerror` used `$()` → dead broken-image
fallback.
- **al_charts 1.0.1**
([#7](https://github.com/al-org-dev/al-charts/pull/7)) —
`chartjs-setup.js` was jQuery → `chartjs` charts threw `$ is not
defined` and never rendered.
- **al_folio_distill 1.0.2**
([#2](https://github.com/al-org-dev/al-folio-distill/pull/2)) —
`overrides.js` top-level `$(window).on("load")` → distill
footnote/citation theming never applied + console error.

Verified end-to-end with a production build after the pin bumps:
`main.css` now cache-busts to a real hash (`9278fad1…`, not
`d41d8cd9…`), zero jQuery `$(` in the built HTML, and the Tailwind
spacing utilities / `.fixed-top` navbar are intact.

Also noted (not fixed here): the `visual-regression` workflow only
renders in dev mode, so it can't catch production-only CSS regressions —
`test/integration_css_minify.sh` is the immediate guard; a production
screenshot leg would be a fuller backstop.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: expand CLAUDE.md with the v1 plugin-ecosystem architecture (#3635)

## Summary

Expands `CLAUDE.md` from a bare `@AGENTS.md` import into a useful entry
point for coding agents, while **keeping** that import so `AGENTS.md`'s
ownership boundaries, validated command set, and PR-routing rules still
flow in (and stay the short, ecosystem-neutral shared file).

The added content is the cross-repo "big picture" that no single file in
this repo currently documents — gathered by reading the starter
internals plus all 16 `al-*` / `al_folio_*` plugin gems:

- **al_folio_core hub + delegation map** — a `wrapper → tag → gem` table
for every bundled plugin, so a runtime change can be routed to the
owning repo in one lookup.
- **Sibling-repos-on-disk** layout and how to point the `Gemfile` at a
local gem checkout (`path:`) to test a gem fix against the site.
- **Cross-repo invariants** — two-layer feature gating (config flag
*and* front matter), `AssetsGenerator` build-time asset injection, the
`Gemfile` ↔ `_config.yml` plugin-list sync, the v1 config contract
(enforced by core's `:after_init` and `al-folio upgrade audit`),
`.al-folio-overrides.yml` drift tracking, and the time-boxed
bootstrap-compat path.
- **Daily dev loop** that `AGENTS.md` omits (`jekyll serve`, single
integration test, snapshot refresh, upgrade subcommands).
- The v1 Docker `/tmp/_site` rationale and the `style_contract.js`
boundary that fails CI if runtime/build files leak into the starter.

Every specific claim (gem versions, tag names, config keys) is grounded
in the actual repos. Prettier-clean.

> Split out from the navbar-fix PR (#3634) per request; this PR is
docs-only and independent.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix links (#3628)

## Summary

In the "User community" README section several links didn't work
anymore. I updated them where I was able to find a new link from the
same person, and removed the ones where I didn't find a new link.

## Ownership Routing

- [x] I confirmed this PR targets the correct repo based on
`docs/BOUNDARIES.md`.
- [x] This PR only changes starter-owned scope (`al-folio`) **or** I am
porting a routed change and linked the owning repo issue/PR.

## Plugin Ecosystem (if applicable)

- [x] Not applicable
- [ ] This PR proposes a plugin for **featured-only** listing.
- [ ] This PR proposes a plugin for **bundled** starter inclusion.

## Starter Wiring Changes

- [x] Not applicable
- [ ] Updated `Gemfile` dependency wiring.
- [ ] Updated `_config.yml` plugin activation/config.
- [ ] Updated `_data/featured_plugins.yml` metadata.

## Validation

- [x] `npm ci`
- [ ] `bundle exec jekyll build`
- [x] `npm run lint:prettier`
- [x] `npm run lint:style-contract`
- [ ] Integration tests (`test/integration_*.sh`) as needed
- [ ] Visual tests (`npm run test:visual`) as needed

* Fix visual regressions: broken repo stat cards and unstyled af-popover/tooltip (#3636)

## What's broken on the demo site

A full-page screenshot audit of every page on
https://alshedivat.github.io/al-folio/ surfaced two user-visible bugs
introduced or exposed by the v1 upgrade.

### Bug 1 — Repositories page: all stat cards show broken alt-text
(HIGH)

Both external services are currently unavailable:
- `github-readme-stats.vercel.app` → HTTP 503 `DEPLOYMENT_PAUSED`
- `github-profile-trophy.vercel.app` → HTTP 402

Every `<img>` on the repositories page fails to load, rendering as a
list of broken-image alt-text strings. The templates had no `onerror`
fallback.

**Fix (in al_folio_core):**
`onerror="this.closest('.repo').style.display='none'"` on every
stat-card image in `repo.liquid`, `repo_user.liquid`, and
`repo_trophies.liquid`. When a service is unavailable the entire card
hides gracefully; when it comes back up cards render normally.

### Bug 2 — `.af-popover` / `.af-tooltip` completely unstyled (MEDIUM)

`tooltips-setup.js` (active by default, since bootstrap-compat is
disabled) creates `.af-popover` and `.af-tooltip` elements as its
vanilla fallback — for example when hovering the author-info circle icon
(ⓘ) on the publications page. These class names had **no CSS rules at
all** in `al_folio_core`: no `position`, no styling, no `z-index`. The
tooltip/popover appeared as invisible, unpositioned text nodes appended
to `document.body`.

(The theme's `_utilities.scss` only defined `.popover` — Bootstrap's
class — which is irrelevant without bootstrap-compat loaded.)

**Fix (in al_folio_core):** Added `position: absolute`, `z-index:
1070/1080`, and theme-color styling to both classes. The purgecss
safelist in al-folio already protects both names so they survive the
deploy pipeline.

## Changes

- `Gemfile` / `Gemfile.lock`: bump `al_folio_core` 1.0.10 → 1.0.11 ([PR
#19](https://github.com/al-org-dev/al-folio-core/pull/19), now merged
and released)

## Scope

All other pages screenshotted look correct. No other CSS/layout
regressions were found beyond these two. The screenshot audit also
confirmed:
- The `var(--spacing)` Tailwind fix from #3634 is working correctly in
production.
- `main.css` cache-bust hash (`9278fad1…`) is stable and non-empty.
- All blog posts, CV, teaching, people, projects, books pages render as
expected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Add a link to my lab website in user community section (#3645)

Add a link to my lab website in the user community of README.

## Summary

Many thanks to the authors and contributors of this repo. I'm glad to
add my lab's website in the user community section of README.

## Ownership Routing

- [x] I confirmed this PR targets the correct repo based on
`docs/BOUNDARIES.md`.
- [ ] This PR only changes starter-owned scope (`al-folio`) **or** I am
porting a routed change and linked the owning repo issue/PR.

Owning repo (if not starter): <!-- e.g., al-org-dev/al-folio-core -->
Related issue/PR: <!-- link -->

## Plugin Ecosystem (if applicable)

- [x] Not applicable
- [ ] This PR proposes a plugin for **featured-only** listing.
- [ ] This PR proposes a plugin for **bundled** starter inclusion.

If plugin-related, provide:

- Plugin repo URL:
- Gem name:
- Jekyll plugin id:
- Compatibility (`al_folio_min`/`al_folio_max`):
- Demo page/post path:
- Maintainer contact:

## Starter Wiring Changes

- [x] Not applicable
- [ ] Updated `Gemfile` dependency wiring.
- [ ] Updated `_config.yml` plugin activation/config.
- [ ] Updated `_data/featured_plugins.yml` metadata.

## Validation

- [ ] `npm ci`
- [ ] `bundle exec jekyll build`
- [ ] `npm run lint:prettier`
- [ ] `npm run lint:style-contract`
- [ ] Integration tests (`test/integration_*.sh`) as needed
- [ ] Visual tests (`npm run test:visual`) as needed

## Notes

Compatibility, migration implications, and follow-ups:

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Update Google Scholar citations

* Bump nokogiri from 1.19.3 to 1.19.4 (#3653)

Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.19.3
to 1.19.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/sparklemotion/nokogiri/releases">nokogiri's
releases</a>.</em></p>
<blockquote>
<h2>v1.19.4 / 2026-06-18</h2>
<h3>Security</h3>
<ul>
<li>[CRuby] (Low) Fixed a possible invalid memory read when
<code>XML::Node#initialize_copy_with_args</code> is called with an
argument that is not a <code>Node</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-g9g8-vgvw-g3vf">GHSA-g9g8-vgvw-g3vf</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when an
<code>XML::XPathContext</code> is used after its source document has
been garbage collected. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-p67v-3w7g-wjg7">GHSA-p67v-3w7g-wjg7</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free during XInclude
processing via <code>Node#do_xinclude</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wfpw-mmfh-qq69">GHSA-wfpw-mmfh-qq69</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#root=</code> is assigned a non-element node. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wjv4-x9w8-wm3h">GHSA-wjv4-x9w8-wm3h</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when setting an
attribute value via <code>XML::Attr#value=</code> or
<code>#content=</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-phwj-rprq-35pp">GHSA-phwj-rprq-35pp</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a null pointer dereference when methods are
called on uninitialized wrapper objects (e.g. via
<code>allocate</code>); these now raise instead of crashing the process.
See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-9cv2-cfxc-v4v2">GHSA-9cv2-cfxc-v4v2</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#encoding=</code> raises an exception. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5v8h-3h3q-446p">GHSA-5v8h-3h3q-446p</a>
for more information.</li>
<li>[CRuby] (Medium) Fixed an out-of-bounds read in
<code>XML::NodeSet#[]</code> (alias <code>#slice</code>) when given a
large negative index. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5prr-v3j2-97mh">GHSA-5prr-v3j2-97mh</a>
for more information.</li>
<li>[JRuby] (Low) <code>XML::Schema</code> now enforces the
<code>NONET</code> parse option, which Nokogiri enables by default. It
was not enforced on JRuby, so a schema parsed with default options could
still fetch external resources over the network, potentially enabling
SSRF or XXE attacks and bypassing the mitigation for CVE-2020-26247. See
<a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-8678-w3jw-xfc2">GHSA-8678-w3jw-xfc2</a>
for more information.</li>
</ul>
<!-- raw HTML omitted -->

<pre><code>1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f
nokogiri-1.19.4-aarch64-linux-gnu.gem
35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af
nokogiri-1.19.4-aarch64-linux-musl.gem
a301313e38bb065d68239e79734bcd6f56fb6efaacebde29e9abf2a4735340ca
nokogiri-1.19.4-arm-linux-gnu.gem
588923c101bcfa78869734d247d25b598674323e7f22474fc468f6e5647311eb
nokogiri-1.19.4-arm-linux-musl.gem
a46db9853286e6597b36ebc6953817d15acf3a299583eb3f89fdc6f91dd63527
nokogiri-1.19.4-arm64-darwin.gem
ce04b9e268c9626852231a48b49128ed52034f1ccb39484a6da3875491cd709e
nokogiri-1.19.4-java.gem
051da97b8eccfdb5444fed40246a35e10d7298b9efe759b4cd25455ea04c587e
nokogiri-1.19.4-x64-mingw-ucrt.gem
7fd17057d3e1f00e9954a74b3cd76595d3d4a5ef233b7ed9599047c204f70551
nokogiri-1.19.4-x86_64-darwin.gem
379fae440b28915e3f19d752ce2dcf8465ed2b2fbefd2a7ca0dd497bc981a06a
nokogiri-1.19.4-x86_64-linux-gnu.gem
17dfb7c1fa194ae02fbf7c51a7afc8d278045ab3fdacfd86f91d02d7b274470b
nokogiri-1.19.4-x86_64-linux-musl.gem
50c951611c92bca05c51411aef45f1cbc50f2821c4802758c5c6d34696533ab5
nokogiri-1.19.4.gem
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md">nokogiri's
changelog</a>.</em></p>
<blockquote>
<h2>v1.19.4 / 2026-06-18</h2>
<h3>Security</h3>
<ul>
<li>[CRuby] (Low) Fixed a possible invalid memory read when
<code>XML::Node#initialize_copy_with_args</code> is called with an
argument that is not a <code>Node</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-g9g8-vgvw-g3vf">GHSA-g9g8-vgvw-g3vf</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when an
<code>XML::XPathContext</code> is used after its source document has
been garbage collected. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-p67v-3w7g-wjg7">GHSA-p67v-3w7g-wjg7</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free during XInclude
processing via <code>Node#do_xinclude</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wfpw-mmfh-qq69">GHSA-wfpw-mmfh-qq69</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#root=</code> is assigned a non-element node. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-wjv4-x9w8-wm3h">GHSA-wjv4-x9w8-wm3h</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when setting an
attribute value via <code>XML::Attr#value=</code> or
<code>#content=</code>. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-phwj-rprq-35pp">GHSA-phwj-rprq-35pp</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a null pointer dereference when methods are
called on uninitialized wrapper objects (e.g. via
<code>allocate</code>); these now raise instead of crashing the process.
See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-9cv2-cfxc-v4v2">GHSA-9cv2-cfxc-v4v2</a>
for more information.</li>
<li>[CRuby] (Low) Fixed a possible use-after-free when
<code>Document#encoding=</code> raises an exception. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5v8h-3h3q-446p">GHSA-5v8h-3h3q-446p</a>
for more information.</li>
<li>[CRuby] (Medium) Fixed an out-of-bounds read in
<code>XML::NodeSet#[]</code> (alias <code>#slice</code>) when given a
large negative index. See <a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-5prr-v3j2-97mh">GHSA-5prr-v3j2-97mh</a>
for more information.</li>
<li>[JRuby] (Low) <code>XML::Schema</code> now enforces the
<code>NONET</code> parse option, which Nokogiri enables by default. It
was not enforced on JRuby, so a schema parsed with default options could
still fetch external resources over the network, potentially enabling
SSRF or XXE attacks and bypassing the mitigation for CVE-2020-26247. See
<a
href="https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-8678-w3jw-xfc2">GHSA-8678-w3jw-xfc2</a>
for more information.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/8cfb9daae9ee4a0837508eab43c40fbc8c4138c9"><code>8cfb9da</code></a>
version bump to v1.19.4</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/a856d1e46bda04ef47a0bd2b9eefe86df1eb0bb2"><code>a856d1e</code></a>
fix: JRuby NONET bypass in XML::Schema (v1.19.x) (<a
href="https://redirect.github.com/sparklemotion/nokogiri/issues/3639">#3639</a>)</li>
<li><a
href="https://github.com/sparklemotion/nokogiri/commit/6a0aa1e7042ea58e10db713…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.