From bb2fd98253a1419682c33ebdfde9a1a5f2a40413 Mon Sep 17 00:00:00 2001
From: Nicholas La Roux <nicholas.laroux@shopify.com>
Date: Thu, 22 Aug 2024 13:31:57 +0900
Subject: [PATCH 001/384] Add Rails 7.2 docs

---
 lib/docs/scrapers/rdoc/rails.rb | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/docs/scrapers/rdoc/rails.rb b/lib/docs/scrapers/rdoc/rails.rb
index 03c9e4f2d5..43d9033beb 100644
--- a/lib/docs/scrapers/rdoc/rails.rb
+++ b/lib/docs/scrapers/rdoc/rails.rb
@@ -75,6 +75,10 @@ class Rails < Rdoc
       end
     end
 
+    version '7.2' do
+      self.release = '7.2.0'
+    end
+
     version '7.1' do
       self.release = '7.1.2'
     end

From b659d87b8cb7a59ed52c977227d717c00ae2c56f Mon Sep 17 00:00:00 2001
From: Pasha Suprunchuk <suprunchuk@internet.ru>
Date: Thu, 22 Aug 2024 07:54:04 +0000
Subject: [PATCH 002/384] [ver]: update to 0.75

---
 lib/docs/scrapers/react_native.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/react_native.rb b/lib/docs/scrapers/react_native.rb
index 651e0b1d04..6f8e39c03f 100644
--- a/lib/docs/scrapers/react_native.rb
+++ b/lib/docs/scrapers/react_native.rb
@@ -3,7 +3,7 @@ class ReactNative < UrlScraper
     self.name = 'React Native'
     self.slug = 'react_native'
     self.type = 'react_native'
-    self.release = '0.69'
+    self.release = '0.75'
     self.base_url = 'https://reactnative.dev/docs/'
     self.root_path = 'getting-started.html'
     self.links = {

From 3e110bfe22a5cd5e42b1c97ff0671b8acf64f62b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 22 Aug 2024 22:56:27 +0000
Subject: [PATCH 003/384] chore(deps): update dependency activesupport to
 v7.2.1

---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 01a65e54e5..442c3b502b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    activesupport (7.2.0)
+    activesupport (7.2.1)
       base64
       bigdecimal
       concurrent-ruby (~> 1.0, >= 1.3.1)
@@ -22,7 +22,7 @@ GEM
     byebug (11.1.3)
     chunky_png (1.4.0)
     coderay (1.1.3)
-    concurrent-ruby (1.3.3)
+    concurrent-ruby (1.3.4)
     connection_pool (2.4.1)
     daemons (1.4.1)
     drb (2.2.1)

From a7c9db2fe8143675ebcd1d54a93b3c3881c40eea Mon Sep 17 00:00:00 2001
From: Chris Grieser <73286100+chrisgrieser@users.noreply.github.com>
Date: Sun, 25 Aug 2024 12:20:40 +0200
Subject: [PATCH 004/384] docs: add new alfred workflow under 'Related
 Projects'

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index d161d6f9bc..54c9476102 100644
--- a/README.md
+++ b/README.md
@@ -178,6 +178,7 @@ Made something cool? Feel free to open a PR to add a new row to this table! You
 | [luckasRanarison/nvim-devdocs](https://github.com/luckasRanarison/nvim-devdocs)             | Neovim plugin                        | ![Latest GitHub commit](https://img.shields.io/github/last-commit/luckasRanarison/nvim-devdocs?logo=github&label)    | ![GitHub stars](https://img.shields.io/github/stars/luckasRanarison/nvim-devdocs?logo=github&label)    |
 | [toiletbril/dedoc](https://github.com/toiletbril/dedoc)                                     | Terminal based viewer                | ![Latest GitHub commit](https://img.shields.io/github/last-commit/toiletbril/dedoc?logo=github&label)                | ![GitHub stars](https://img.shields.io/github/stars/toiletbril/dedoc?logo=github&label)                |
 | [Raycast Devdocs](https://www.raycast.com/djpowers/devdocs)                                 | Raycast extension                    | Unavailable                 | Unavailable                |
+| [chrisgrieser/alfred-docs-searches](https://github.com/chrisgrieser/alfred-docs-searches)   | Alfred workflow                      | ![Latest GitHub commit](https://img.shields.io/github/last-commit/chrisgrieser/alfred-docs-searches?logo=github&label) | ![GitHub stars](https://img.shields.io/github/stars/chrisgrieser/alfred-docs-searches?logo=github&label) |
 
 ## Copyright / License
 

From a01f1aff05b12d206f3f1e36907b726e18d22e59 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 29 Aug 2024 19:31:03 +0000
Subject: [PATCH 005/384] chore(deps): update dependency thor to v1.3.2

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 442c3b502b..4bd16c6fe0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -130,7 +130,7 @@ GEM
       daemons (~> 1.0, >= 1.0.9)
       eventmachine (~> 1.0, >= 1.0.4)
       rack (>= 1, < 3)
-    thor (1.3.1)
+    thor (1.3.2)
     tilt (2.3.0)
     tty-pager (0.14.0)
       strings (~> 0.2.0)

From b05a4be91ba4c4a407a96f4722a0f76075952efa Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 29 Aug 2024 22:21:55 +0000
Subject: [PATCH 006/384] chore(deps): update dependency rr to v3.1.1

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 4bd16c6fe0..193a372849 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -88,7 +88,7 @@ GEM
     redcarpet (3.6.0)
     rexml (3.2.6)
     rouge (1.11.1)
-    rr (3.1.0)
+    rr (3.1.1)
     rss (0.3.0)
       rexml
     ruby2_keywords (0.0.5)

From 2449a70ff13ca5cf8295a37bc0cb00f9872617d7 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 30 Aug 2024 01:52:16 +0000
Subject: [PATCH 007/384] chore(deps): update dependency rss to v0.3.1

---
 Gemfile.lock | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 193a372849..a98171ff56 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -86,10 +86,11 @@ GEM
     rb-inotify (0.10.1)
       ffi (~> 1.0)
     redcarpet (3.6.0)
-    rexml (3.2.6)
+    rexml (3.2.9)
+      strscan
     rouge (1.11.1)
     rr (3.1.1)
-    rss (0.3.0)
+    rss (0.3.1)
       rexml
     ruby2_keywords (0.0.5)
     sass (3.7.4)
@@ -122,6 +123,7 @@ GEM
       unicode-display_width (>= 1.5, < 3.0)
       unicode_utils (~> 1.4)
     strings-ansi (0.2.0)
+    strscan (1.0.3)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
     terser (1.2.3)

From 58d50780d190b96ea2e47ded468eab17dc824b78 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 3 Sep 2024 21:39:16 +0000
Subject: [PATCH 008/384] chore(deps): update ruby/setup-ruby action to
 v1.191.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index af8ee47da8..7e6c7bd056 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+      uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # v1.191.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index ac3f079c88..a242f8d516 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+      uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # v1.191.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4bc4ac8fbc..dbc2c9c26c 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+      uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # v1.191.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 59856793bacd0f7973bd4428cc4f0cb6f3269dba Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 4 Sep 2024 01:32:23 +0000
Subject: [PATCH 009/384] chore(deps): update dependency ruby to v3.3.5

---
 .ruby-version  | 2 +-
 .tool-versions | 2 +-
 Gemfile        | 2 +-
 Gemfile.lock   | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.ruby-version b/.ruby-version
index a0891f563f..fa7adc7ac7 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.3.4
+3.3.5
diff --git a/.tool-versions b/.tool-versions
index 05668b726a..1dd199803a 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1 @@
-ruby 3.3.4
+ruby 3.3.5
diff --git a/Gemfile b/Gemfile
index e384795232..ebcfc2b98b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,5 @@
 source 'https://rubygems.org'
-ruby '3.3.4'
+ruby '3.3.5'
 
 gem 'activesupport', require: false
 gem 'html-pipeline'
diff --git a/Gemfile.lock b/Gemfile.lock
index 193a372849..47a2f7c89c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -185,7 +185,7 @@ DEPENDENCIES
   yajl-ruby
 
 RUBY VERSION
-   ruby 3.3.4p94
+   ruby 3.3.5p100
 
 BUNDLED WITH
    2.4.6

From 9568d535b61dd03c7827d22aced5e5ddb92ca460 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 4 Sep 2024 19:04:05 +0000
Subject: [PATCH 010/384] chore(deps): update ruby docker tag to v3.3.5

---
 Dockerfile        | 2 +-
 Dockerfile-alpine | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 03ea13938f..61d61ae624 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:3.3.4
+FROM ruby:3.3.5
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
 
diff --git a/Dockerfile-alpine b/Dockerfile-alpine
index 93a8b482bb..b2b3f50aa8 100644
--- a/Dockerfile-alpine
+++ b/Dockerfile-alpine
@@ -1,4 +1,4 @@
-FROM ruby:3.3.4-alpine
+FROM ruby:3.3.5-alpine
 
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true

From 86e24fb5ce74ff0f4fdb545a0083fe550c0e9315 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 5 Sep 2024 18:47:10 +0200
Subject: [PATCH 011/384] Update Vue documentation (3.5.2)

---
 lib/docs/scrapers/vue.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vue.rb b/lib/docs/scrapers/vue.rb
index 25a2101177..ed07bbc880 100644
--- a/lib/docs/scrapers/vue.rb
+++ b/lib/docs/scrapers/vue.rb
@@ -19,7 +19,7 @@ class Vue < UrlScraper
     HTML
 
     version '3' do
-      self.release = '3.4.27'
+      self.release = '3.5.2'
       self.base_url = 'https://vuejs.org/'
       self.initial_paths = %w(guide/introduction.html)
       html_filters.push 'vue/entries_v3', 'vue/clean_html'

From b4173ea2d43841023d946b7094776bcda76019f7 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 5 Sep 2024 19:01:46 +0200
Subject: [PATCH 012/384] Update Ruby on Rails documentation (7.2.1)

---
 docs/file-scrapers.md           | 6 +++---
 lib/docs/scrapers/rdoc/rails.rb | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index 2cc99165f4..ff9889033f 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -244,9 +244,9 @@ done
 * Open `railties/lib/rails/api/task.rb` and comment out any code related to sdoc (`configure_sdoc`)
 * Run `bundle config set --local without 'db job'` (in the Rails directory)
 * Run `bundle install && bundle exec rake rdoc` (in the Rails directory)
-* Run `cd guides && bundle exec rake guides:generate:html`
-* Copy the `guides/output` directory to `html/guides`
-* Copy the `html` directory to `docs/rails~[version]`
+* Run `cd guides && bundle exec rake guides:generate:html && cd ..`
+* Run `cp -r guides/output html/guides`
+* Run `cp -r html $DEVDOCS/docs/rails~[version]`
 
 ### Ruby
 Download the tarball of Ruby from https://www.ruby-lang.org/en/downloads/, extract it, run
diff --git a/lib/docs/scrapers/rdoc/rails.rb b/lib/docs/scrapers/rdoc/rails.rb
index 43d9033beb..414bd4a537 100644
--- a/lib/docs/scrapers/rdoc/rails.rb
+++ b/lib/docs/scrapers/rdoc/rails.rb
@@ -76,7 +76,7 @@ class Rails < Rdoc
     end
 
     version '7.2' do
-      self.release = '7.2.0'
+      self.release = '7.2.1'
     end
 
     version '7.1' do

From 67c06d765b2a663b223711902e667a47fdcc13e9 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 9 Sep 2024 16:37:05 +0000
Subject: [PATCH 013/384] chore(deps): update dependency sprockets to v3.7.4

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 47a2f7c89c..4ce6f2b282 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -109,7 +109,7 @@ GEM
       rack-protection (= 3.2.0)
       sinatra (= 3.2.0)
       tilt (~> 2.0)
-    sprockets (3.7.3)
+    sprockets (3.7.4)
       base64
       concurrent-ruby (~> 1.0)
       rack (> 1, < 3)

From af7ce9fb2aa541eb6ee6506d901a25b48df64e12 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 16 Sep 2024 15:04:33 +0000
Subject: [PATCH 014/384] chore(deps): update ruby/setup-ruby action to
 v1.192.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7e6c7bd056..8a1b8aac94 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # v1.191.0
+      uses: ruby/setup-ruby@a6b46b8a08edb18935835849f2a17072d5cc8c73 # v1.192.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index a242f8d516..fa2d836cf0 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # v1.191.0
+      uses: ruby/setup-ruby@a6b46b8a08edb18935835849f2a17072d5cc8c73 # v1.192.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index dbc2c9c26c..48d4ffdc5b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
     - name: Set up Ruby
-      uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # v1.191.0
+      uses: ruby/setup-ruby@a6b46b8a08edb18935835849f2a17072d5cc8c73 # v1.192.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 9282390a647ed6445f078bb5e75d5c4553caa5bc Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 17 Sep 2024 19:52:23 +0000
Subject: [PATCH 015/384] chore(deps): update ruby/setup-ruby action to
 v1.193.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8a1b8aac94..26a767f15f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a6b46b8a08edb18935835849f2a17072d5cc8c73 # v1.192.0
+      uses: ruby/setup-ruby@f321cf5a4d1533575411f8752cf25b86478b0442 # v1.193.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index fa2d836cf0..a20cc80507 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a6b46b8a08edb18935835849f2a17072d5cc8c73 # v1.192.0
+      uses: ruby/setup-ruby@f321cf5a4d1533575411f8752cf25b86478b0442 # v1.193.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 48d4ffdc5b..006fc13599 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a6b46b8a08edb18935835849f2a17072d5cc8c73 # v1.192.0
+      uses: ruby/setup-ruby@f321cf5a4d1533575411f8752cf25b86478b0442 # v1.193.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From b603c8cdf8f42bf6cff5e8be8f83bc91f65a94c5 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 19 Sep 2024 13:55:55 +0000
Subject: [PATCH 016/384] chore(deps): update dependency sprockets to v3.7.5

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 4ce6f2b282..eaa8909c2b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -109,7 +109,7 @@ GEM
       rack-protection (= 3.2.0)
       sinatra (= 3.2.0)
       tilt (~> 2.0)
-    sprockets (3.7.4)
+    sprockets (3.7.5)
       base64
       concurrent-ruby (~> 1.0)
       rack (> 1, < 3)

From 4f8203fa8a6a48f48f52a6c7e369faba1d9480d3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 25 Sep 2024 22:58:03 +0000
Subject: [PATCH 017/384] chore(deps): update github actions

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 26a767f15f..b8ecf1edd6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f321cf5a4d1533575411f8752cf25b86478b0442 # v1.193.0
+      uses: ruby/setup-ruby@c04af2bb7258bb6a03df1d3c1865998ac9390972 # v1.194.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index a20cc80507..ecc8bda63a 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f321cf5a4d1533575411f8752cf25b86478b0442 # v1.193.0
+      uses: ruby/setup-ruby@c04af2bb7258bb6a03df1d3c1865998ac9390972 # v1.194.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 006fc13599..945d723de2 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -9,9 +9,9 @@ jobs:
   test:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
+    - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f321cf5a4d1533575411f8752cf25b86478b0442 # v1.193.0
+      uses: ruby/setup-ruby@c04af2bb7258bb6a03df1d3c1865998ac9390972 # v1.194.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 8c1b94c8e1174d80fd9a43042cb5c7f421732866 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 5 Oct 2024 21:45:05 +0000
Subject: [PATCH 018/384] chore(deps): update ruby/setup-ruby action to
 v1.195.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b8ecf1edd6..15e7cfd63a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@c04af2bb7258bb6a03df1d3c1865998ac9390972 # v1.194.0
+      uses: ruby/setup-ruby@086ffb1a2090c870a3f881cc91ea83aa4243d408 # v1.195.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index ecc8bda63a..f3f12570cd 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@c04af2bb7258bb6a03df1d3c1865998ac9390972 # v1.194.0
+      uses: ruby/setup-ruby@086ffb1a2090c870a3f881cc91ea83aa4243d408 # v1.195.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 945d723de2..f63db2110b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@c04af2bb7258bb6a03df1d3c1865998ac9390972 # v1.194.0
+      uses: ruby/setup-ruby@086ffb1a2090c870a3f881cc91ea83aa4243d408 # v1.195.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From c9cc0b4b0515a7daf738b04ed2b8e6cc11926c68 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 7 Oct 2024 15:54:01 +0000
Subject: [PATCH 019/384] chore(deps): update dependency terser to v1.2.4

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index eaa8909c2b..cbc8521f9e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -124,7 +124,7 @@ GEM
     strings-ansi (0.2.0)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
-    terser (1.2.3)
+    terser (1.2.4)
       execjs (>= 0.3.0, < 3)
     thin (1.8.2)
       daemons (~> 1.0, >= 1.0.9)

From 6293ae880cb656957e3161f922ac18fc4cf7b108 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 7 Oct 2024 22:00:28 +0000
Subject: [PATCH 020/384] chore(deps): update github actions

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 15e7cfd63a..dceadff778 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@086ffb1a2090c870a3f881cc91ea83aa4243d408 # v1.195.0
+      uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # v1.196.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index f3f12570cd..3f84390394 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@086ffb1a2090c870a3f881cc91ea83aa4243d408 # v1.195.0
+      uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # v1.196.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f63db2110b..20ab33affa 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -9,9 +9,9 @@ jobs:
   test:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+    - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
     - name: Set up Ruby
-      uses: ruby/setup-ruby@086ffb1a2090c870a3f881cc91ea83aa4243d408 # v1.195.0
+      uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # v1.196.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From d88f593104c4b0bbd99e6c971b3f4131c2545af0 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 8 Oct 2024 21:42:30 +0200
Subject: [PATCH 021/384] Update Python documentation (3.13.0)

---
 lib/docs/scrapers/python.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/python.rb b/lib/docs/scrapers/python.rb
index 3ff84bd76a..bd2c1dc176 100644
--- a/lib/docs/scrapers/python.rb
+++ b/lib/docs/scrapers/python.rb
@@ -28,7 +28,7 @@ class Python < UrlScraper
     HTML
 
     version '3.13' do
-      self.release = '3.13.0rc1'
+      self.release = '3.13.0'
       self.base_url = "https://docs.python.org/#{self.version}/"
 
       html_filters.push 'python/entries_v3', 'sphinx/clean_html', 'python/clean_html'

From f3294f6eee9e87154bfafba1e3d078e247a89d6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Thu, 10 Oct 2024 08:31:31 +0200
Subject: [PATCH 022/384] Update Crystal docs to 1.14.0

---
 lib/docs/scrapers/crystal.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index 203d1febe1..c06d2fa7df 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -2,7 +2,7 @@ module Docs
   class Crystal < UrlScraper
     include MultipleBaseUrls
     self.type = 'crystal'
-    self.release = '1.13.1'
+    self.release = '1.14.0'
     self.base_urls = [
       "https://crystal-lang.org/api/#{release}/",
       "https://crystal-lang.org/reference/#{release[0..2]}/",

From 5a6f0ad16c2eeacbab5796d7cefd3d1550a1d13c Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 10 Oct 2024 22:32:33 +0200
Subject: [PATCH 023/384] Update HAProxy documentation (3.0.0)

Fixes #2332.
---
 lib/docs/scrapers/haproxy.rb | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/haproxy.rb b/lib/docs/scrapers/haproxy.rb
index 9135f4d7db..5f87168732 100644
--- a/lib/docs/scrapers/haproxy.rb
+++ b/lib/docs/scrapers/haproxy.rb
@@ -16,10 +16,15 @@ class Haproxy < UrlScraper
     options[:follow_links] = false
 
     options[:attribution] = <<-HTML
-      &copy; 2023 Willy Tarreau, HAProxy contributors<br>
+      &copy; 2024 Willy Tarreau, HAProxy contributors<br>
       Licensed under the GNU General Public License version 2.
     HTML
 
+    version '3.0' do
+      self.release = '3.0.0'
+      self.base_url = "https://docs.haproxy.org/#{self.version}/"
+    end
+
     version '2.9' do
       self.release = '2.9.0'
       self.base_url = "https://docs.haproxy.org/#{self.version}/"

From e68269b3f4ce4a0ae896d93be35af8cc9472d609 Mon Sep 17 00:00:00 2001
From: Tim Lim <tim@thewheatfield.org>
Date: Sun, 13 Oct 2024 19:19:48 +0800
Subject: [PATCH 024/384] Fix Cordova indents with new option

---
 lib/docs/filters/core/clean_html.rb | 1 +
 lib/docs/scrapers/cordova.rb        | 1 +
 2 files changed, 2 insertions(+)

diff --git a/lib/docs/filters/core/clean_html.rb b/lib/docs/filters/core/clean_html.rb
index f17333c011..c8a7cfc11e 100644
--- a/lib/docs/filters/core/clean_html.rb
+++ b/lib/docs/filters/core/clean_html.rb
@@ -8,6 +8,7 @@ def call
       xpath('./text()', './/text()[not(ancestor::pre) and not(ancestor::code) and not(ancestor::div[contains(concat(" ", normalize-space(@class), " "), " prism ")])]').each do |node|
         content = node.content
         next unless content.valid_encoding?
+        next if context[:clean_html_maintain_nbsp] && !content.index(" ").nil?
         content.gsub! %r{[[:space:]]+}, ' '
         node.content = content
       end
diff --git a/lib/docs/scrapers/cordova.rb b/lib/docs/scrapers/cordova.rb
index 9395a316fb..0ef045712e 100644
--- a/lib/docs/scrapers/cordova.rb
+++ b/lib/docs/scrapers/cordova.rb
@@ -11,6 +11,7 @@ class Cordova < UrlScraper
     html_filters.push 'cordova/entries', 'cordova/clean_html'
 
     options[:container] = '.docs'
+    options[:clean_html_maintain_nbsp] = true
     options[:skip] = %w(index.html)
 
     options[:fix_urls] = ->(url) do

From 38faed2a24b6da28874763367120512434b947f2 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 14 Oct 2024 03:27:29 +0000
Subject: [PATCH 025/384] chore(deps): update dependency rack to v2.2.10

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index cbc8521f9e..acd6cdf516 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -74,7 +74,7 @@ GEM
       byebug (~> 11.0)
       pry (>= 0.13, < 0.15)
     racc (1.7.3)
-    rack (2.2.9)
+    rack (2.2.10)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)

From 51f6330643cf27298f49501c13dae78d94dc2baa Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 15 Oct 2024 21:51:20 +0000
Subject: [PATCH 026/384] chore(deps): update dependency activesupport to
 v7.2.1.1

---
 Gemfile.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index acd6cdf516..3263e33002 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    activesupport (7.2.1)
+    activesupport (7.2.1.1)
       base64
       bigdecimal
       concurrent-ruby (~> 1.0, >= 1.3.1)
@@ -38,7 +38,7 @@ GEM
     html-pipeline (2.14.3)
       activesupport (>= 2)
       nokogiri (>= 1.4)
-    i18n (1.14.5)
+    i18n (1.14.6)
       concurrent-ruby (~> 1.0)
     image_optim (0.31.3)
       exifr (~> 1.2, >= 1.2.2)
@@ -51,7 +51,7 @@ GEM
       image_optim (~> 0.19)
     image_size (3.3.0)
     in_threads (1.6.0)
-    logger (1.6.0)
+    logger (1.6.1)
     method_source (1.0.0)
     mini_portile2 (2.8.7)
     minitest (5.25.1)

From df688154b671719774912df548ba652070ee7f19 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 17 Oct 2024 09:12:30 +0200
Subject: [PATCH 027/384] Update Ansible documentation

Fixes #2325.
---
 lib/docs/scrapers/ansible.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/ansible.rb b/lib/docs/scrapers/ansible.rb
index 7b021b26ad..1b1ef95e72 100644
--- a/lib/docs/scrapers/ansible.rb
+++ b/lib/docs/scrapers/ansible.rb
@@ -11,7 +11,7 @@ class Ansible < UrlScraper
 
     options[:attribution] = <<-HTML
       &copy; 2012&ndash;2018 Michael DeHaan<br>
-      &copy; 2018&ndash;2021 Red Hat, Inc.<br>
+      &copy; 2018&ndash;2024 Red Hat, Inc.<br>
       Licensed under the GNU General Public License version 3.
     HTML
 

From 248dccd113a01645841257346bb8af06c9195338 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 17 Oct 2024 22:39:14 +0000
Subject: [PATCH 028/384] chore(deps): update ruby/setup-ruby action to
 v1.197.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index dceadff778..1827a19b08 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # v1.196.0
+      uses: ruby/setup-ruby@7bae1d00b5db9166f4f0fc47985a3a5702cb58f0 # v1.197.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 3f84390394..958e9bcdc8 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # v1.196.0
+      uses: ruby/setup-ruby@7bae1d00b5db9166f4f0fc47985a3a5702cb58f0 # v1.197.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 20ab33affa..4a1b003ceb 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # v1.196.0
+      uses: ruby/setup-ruby@7bae1d00b5db9166f4f0fc47985a3a5702cb58f0 # v1.197.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 5ff242b4c3e23c791f52676f0ac998b984ba1852 Mon Sep 17 00:00:00 2001
From: Dave Powers <djpowers89@gmail.com>
Date: Thu, 17 Oct 2024 20:44:51 -0400
Subject: [PATCH 029/384] Add field to docs.json denoting available aliases

- read JavaScript file defining slug/alias mapping
- parse aliases object as Ruby hash
- add alias key to JSON output with value or null
---
 lib/docs/core/manifest.rb | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lib/docs/core/manifest.rb b/lib/docs/core/manifest.rb
index b7c2e00dc8..a043cb5db0 100644
--- a/lib/docs/core/manifest.rb
+++ b/lib/docs/core/manifest.rb
@@ -20,6 +20,15 @@ def as_json
         if doc.options[:attribution].is_a?(String)
           json[:attribution] = doc.options[:attribution].strip
         end
+
+        # parse doc aliases from JS file as Ruby hash
+        entry_file = File.open("assets/javascripts/models/entry.js")
+        data = entry_file.read
+        aliases = eval data.split("ALIASES = ").last.split(";").first
+
+        # set alias value
+        json["alias"] = aliases[json["slug"].to_sym]
+
         result << json
       end
     end

From ed116eb795d3b45f78b4b2348ea5b4d758fc7e3b Mon Sep 17 00:00:00 2001
From: Dave Powers <djpowers89@gmail.com>
Date: Thu, 17 Oct 2024 21:10:00 -0400
Subject: [PATCH 030/384] Update and fix manifest test

---
 lib/docs/core/manifest.rb           | 2 +-
 test/files/docs.json                | 2 +-
 test/lib/docs/core/manifest_test.rb | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/docs/core/manifest.rb b/lib/docs/core/manifest.rb
index a043cb5db0..2a1f084c49 100644
--- a/lib/docs/core/manifest.rb
+++ b/lib/docs/core/manifest.rb
@@ -27,7 +27,7 @@ def as_json
         aliases = eval data.split("ALIASES = ").last.split(";").first
 
         # set alias value
-        json["alias"] = aliases[json["slug"].to_sym]
+        json["alias"] = aliases[json["slug"].try(:to_sym)]
 
         result << json
       end
diff --git a/test/files/docs.json b/test/files/docs.json
index bd9146b528..7f795c4356 100644
--- a/test/files/docs.json
+++ b/test/files/docs.json
@@ -1 +1 @@
-[{"name":"CSS","slug":"css","type":"mdn","release":null,"mtime":1420139788,"db_size":3460507},{"name":"DOM","slug":"dom","type":"mdn","release":null,"mtime":1420139789,"db_size":11399128},{"name":"DOM Events","slug":"dom_events","type":"mdn","release":null,"mtime":1420139790,"db_size":889020},{"name":"HTML","slug":"html~5","type":"mdn","version":"5","mtime":1420139791,"db_size":1835647},{"name":"HTML","slug":"html~4","type":"mdn","version":"4","mtime":1420139790,"db_size":1835646},{"name":"HTTP","slug":"http","type":"rfc","release":null,"mtime":1420139790,"db_size":183083},{"name":"JavaScript","slug":"javascript","type":"mdn","release":null,"mtime":1420139791,"db_size":4125477}]
+[{"name":"CSS","slug":"css","type":"mdn","release":null,"mtime":1420139788,"db_size":3460507,"alias":null},{"name":"DOM","slug":"dom","type":"mdn","release":null,"mtime":1420139789,"db_size":11399128,"alias":null},{"name":"DOM Events","slug":"dom_events","type":"mdn","release":null,"mtime":1420139790,"db_size":889020,"alias":null},{"name":"HTML","slug":"html~5","type":"mdn","version":"5","mtime":1420139791,"db_size":1835647,"alias":null},{"name":"HTML","slug":"html~4","type":"mdn","version":"4","mtime":1420139790,"db_size":1835646,"alias":null},{"name":"HTTP","slug":"http","type":"rfc","release":null,"mtime":1420139790,"db_size":183083,"alias":null},{"name":"JavaScript","slug":"javascript","type":"mdn","release":null,"mtime":1420139791,"db_size":4125477,"alias":"js"}]
diff --git a/test/lib/docs/core/manifest_test.rb b/test/lib/docs/core/manifest_test.rb
index 636885cd1a..42c053af94 100644
--- a/test/lib/docs/core/manifest_test.rb
+++ b/test/lib/docs/core/manifest_test.rb
@@ -64,7 +64,7 @@ class ManifestTest < Minitest::Spec
       it "includes the doc's meta representation" do
         json = manifest.as_json
         assert_equal 1, json.length
-        assert_equal "{\"name\"=>\"Test\", \"db_size\"=>776533, :attribution=>\"foo\"}", json[0].to_s
+        assert_equal "{\"name\"=>\"Test\", \"db_size\"=>776533, :attribution=>\"foo\", \"alias\"=>nil}", json[0].to_s
       end
     end
 

From 47218a47c2366b8ae4bb07ed97c25cbce8041310 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 23 Oct 2024 17:08:54 +0000
Subject: [PATCH 031/384] chore(deps): update actions/checkout action to v4.2.2

---
 .github/workflows/test.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4a1b003ceb..954b85dd69 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -9,7 +9,7 @@ jobs:
   test:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
+    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
       uses: ruby/setup-ruby@7bae1d00b5db9166f4f0fc47985a3a5702cb58f0 # v1.197.0
       with:

From 11a85f36a0c85d980379bf07d8a340d0cbafc497 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 23 Oct 2024 23:28:44 +0000
Subject: [PATCH 032/384] chore(deps): update dependency activesupport to
 v7.2.1.2

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 3263e33002..07554ea87c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    activesupport (7.2.1.1)
+    activesupport (7.2.1.2)
       base64
       bigdecimal
       concurrent-ruby (~> 1.0, >= 1.3.1)

From 48c3e26f94ec71a2af176090a725014998c472d1 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 30 Oct 2024 22:29:00 +0000
Subject: [PATCH 033/384] chore(deps): update ruby/setup-ruby action to
 v1.198.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1827a19b08..d870e61bbd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7bae1d00b5db9166f4f0fc47985a3a5702cb58f0 # v1.197.0
+      uses: ruby/setup-ruby@98aefb3c83eea830993080938ed245dc8e2b843b # v1.198.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 958e9bcdc8..dd8d0dad0a 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7bae1d00b5db9166f4f0fc47985a3a5702cb58f0 # v1.197.0
+      uses: ruby/setup-ruby@98aefb3c83eea830993080938ed245dc8e2b843b # v1.198.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 954b85dd69..41476de193 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7bae1d00b5db9166f4f0fc47985a3a5702cb58f0 # v1.197.0
+      uses: ruby/setup-ruby@98aefb3c83eea830993080938ed245dc8e2b843b # v1.198.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 9fe93b4b7fee2c0ed4b0b04ab6db029aae54788c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 31 Oct 2024 03:18:30 +0000
Subject: [PATCH 034/384] chore(deps): update dependency activesupport to
 v7.2.2

---
 Gemfile.lock | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 07554ea87c..c011dd7950 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,8 +1,9 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    activesupport (7.2.1.2)
+    activesupport (7.2.2)
       base64
+      benchmark (>= 0.3)
       bigdecimal
       concurrent-ruby (~> 1.0, >= 1.3.1)
       connection_pool (>= 2.2.5)
@@ -13,6 +14,7 @@ GEM
       securerandom (>= 0.3)
       tzinfo (~> 2.0, >= 2.0.5)
     base64 (0.2.0)
+    benchmark (0.3.0)
     better_errors (2.10.1)
       erubi (>= 1.0.0)
       rack (>= 0.9.0)

From f899731ee562c64e89a7fcd43f5dadc2fb0af3e0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 31 Oct 2024 21:15:32 +0000
Subject: [PATCH 035/384] chore(deps): update ruby/setup-ruby action to
 v1.199.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d870e61bbd..b13f2ec27b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@98aefb3c83eea830993080938ed245dc8e2b843b # v1.198.0
+      uses: ruby/setup-ruby@7d3497fd78c07c0d84ebafa58d8dac60cd1f0763 # v1.199.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index dd8d0dad0a..8a4c38aa5a 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@98aefb3c83eea830993080938ed245dc8e2b843b # v1.198.0
+      uses: ruby/setup-ruby@7d3497fd78c07c0d84ebafa58d8dac60cd1f0763 # v1.199.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 41476de193..66f228e191 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@98aefb3c83eea830993080938ed245dc8e2b843b # v1.198.0
+      uses: ruby/setup-ruby@7d3497fd78c07c0d84ebafa58d8dac60cd1f0763 # v1.199.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 56793f43ed225ce9f28d92a40935c55246ca4beb Mon Sep 17 00:00:00 2001
From: JL <34074989+commandline-be@users.noreply.github.com>
Date: Sun, 3 Nov 2024 19:32:22 +0100
Subject: [PATCH 036/384] Update nim.rb

added most recent version 2.2.0
---
 lib/docs/scrapers/nim.rb | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/docs/scrapers/nim.rb b/lib/docs/scrapers/nim.rb
index 9001dbee20..a5534877ca 100644
--- a/lib/docs/scrapers/nim.rb
+++ b/lib/docs/scrapers/nim.rb
@@ -17,6 +17,10 @@ class Nim < UrlScraper
       Licensed under the MIT License.
     HTML
 
+    version do
+      self.release = '2.2.0'
+    end
+    
     version do
       self.release = '2.0.2'
     end

From 3737a0e1bdb1328f0635df50c93eeea666f963ae Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 5 Nov 2024 13:38:38 +0000
Subject: [PATCH 037/384] chore(deps): update ruby/setup-ruby action to
 v1.200.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b13f2ec27b..ac1e0c04ec 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7d3497fd78c07c0d84ebafa58d8dac60cd1f0763 # v1.199.0
+      uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 8a4c38aa5a..458b21dcf0 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7d3497fd78c07c0d84ebafa58d8dac60cd1f0763 # v1.199.0
+      uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 66f228e191..244ab6e255 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7d3497fd78c07c0d84ebafa58d8dac60cd1f0763 # v1.199.0
+      uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 8185a84c00f69a8612def93cac6e921f7f8e0ccd Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 5 Nov 2024 16:52:38 +0000
Subject: [PATCH 038/384] chore(deps): update dependency ruby to v3.3.6

---
 .ruby-version  | 2 +-
 .tool-versions | 2 +-
 Gemfile        | 2 +-
 Gemfile.lock   | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.ruby-version b/.ruby-version
index fa7adc7ac7..9c25013dbb 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.3.5
+3.3.6
diff --git a/.tool-versions b/.tool-versions
index 1dd199803a..5aa8e0c30b 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1 @@
-ruby 3.3.5
+ruby 3.3.6
diff --git a/Gemfile b/Gemfile
index ebcfc2b98b..9079b2c955 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,5 @@
 source 'https://rubygems.org'
-ruby '3.3.5'
+ruby '3.3.6'
 
 gem 'activesupport', require: false
 gem 'html-pipeline'
diff --git a/Gemfile.lock b/Gemfile.lock
index c011dd7950..95ae67be86 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -187,7 +187,7 @@ DEPENDENCIES
   yajl-ruby
 
 RUBY VERSION
-   ruby 3.3.5p100
+   ruby 3.3.6p108
 
 BUNDLED WITH
    2.4.6

From d38532187099003faf5aa33963ac7db07d5ef68e Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 5 Nov 2024 21:02:32 +0000
Subject: [PATCH 039/384] chore(deps): update ruby docker tag to v3.3.6

---
 Dockerfile        | 2 +-
 Dockerfile-alpine | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 61d61ae624..7ec33c21b8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:3.3.5
+FROM ruby:3.3.6
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
 
diff --git a/Dockerfile-alpine b/Dockerfile-alpine
index b2b3f50aa8..1d258221a9 100644
--- a/Dockerfile-alpine
+++ b/Dockerfile-alpine
@@ -1,4 +1,4 @@
-FROM ruby:3.3.5-alpine
+FROM ruby:3.3.6-alpine
 
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true

From 16918d2d8ec6944515be28d9891ce4d1000461a3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 7 Nov 2024 15:23:06 +0000
Subject: [PATCH 040/384] chore(deps): update ruby/setup-ruby action to
 v1.201.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ac1e0c04ec..cdaa38cb5a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0
+      uses: ruby/setup-ruby@46ca53beb334a2329bcd0e46a694816a6ae6d173 # v1.201.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 458b21dcf0..e858bf97dd 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0
+      uses: ruby/setup-ruby@46ca53beb334a2329bcd0e46a694816a6ae6d173 # v1.201.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 244ab6e255..407024c924 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0
+      uses: ruby/setup-ruby@46ca53beb334a2329bcd0e46a694816a6ae6d173 # v1.201.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From eaec6ec43ff3136df6ba83a7abcb55ad28da492f Mon Sep 17 00:00:00 2001
From: Scott Goley <scottmgoley@gmail.com>
Date: Fri, 8 Nov 2024 23:05:14 -0500
Subject: [PATCH 041/384] duckdb docs (v1.1) - scrape v1

---
 lib/docs/filters/duckdb/clean_html.rb | 41 ++++++++++++++++
 lib/docs/filters/duckdb/entries.rb    | 45 +++++++++++++++++
 lib/docs/scrapers/duckdb.rb           | 69 +++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 lib/docs/filters/duckdb/clean_html.rb
 create mode 100644 lib/docs/filters/duckdb/entries.rb
 create mode 100644 lib/docs/scrapers/duckdb.rb

diff --git a/lib/docs/filters/duckdb/clean_html.rb b/lib/docs/filters/duckdb/clean_html.rb
new file mode 100644
index 0000000000..ae518c7b38
--- /dev/null
+++ b/lib/docs/filters/duckdb/clean_html.rb
@@ -0,0 +1,41 @@
+module Docs
+  class Duckdb
+    class CleanHtmlFilter < Filter
+      def call
+        # First extract the main content
+        @doc = at_css('main')
+        return doc if @doc.nil?
+
+        # Remove navigation and header elements
+        css('.headerline', '.landingmenu', '.search_icon', '#sidebar', '.pagemeta', '.toc_menu', '.section-nav').remove
+
+        # Clean up code blocks
+        css('pre').each do |node|
+          # Detect language from class or parent div
+          if node['class']&.include?('sql') || node.at_css('code.sql')
+            node['data-language'] = 'sql'
+          elsif node['class']&.include?('language-sql')
+            node['data-language'] = 'sql'
+          end
+          node.content = node.content.strip
+        end
+
+        # Remove unnecessary attributes but keep essential ones
+        css('div, span, p').each do |node|
+          node.remove_attribute('style')
+          node.remove_attribute('class') unless node['class'] =~ /highlight/
+        end
+
+        # Remove empty elements
+        css('div, span').each do |node|
+          node.remove if node.content.strip.empty?
+        end
+
+        # Remove script tags
+        css('script').remove
+
+        doc
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/docs/filters/duckdb/entries.rb b/lib/docs/filters/duckdb/entries.rb
new file mode 100644
index 0000000000..ea9290227f
--- /dev/null
+++ b/lib/docs/filters/duckdb/entries.rb
@@ -0,0 +1,45 @@
+module Docs
+  class Duckdb
+    class EntriesFilter < Docs::EntriesFilter
+      def get_name
+        at_css('h1')&.content || 'DuckDB'
+      end
+
+      def get_type
+        case subpath
+        when /\Asql\//
+          'SQL Reference'
+        when /\Aapi\//
+          'Client APIs'
+        when /\Aguides\//
+          'How-to Guides'
+        when /\Adata\//
+          'Data Import'
+        when /\Aoperations_manual\//
+          'Operations Manual'
+        when /\Adev\//
+          'Development'
+        when /\Ainternals\//
+          'Internals'
+        when /\Aextensions\//
+          'Extensions'
+        when /\Aarchive\//
+          'Archive'
+        else
+          'Documentation'
+        end
+      end
+
+      def additional_entries
+        entries = []
+        css('h2[id]', 'h3[id]').each do |node|
+          name = node.content.strip
+          # Clean up the name
+          name = name.gsub(/[\r\n\t]/, ' ').squeeze(' ')
+          entries << [name, node['id'], get_type]
+        end
+        entries
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/docs/scrapers/duckdb.rb b/lib/docs/scrapers/duckdb.rb
new file mode 100644
index 0000000000..a160b3ef21
--- /dev/null
+++ b/lib/docs/scrapers/duckdb.rb
@@ -0,0 +1,69 @@
+module Docs
+  class Duckdb < UrlScraper
+    self.name = 'DuckDB'
+    self.type = 'duckdb'
+    self.root_path = 'index.html'
+    self.links = {
+      home: 'https://duckdb.org/',
+      code: 'https://github.com/duckdb/duckdb'
+    }
+
+    html_filters.push 'duckdb/entries', 'duckdb/clean_html'
+
+    options[:container] = '.documentation'
+    
+    options[:skip_patterns] = [
+      /installation/,
+      /archive/,
+      /reference/,
+    ]
+
+    options[:skip] = %w(
+      docs/archive/
+      docs/installation/
+      docs/api/
+    )
+
+    options[:attribution] = <<-HTML
+      &copy; Copyright 2018&ndash;2024 Stichting DuckDB Foundation<br>
+      Licensed under the MIT License.
+    HTML
+
+    version '1.1' do
+      self.release = '1.1.x'
+      self.base_url = 'http://localhost:8000/docs/'
+    end
+
+    # version '1.0' do
+    #     self.release = '1.0.x'
+    #     self.base_url = "https://duckdb.org/docs/archive/#{self.version}/"
+
+    #     html_filters.push 'duckdb/clean_html'
+    # end
+
+    # version '0.9' do
+    #     self.release = '0.9.x'
+    #     self.base_url = "https://duckdb.org/docs/archive/#{self.version}/"
+
+    #     html_filters.push 'duckdb/clean_html'
+    # end
+
+    # version '0.8' do
+    #     self.release = '0.8.x'
+    #     self.base_url = "https://duckdb.org/docs/archive/#{self.version}/"
+
+    #     html_filters.push 'duckdb/clean_html'
+    # end
+
+    # version '0.7' do
+    #     self.release = '0.7.x'
+    #     self.base_url = "https://duckdb.org/docs/archive/#{self.version}/"
+
+    #     html_filters.push 'duckdb/clean_html'
+    # end
+
+    def get_latest_version(opts)
+      get_github_tags('duckdb', 'duckdb', opts)
+    end
+  end
+end

From 4ea7bb16dabd16dd7bd5a874d127fe1f04c8b313 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 9 Nov 2024 16:39:15 +0000
Subject: [PATCH 042/384] chore(deps): update ruby/setup-ruby action to
 v1.202.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cdaa38cb5a..a23e7a6cda 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@46ca53beb334a2329bcd0e46a694816a6ae6d173 # v1.201.0
+      uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index e858bf97dd..75c174474a 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@46ca53beb334a2329bcd0e46a694816a6ae6d173 # v1.201.0
+      uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 407024c924..f7bcde5334 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@46ca53beb334a2329bcd0e46a694816a6ae6d173 # v1.201.0
+      uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 603f6b94bf08e8789e61773e8cfcbc25bfa4dfac Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 10:51:05 +0100
Subject: [PATCH 043/384] Update Nim documentation (2.2.0)

---
 lib/docs/scrapers/nim.rb | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/lib/docs/scrapers/nim.rb b/lib/docs/scrapers/nim.rb
index a5534877ca..87be40ff8f 100644
--- a/lib/docs/scrapers/nim.rb
+++ b/lib/docs/scrapers/nim.rb
@@ -20,10 +20,6 @@ class Nim < UrlScraper
     version do
       self.release = '2.2.0'
     end
-    
-    version do
-      self.release = '2.0.2'
-    end
 
     version '1' do
       self.release = '1.4.8'

From 050022bfb7bee46e4615fa5ede4bd2194c47f2ba Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 11:09:13 +0100
Subject: [PATCH 044/384] Move docs_aliases to class App

---
 assets/javascripts/app/config.js.erb |  1 +
 assets/javascripts/models/entry.js   | 45 ++++------------------------
 lib/app.rb                           | 36 ++++++++++++++++++++++
 lib/docs/core/manifest.rb            | 10 +------
 4 files changed, 43 insertions(+), 49 deletions(-)

diff --git a/assets/javascripts/app/config.js.erb b/assets/javascripts/app/config.js.erb
index 56ce26522f..04bc8cbaf4 100644
--- a/assets/javascripts/app/config.js.erb
+++ b/assets/javascripts/app/config.js.erb
@@ -1,6 +1,7 @@
 app.config = {
   db_filename: 'db.json',
   default_docs: <%= App.default_docs.to_json %>,
+  docs_aliases: <%= App.docs_aliases.to_json %>,
   docs_origin: '<%= App.docs_origin %>',
   env: '<%= App.environment %>',
   history_cache_size: 10,
diff --git a/assets/javascripts/models/entry.js b/assets/javascripts/models/entry.js
index 79c8134208..98822bc97e 100644
--- a/assets/javascripts/models/entry.js
+++ b/assets/javascripts/models/entry.js
@@ -2,14 +2,15 @@
 
 app.models.Entry = class Entry extends app.Model {
   static applyAliases(string) {
-    if (Entry.ALIASES.hasOwnProperty(string)) {
-      return [string, Entry.ALIASES[string]];
+    const aliases = app.config.docs_aliases;
+    if (aliases.hasOwnProperty(string)) {
+      return [string, aliases[string]];
     } else {
       const words = string.split(".");
       for (let i = 0; i < words.length; i++) {
         var word = words[i];
-        if (Entry.ALIASES.hasOwnProperty(word)) {
-          words[i] = Entry.ALIASES[word];
+        if (aliases.hasOwnProperty(word)) {
+          words[i] = aliases[word];
           return [string, words.join(".")];
         }
       }
@@ -17,43 +18,7 @@ app.models.Entry = class Entry extends app.Model {
     return string;
   }
 
-  static ALIASES = {
-    angular: "ng",
-    "angular.js": "ng",
-    "backbone.js": "bb",
-    "c++": "cpp",
-    coffeescript: "cs",
-    crystal: "cr",
-    elixir: "ex",
-    javascript: "js",
-    julia: "jl",
-    jquery: "$",
-    "knockout.js": "ko",
-    kubernetes: "k8s",
-    less: "ls",
-    lodash: "_",
-    löve: "love",
-    marionette: "mn",
-    markdown: "md",
-    matplotlib: "mpl",
-    modernizr: "mdr",
-    "moment.js": "mt",
-    openjdk: "java",
-    nginx: "ngx",
-    numpy: "np",
-    pandas: "pd",
-    postgresql: "pg",
-    python: "py",
-    "ruby.on.rails": "ror",
-    ruby: "rb",
-    rust: "rs",
-    sass: "scss",
-    tensorflow: "tf",
-    typescript: "ts",
-    "underscore.js": "_",
-  };
   // Attributes: name, type, path
-
   constructor() {
     super(...arguments);
     this.text = Entry.applyAliases(app.Searcher.normalizeString(this.name));
diff --git a/lib/app.rb b/lib/app.rb
index e23b241c06..939eab4778 100644
--- a/lib/app.rb
+++ b/lib/app.rb
@@ -33,6 +33,42 @@ class App < Sinatra::Application
     set :default_docs, %w(css dom html http javascript)
     set :news_path, File.join(root, assets_prefix, 'javascripts', 'news.json')
 
+    set :docs_aliases, {
+      'angular' => 'ng',
+      'angular.js' => 'ng',
+      'backbone.js' => 'bb',
+      'c++' => 'cpp',
+      'coffeescript' => 'cs',
+      'crystal' => 'cr',
+      'elixir' => 'ex',
+      'javascript' => 'js',
+      'julia' => 'jl',
+      'jquery' => '$',
+      'knockout.js' => 'ko',
+      'kubernetes' => 'k8s',
+      'less' => 'ls',
+      'lodash' => '_',
+      'löve' => 'love',
+      'marionette' => 'mn',
+      'markdown' => 'md',
+      'matplotlib' => 'mpl',
+      'modernizr' => 'mdr',
+      'moment.js' => 'mt',
+      'openjdk' => 'java',
+      'nginx' => 'ngx',
+      'numpy' => 'np',
+      'pandas' => 'pd',
+      'postgresql' => 'pg',
+      'python' => 'py',
+      'ruby.on.rails' => 'ror',
+      'ruby' => 'rb',
+      'rust' => 'rs',
+      'sass' => 'scss',
+      'tensorflow' => 'tf',
+      'typescript' => 'ts',
+      'underscore.js' => '_',
+    }
+
     set :csp, false
 
     require 'docs'
diff --git a/lib/docs/core/manifest.rb b/lib/docs/core/manifest.rb
index 2a1f084c49..134bb9e3f2 100644
--- a/lib/docs/core/manifest.rb
+++ b/lib/docs/core/manifest.rb
@@ -20,15 +20,7 @@ def as_json
         if doc.options[:attribution].is_a?(String)
           json[:attribution] = doc.options[:attribution].strip
         end
-
-        # parse doc aliases from JS file as Ruby hash
-        entry_file = File.open("assets/javascripts/models/entry.js")
-        data = entry_file.read
-        aliases = eval data.split("ALIASES = ").last.split(";").first
-
-        # set alias value
-        json["alias"] = aliases[json["slug"].try(:to_sym)]
-
+        json[:alias] = App.docs_aliases[json["slug"].try(:to_sym)]
         result << json
       end
     end

From 63dd3dce7001b30ededaf46c9a84eb2bc9f126e7 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 11:26:12 +0100
Subject: [PATCH 045/384] cordova: do not clean &nbsp;

Do not use core/clean_html filter.
---
 lib/docs/filters/cordova/clean_html_core.rb | 11 +++++++++++
 lib/docs/filters/core/clean_html.rb         |  1 -
 lib/docs/scrapers/cordova.rb                |  2 +-
 3 files changed, 12 insertions(+), 2 deletions(-)
 create mode 100644 lib/docs/filters/cordova/clean_html_core.rb

diff --git a/lib/docs/filters/cordova/clean_html_core.rb b/lib/docs/filters/cordova/clean_html_core.rb
new file mode 100644
index 0000000000..c862548657
--- /dev/null
+++ b/lib/docs/filters/cordova/clean_html_core.rb
@@ -0,0 +1,11 @@
+module Docs
+  class Cordova
+    class CleanHtmlCoreFilter < Filter
+      def call
+        css('script', 'style', 'link').remove
+        xpath('descendant::comment()').remove
+        doc
+      end
+    end
+  end
+end
diff --git a/lib/docs/filters/core/clean_html.rb b/lib/docs/filters/core/clean_html.rb
index c8a7cfc11e..f17333c011 100644
--- a/lib/docs/filters/core/clean_html.rb
+++ b/lib/docs/filters/core/clean_html.rb
@@ -8,7 +8,6 @@ def call
       xpath('./text()', './/text()[not(ancestor::pre) and not(ancestor::code) and not(ancestor::div[contains(concat(" ", normalize-space(@class), " "), " prism ")])]').each do |node|
         content = node.content
         next unless content.valid_encoding?
-        next if context[:clean_html_maintain_nbsp] && !content.index(" ").nil?
         content.gsub! %r{[[:space:]]+}, ' '
         node.content = content
       end
diff --git a/lib/docs/scrapers/cordova.rb b/lib/docs/scrapers/cordova.rb
index 0ef045712e..5cf0bf90fd 100644
--- a/lib/docs/scrapers/cordova.rb
+++ b/lib/docs/scrapers/cordova.rb
@@ -8,10 +8,10 @@ class Cordova < UrlScraper
       code: 'https://github.com/apache/cordova'
     }
 
+    html_filters.replace 'clean_html', 'cordova/clean_html_core'
     html_filters.push 'cordova/entries', 'cordova/clean_html'
 
     options[:container] = '.docs'
-    options[:clean_html_maintain_nbsp] = true
     options[:skip] = %w(index.html)
 
     options[:fix_urls] = ->(url) do

From 9967bef8db3a083a094ed8630d4d856070b5b3d3 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 11:30:48 +0100
Subject: [PATCH 046/384] Fix manifest_test.rb

---
 test/lib/docs/core/manifest_test.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/lib/docs/core/manifest_test.rb b/test/lib/docs/core/manifest_test.rb
index 42c053af94..60d5ba90e3 100644
--- a/test/lib/docs/core/manifest_test.rb
+++ b/test/lib/docs/core/manifest_test.rb
@@ -64,7 +64,7 @@ class ManifestTest < Minitest::Spec
       it "includes the doc's meta representation" do
         json = manifest.as_json
         assert_equal 1, json.length
-        assert_equal "{\"name\"=>\"Test\", \"db_size\"=>776533, :attribution=>\"foo\", \"alias\"=>nil}", json[0].to_s
+        assert_equal "{\"name\"=>\"Test\", \"db_size\"=>776533, :attribution=>\"foo\", :alias=>nil}", json[0].to_s
       end
     end
 

From 83c4a189c1148be4a616c8cdbd8e3b6caad55a5e Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 11:46:23 +0100
Subject: [PATCH 047/384] Update React Native documentation (0.75)

---
 lib/docs/filters/react_native/entries.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/filters/react_native/entries.rb b/lib/docs/filters/react_native/entries.rb
index a3a9c79317..29960adf31 100644
--- a/lib/docs/filters/react_native/entries.rb
+++ b/lib/docs/filters/react_native/entries.rb
@@ -6,7 +6,7 @@ def get_name
       end
 
       def get_type
-        type = at_css('.navbar__link--active')
+        type = at_css('.menu__link--active')
         return 'Miscellaneous' unless type
         type.content.strip
       end

From 5e02d779a14ca028132cdcd8299acc6c8ad21cea Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 12:08:31 +0100
Subject: [PATCH 048/384] Fix Docs.aliases

---
 lib/app.rb                | 37 +------------------------------------
 lib/docs.rb               | 38 ++++++++++++++++++++++++++++++++++++++
 lib/docs/core/manifest.rb |  2 +-
 3 files changed, 40 insertions(+), 37 deletions(-)

diff --git a/lib/app.rb b/lib/app.rb
index 939eab4778..89fe6cf0a3 100644
--- a/lib/app.rb
+++ b/lib/app.rb
@@ -33,46 +33,11 @@ class App < Sinatra::Application
     set :default_docs, %w(css dom html http javascript)
     set :news_path, File.join(root, assets_prefix, 'javascripts', 'news.json')
 
-    set :docs_aliases, {
-      'angular' => 'ng',
-      'angular.js' => 'ng',
-      'backbone.js' => 'bb',
-      'c++' => 'cpp',
-      'coffeescript' => 'cs',
-      'crystal' => 'cr',
-      'elixir' => 'ex',
-      'javascript' => 'js',
-      'julia' => 'jl',
-      'jquery' => '$',
-      'knockout.js' => 'ko',
-      'kubernetes' => 'k8s',
-      'less' => 'ls',
-      'lodash' => '_',
-      'löve' => 'love',
-      'marionette' => 'mn',
-      'markdown' => 'md',
-      'matplotlib' => 'mpl',
-      'modernizr' => 'mdr',
-      'moment.js' => 'mt',
-      'openjdk' => 'java',
-      'nginx' => 'ngx',
-      'numpy' => 'np',
-      'pandas' => 'pd',
-      'postgresql' => 'pg',
-      'python' => 'py',
-      'ruby.on.rails' => 'ror',
-      'ruby' => 'rb',
-      'rust' => 'rs',
-      'sass' => 'scss',
-      'tensorflow' => 'tf',
-      'typescript' => 'ts',
-      'underscore.js' => '_',
-    }
-
     set :csp, false
 
     require 'docs'
     Docs.generate_manifest
+    set :docs_aliases, Docs.aliases
 
     Dir[docs_path, root.join(assets_prefix, '*/')].each do |path|
       sprockets.append_path(path)
diff --git a/lib/docs.rb b/lib/docs.rb
index abea091572..f8ab6a039f 100644
--- a/lib/docs.rb
+++ b/lib/docs.rb
@@ -108,6 +108,44 @@ def self.store
     store_class.new(store_path)
   end
 
+  def self.aliases
+    {
+      'angular' => 'ng',
+      'angular.js' => 'ng',
+      'backbone.js' => 'bb',
+      'c++' => 'cpp',
+      'coffeescript' => 'cs',
+      'crystal' => 'cr',
+      'elixir' => 'ex',
+      'javascript' => 'js',
+      'julia' => 'jl',
+      'jquery' => '$',
+      'knockout.js' => 'ko',
+      'kubernetes' => 'k8s',
+      'less' => 'ls',
+      'lodash' => '_',
+      'löve' => 'love',
+      'marionette' => 'mn',
+      'markdown' => 'md',
+      'matplotlib' => 'mpl',
+      'modernizr' => 'mdr',
+      'moment.js' => 'mt',
+      'openjdk' => 'java',
+      'nginx' => 'ngx',
+      'numpy' => 'np',
+      'pandas' => 'pd',
+      'postgresql' => 'pg',
+      'python' => 'py',
+      'ruby.on.rails' => 'ror',
+      'ruby' => 'rb',
+      'rust' => 'rs',
+      'sass' => 'scss',
+      'tensorflow' => 'tf',
+      'typescript' => 'ts',
+      'underscore.js' => '_',
+    }
+  end
+
   extend Instrumentable
 
   def self.install_report(*names)
diff --git a/lib/docs/core/manifest.rb b/lib/docs/core/manifest.rb
index 134bb9e3f2..b9744ca218 100644
--- a/lib/docs/core/manifest.rb
+++ b/lib/docs/core/manifest.rb
@@ -20,7 +20,7 @@ def as_json
         if doc.options[:attribution].is_a?(String)
           json[:attribution] = doc.options[:attribution].strip
         end
-        json[:alias] = App.docs_aliases[json["slug"].try(:to_sym)]
+        json[:alias] = Docs.aliases[json["slug"].try(:to_sym)]
         result << json
       end
     end

From 215cf3bb673adb149baa0634cad37b166fab2a7d Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 12:26:27 +0100
Subject: [PATCH 049/384] Update CSS documentation

---
 lib/docs/filters/mdn/clean_html.rb              |   2 ++
 lib/docs/scrapers/mdn/css.rb                    |   2 +-
 public/icons/docs/css/16.png                    | Bin 579 -> 621 bytes
 public/icons/docs/css/16@2x.png                 | Bin 969 -> 980 bytes
 public/icons/docs/css/CSS3.sketch/Data          | Bin 69815 -> 0 bytes
 .../docs/css/CSS3.sketch/QuickLook/Preview.png  | Bin 11942 -> 0 bytes
 .../css/CSS3.sketch/QuickLook/Thumbnail.png     | Bin 54726 -> 0 bytes
 public/icons/docs/css/CSS3.sketch/fonts         |   0
 public/icons/docs/css/CSS3.sketch/version       |   1 -
 public/icons/docs/css/SOURCE                    |   2 ++
 10 files changed, 5 insertions(+), 2 deletions(-)
 delete mode 100644 public/icons/docs/css/CSS3.sketch/Data
 delete mode 100644 public/icons/docs/css/CSS3.sketch/QuickLook/Preview.png
 delete mode 100644 public/icons/docs/css/CSS3.sketch/QuickLook/Thumbnail.png
 delete mode 100644 public/icons/docs/css/CSS3.sketch/fonts
 delete mode 100644 public/icons/docs/css/CSS3.sketch/version
 create mode 100644 public/icons/docs/css/SOURCE

diff --git a/lib/docs/filters/mdn/clean_html.rb b/lib/docs/filters/mdn/clean_html.rb
index 91250a43a9..2c6aded972 100644
--- a/lib/docs/filters/mdn/clean_html.rb
+++ b/lib/docs/filters/mdn/clean_html.rb
@@ -72,6 +72,8 @@ def call
           node.remove_attribute('class')
         end
 
+        css('.example-header').remove
+
         css('table').each do |node|
           node.before %(<div class="_table"></div>)
           node.previous_element << node
diff --git a/lib/docs/scrapers/mdn/css.rb b/lib/docs/scrapers/mdn/css.rb
index ca378f2f7b..42ace85097 100644
--- a/lib/docs/scrapers/mdn/css.rb
+++ b/lib/docs/scrapers/mdn/css.rb
@@ -1,6 +1,6 @@
 module Docs
   class Css < Mdn
-    # release = '2024-08-20'
+    # release = '2024-11-17'
     self.name = 'CSS'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/CSS'
     self.root_path = '/Reference'
diff --git a/public/icons/docs/css/16.png b/public/icons/docs/css/16.png
index 538ddb0f0061a2683732d023bed5ff27b1d37332..bfed62bda5816940c32bc092406b0e1e1d3dd92e 100644
GIT binary patch
diff --git a/public/icons/docs/css/16@2x.png b/public/icons/docs/css/16@2x.png
index f06ea2d47918e08a8567d48fc428673c543473de..649420bc84c54d0f4c868e0870351188164346b9 100644
GIT binary patch
diff --git a/public/icons/docs/css/CSS3.sketch/Data b/public/icons/docs/css/CSS3.sketch/Data
deleted file mode 100644
index ca0a9d404aa8b812ff15bfeb7321d427cb199072..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/public/icons/docs/css/CSS3.sketch/QuickLook/Preview.png b/public/icons/docs/css/CSS3.sketch/QuickLook/Preview.png
deleted file mode 100644
index a5b48eef94e14836c1b441e846f37ffb57d95576..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/public/icons/docs/css/CSS3.sketch/QuickLook/Thumbnail.png b/public/icons/docs/css/CSS3.sketch/QuickLook/Thumbnail.png
deleted file mode 100644
index 262ae52804d788365fd34c309f53bc2a89aed278..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/public/icons/docs/css/CSS3.sketch/fonts b/public/icons/docs/css/CSS3.sketch/fonts
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/public/icons/docs/css/CSS3.sketch/version b/public/icons/docs/css/CSS3.sketch/version
deleted file mode 100644
index 9a037142aa..0000000000
--- a/public/icons/docs/css/CSS3.sketch/version
+++ /dev/null
@@ -1 +0,0 @@
-10
\ No newline at end of file
diff --git a/public/icons/docs/css/SOURCE b/public/icons/docs/css/SOURCE
new file mode 100644
index 0000000000..3f8a14e0b2
--- /dev/null
+++ b/public/icons/docs/css/SOURCE
@@ -0,0 +1,2 @@
+https://github.com/CSS-Next/logo.css
+https://commons.wikimedia.org/wiki/File:Official_CSS_Logo.svg

From f814260ff3e26e1e11c8c6fe2eba50d251ec1fc0 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 12:39:22 +0100
Subject: [PATCH 050/384] Update PostgreSQL documentation (17.1)

---
 lib/docs/scrapers/postgresql.rb | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/postgresql.rb b/lib/docs/scrapers/postgresql.rb
index 5ec615d312..e54cc8a513 100644
--- a/lib/docs/scrapers/postgresql.rb
+++ b/lib/docs/scrapers/postgresql.rb
@@ -51,10 +51,15 @@ class Postgresql < UrlScraper
       /\Aunsupported-features/ ]
 
     options[:attribution] = <<-HTML
-      &copy; 1996&ndash;2023 The PostgreSQL Global Development Group<br>
+      &copy; 1996&ndash;2024 The PostgreSQL Global Development Group<br>
       Licensed under the PostgreSQL License.
     HTML
 
+    version '17' do
+      self.release = '17.1'
+      self.base_url = "https://www.postgresql.org/docs/#{version}/"
+    end
+
     version '16' do
       self.release = '16.1'
       self.base_url = "https://www.postgresql.org/docs/#{version}/"

From 12e17eb69bed9c6c06f781f7638cc1b838276a42 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 12:41:11 +0100
Subject: [PATCH 051/384] Update Kubectl documentation (1.31.2)

---
 lib/docs/scrapers/kubectl.rb | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/docs/scrapers/kubectl.rb b/lib/docs/scrapers/kubectl.rb
index 42cff8c754..732b5211f1 100644
--- a/lib/docs/scrapers/kubectl.rb
+++ b/lib/docs/scrapers/kubectl.rb
@@ -14,13 +14,13 @@ class Kubectl < UrlScraper
     options[:container] = '#page-content-wrapper'
 
     options[:attribution] = <<-HTML
-      &copy; 2022 The Kubernetes Authors | Documentation Distributed under CC BY 4.0 <br>
-      Copyright &copy; 2022 The Linux Foundation ®. All rights reserved.
+      &copy; 2024 The Kubernetes Authors | Documentation Distributed under CC BY 4.0 <br>
+      Copyright &copy; 2024 The Linux Foundation ®. All rights reserved.
     HTML
 
     # latest version has a special URL that does not include the version identifier 
     version do
-      self.release = "1.26"
+      self.release = "1.31.2"
       self.base_url = "https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands"
     end
 

From aadbece80a9235ab7e3ac615dc3def72505c88ab Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 12:42:14 +0100
Subject: [PATCH 052/384] Update Kubernetes documentation (1.31.2)

---
 lib/docs/scrapers/kubernetes.rb | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/docs/scrapers/kubernetes.rb b/lib/docs/scrapers/kubernetes.rb
index 22149d066c..39cefac7cb 100644
--- a/lib/docs/scrapers/kubernetes.rb
+++ b/lib/docs/scrapers/kubernetes.rb
@@ -14,13 +14,13 @@ class Kubernetes < UrlScraper
     options[:container] = '.td-content'
 
     options[:attribution] = <<-HTML
-      &copy; 2022 The Kubernetes Authors | Documentation Distributed under CC BY 4.0 <br>
-      Copyright &copy; 2022 The Linux Foundation ®. All rights reserved.
+      &copy; 2024 The Kubernetes Authors | Documentation Distributed under CC BY 4.0 <br>
+      Copyright &copy; 2024 The Linux Foundation ®. All rights reserved.
     HTML
 
     # latest version has a special URL that does not include the version identifier 
     version do
-      self.release = "1.29"
+      self.release = "1.31.2"
       self.base_url = "https://kubernetes.io/docs/reference/kubernetes-api/"
     end
 

From fec3516c7ce594a65e86ba60bcdf811357ab62db Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 12:44:44 +0100
Subject: [PATCH 053/384] Update Axios documentation (1.7.7)

---
 lib/docs/scrapers/axios.rb | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/axios.rb b/lib/docs/scrapers/axios.rb
index 0a78e940a5..6265a9c376 100755
--- a/lib/docs/scrapers/axios.rb
+++ b/lib/docs/scrapers/axios.rb
@@ -5,9 +5,10 @@ class Axios < UrlScraper
       home: 'hthttps://axios-http.com/',
       code: 'https://github.com/axios/axios'
     }
-    self.release = '1.6.5'
+    self.release = '1.7.7'
     self.base_url = "https://axios-http.com/docs/"
     self.initial_paths = %w(index intro)
+    options[:skip] = %w(sponsor)
 
     html_filters.push 'axios/entries', 'axios/clean_html'
 

From d04de6fc533408d9e2ab87adbdf861bacf4b2dca Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 13:24:33 +0100
Subject: [PATCH 054/384] Update SQLite documentation (3.47.0)

---
 lib/docs/scrapers/sqlite.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/sqlite.rb b/lib/docs/scrapers/sqlite.rb
index 9a7ed3762a..a9529e9804 100644
--- a/lib/docs/scrapers/sqlite.rb
+++ b/lib/docs/scrapers/sqlite.rb
@@ -2,7 +2,7 @@ module Docs
   class Sqlite < UrlScraper
     self.name = 'SQLite'
     self.type = 'sqlite'
-    self.release = '3.45.1'
+    self.release = '3.47.0'
     self.base_url = 'https://sqlite.org/'
     self.root_path = 'docs.html'
     self.initial_paths = %w(keyword_index.html)

From 0619b8cb97b5adbfd603b8ebe215ac63340e2cea Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 13:26:29 +0100
Subject: [PATCH 055/384] Update TypeScript documentation (5.6.3)

---
 lib/docs/scrapers/typescript.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/typescript.rb b/lib/docs/scrapers/typescript.rb
index 68452591f1..34003a1626 100644
--- a/lib/docs/scrapers/typescript.rb
+++ b/lib/docs/scrapers/typescript.rb
@@ -45,7 +45,7 @@ def initial_urls
     HTML
 
     version do
-      self.release = '5.5.4'
+      self.release = '5.6.3'
       self.base_urls = [
         'https://www.typescriptlang.org/docs/handbook/',
         'https://www.typescriptlang.org/'

From 6ccf04a8d6aca1e3d4c8d8165b397b331c13073a Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 13:41:00 +0100
Subject: [PATCH 056/384] Update R documentation (4.4.2)

---
 docs/file-scrapers.md            | 9 ++++++++-
 lib/docs/filters/r/clean_html.rb | 4 ++--
 lib/docs/scrapers/r.rb           | 2 +-
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index a15d38adc0..3078e176f3 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -233,7 +233,14 @@ tar xj --strip-components=1
 ```
 
 ## R
+
 ```bash
+sudo dnf install bzip2-devel
+sudo dnf install gcc-gfortran
+sudo dnf install libcurl-devel
+sudo dnf install texinfo
+sudo dnf install xz-devel
+
 DEVDOCSROOT=docs/r
 RLATEST=https://cran.r-project.org/src/base/R-latest.tar.gz # or /R-${VERSION::1}/R-$VERSION.tar.gz
 
@@ -243,7 +250,7 @@ mkdir -p "$RSOURCEDIR" "$RBUILDDIR" "$DEVDOCSROOT"
 
 # Download, configure, and build with static HTML pages
 curl "$RLATEST" | tar -C "$RSOURCEDIR" -xzf - --strip-components=1
-(cd "$RBUILDDIR" && "$RSOURCEDIR/configure" --enable-prebuilt-html --with-recommended-packages --disable-byte-compiled-packages --disable-shared --disable-java)
+(cd "$RBUILDDIR" && "$RSOURCEDIR/configure" --enable-prebuilt-html --with-recommended-packages --disable-byte-compiled-packages --disable-shared --disable-java --with-readline=no --with-x=no)
 make _R_HELP_LINKS_TO_TOPICS_=FALSE -C "$RBUILDDIR"
 
 # Export all html documentation built − global, and per-package
diff --git a/lib/docs/filters/r/clean_html.rb b/lib/docs/filters/r/clean_html.rb
index 8d7b0e2082..c89812e6be 100644
--- a/lib/docs/filters/r/clean_html.rb
+++ b/lib/docs/filters/r/clean_html.rb
@@ -13,8 +13,8 @@ def call
           title = at_css('h2')
           title.inner_html = "<code>#{slug_parts[3]}</code> #{title.content}"
 
-          summary = at_css('table[summary]')
-          summary.remove if summary
+          css('table:contains("R Documentation")').remove
+          css('table[summary]').remove
 
           css('hr ~ *, hr').remove
 
diff --git a/lib/docs/scrapers/r.rb b/lib/docs/scrapers/r.rb
index 28a97c2c90..db08169cb9 100644
--- a/lib/docs/scrapers/r.rb
+++ b/lib/docs/scrapers/r.rb
@@ -3,7 +3,7 @@ class R < FileScraper
     self.name = 'R'
     self.slug = 'r'
     self.type = 'simple'
-    self.release = '4.1.0'
+    self.release = '4.4.2'
     self.links = {
       home: 'https://www.r-project.org/',
       code: 'https://svn.r-project.org/R/'

From 2b8d9b6c338befe97487cd2c4d470bae36a71094 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 14:13:11 +0100
Subject: [PATCH 057/384] Update OCaml documentation (5.2)

---
 docs/file-scrapers.md                | 11 -----------
 lib/docs/filters/ocaml/clean_html.rb |  2 ++
 lib/docs/scrapers/ocaml.rb           | 13 +++++++++----
 3 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index 3078e176f3..2f8fd8f38e 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -157,17 +157,6 @@ curl https://numpy.org/doc/$VERSION/numpy-html.zip | \
 bsdtar --extract --file=- --directory=docs/numpy~$VERSION/
 ```
 
-## OCaml
-
-Download from https://www.ocaml.org/docs/ the HTML reference:
-https://v2.ocaml.org/releases/4.14/ocaml-4.14-refman-html.tar.gz
-and extract it as `docs/ocaml`:
-
-```sh
-curl https://v2.ocaml.org/releases/$VERSION/ocaml-$VERSION-refman-html.tar.gz | \
-tar xz --transform 's/htmlman/ocaml/' --directory docs/
-```
-
 ## OpenGL
 
 ```sh
diff --git a/lib/docs/filters/ocaml/clean_html.rb b/lib/docs/filters/ocaml/clean_html.rb
index 70bac84545..83bb86a0b1 100644
--- a/lib/docs/filters/ocaml/clean_html.rb
+++ b/lib/docs/filters/ocaml/clean_html.rb
@@ -3,6 +3,8 @@ class Ocaml
     class CleanHtmlFilter < Filter
       def call
 
+        css('#sidebar').remove
+
         css('pre').each do |node|
           span = node.at_css('span[id]')
           node['id'] = span['id'] if span
diff --git a/lib/docs/scrapers/ocaml.rb b/lib/docs/scrapers/ocaml.rb
index c26572ac22..4718546fbb 100644
--- a/lib/docs/scrapers/ocaml.rb
+++ b/lib/docs/scrapers/ocaml.rb
@@ -1,5 +1,5 @@
 module Docs
-  class Ocaml < FileScraper
+  class Ocaml < UrlScraper
     self.name = 'OCaml'
     self.type = 'ocaml'
     self.root_path = 'index.html'
@@ -16,15 +16,20 @@ class Ocaml < FileScraper
 
     options[:skip_patterns] = [
       /\Acompilerlibref\//,
-      /\Alibref\/type_/,
-      /\Alibref\/Stdlib\.\w+\.html/,
+      /\Aapi\/type_/,
+      /\Aapi\/Stdlib\.\w+\.html/,
     ]
 
     options[:attribution] = <<-HTML
-      &copy; 1995-2022 INRIA.
+      &copy; 1995-2024 INRIA.
     HTML
 
     version '' do
+      self.release = '5.2'
+      self.base_url = "https://ocaml.org/manual/#{self.release}/"
+    end
+
+    version '5.0' do
       self.release = '5.0'
       self.base_url = "https://v2.ocaml.org/releases/#{self.release}/htmlman/"
     end

From 5d8d12c133b7d456c364252dc3112bc49515f57c Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 14:26:04 +0100
Subject: [PATCH 058/384] Fix Docs.aliases

---
 lib/docs.rb               | 2 +-
 lib/docs/core/manifest.rb | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/docs.rb b/lib/docs.rb
index f8ab6a039f..6607bc6ddb 100644
--- a/lib/docs.rb
+++ b/lib/docs.rb
@@ -101,7 +101,7 @@ def self.generate(doc, version = nil)
   end
 
   def self.generate_manifest
-    Manifest.new(store, all_versions).store
+    Manifest.new(store, all_versions, aliases).store
   end
 
   def self.store
diff --git a/lib/docs/core/manifest.rb b/lib/docs/core/manifest.rb
index b9744ca218..7d90e1f820 100644
--- a/lib/docs/core/manifest.rb
+++ b/lib/docs/core/manifest.rb
@@ -4,9 +4,10 @@ module Docs
   class Manifest
     FILENAME = 'docs.json'
 
-    def initialize(store, docs)
+    def initialize(store, docs, aliases)
       @store = store
       @docs = docs
+      @aliases = aliases
     end
 
     def store
@@ -20,7 +21,7 @@ def as_json
         if doc.options[:attribution].is_a?(String)
           json[:attribution] = doc.options[:attribution].strip
         end
-        json[:alias] = Docs.aliases[json["slug"].try(:to_sym)]
+        json[:alias] = @aliases[doc.slug]
         result << json
       end
     end

From a4a2ab4a3304ad79743644b23ed8858c1c7f7146 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 14:31:15 +0100
Subject: [PATCH 059/384] Fix Docs.aliases

---
 lib/docs.rb               | 2 +-
 lib/docs/core/manifest.rb | 5 ++---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/lib/docs.rb b/lib/docs.rb
index 6607bc6ddb..f8ab6a039f 100644
--- a/lib/docs.rb
+++ b/lib/docs.rb
@@ -101,7 +101,7 @@ def self.generate(doc, version = nil)
   end
 
   def self.generate_manifest
-    Manifest.new(store, all_versions, aliases).store
+    Manifest.new(store, all_versions).store
   end
 
   def self.store
diff --git a/lib/docs/core/manifest.rb b/lib/docs/core/manifest.rb
index 7d90e1f820..ac3162ca09 100644
--- a/lib/docs/core/manifest.rb
+++ b/lib/docs/core/manifest.rb
@@ -4,10 +4,9 @@ module Docs
   class Manifest
     FILENAME = 'docs.json'
 
-    def initialize(store, docs, aliases)
+    def initialize(store, docs)
       @store = store
       @docs = docs
-      @aliases = aliases
     end
 
     def store
@@ -21,7 +20,7 @@ def as_json
         if doc.options[:attribution].is_a?(String)
           json[:attribution] = doc.options[:attribution].strip
         end
-        json[:alias] = @aliases[doc.slug]
+        json[:alias] = Docs.aliases[doc.slug]
         result << json
       end
     end

From 2c4c474bce51097856a22fceb6f9f0b8c8e234aa Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 15:54:52 +0100
Subject: [PATCH 060/384] Update Vue documentation (3.5.13)

---
 lib/docs/scrapers/vue.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vue.rb b/lib/docs/scrapers/vue.rb
index ed07bbc880..b0649eb31f 100644
--- a/lib/docs/scrapers/vue.rb
+++ b/lib/docs/scrapers/vue.rb
@@ -19,7 +19,7 @@ class Vue < UrlScraper
     HTML
 
     version '3' do
-      self.release = '3.5.2'
+      self.release = '3.5.13'
       self.base_url = 'https://vuejs.org/'
       self.initial_paths = %w(guide/introduction.html)
       html_filters.push 'vue/entries_v3', 'vue/clean_html'

From 553240c4f04623403ac1b62a7ba72e44c193b578 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 16:03:11 +0100
Subject: [PATCH 061/384] Update Vite documentation (5.4.11)

---
 lib/docs/filters/vite/clean_html.rb |  1 +
 lib/docs/scrapers/vite.rb           | 14 +++++++-------
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/lib/docs/filters/vite/clean_html.rb b/lib/docs/filters/vite/clean_html.rb
index 5e213236b2..c19745ca3e 100644
--- a/lib/docs/filters/vite/clean_html.rb
+++ b/lib/docs/filters/vite/clean_html.rb
@@ -24,6 +24,7 @@ def call
           node.remove
         end
 
+        css('.lang').remove
         css('.line-numbers-wrapper').remove
         css('pre').each do |node|
           node.content = node.content.strip
diff --git a/lib/docs/scrapers/vite.rb b/lib/docs/scrapers/vite.rb
index e63b1454ab..e6ed520327 100644
--- a/lib/docs/scrapers/vite.rb
+++ b/lib/docs/scrapers/vite.rb
@@ -4,7 +4,7 @@ class Vite < UrlScraper
     self.slug = 'vite'
     self.type = 'simple'
     self.links = {
-      home: 'https://vitejs.dev/',
+      home: 'https://vite.dev/',
       code: 'https://github.com/vitejs/vite'
     }
 
@@ -22,18 +22,18 @@ class Vite < UrlScraper
     html_filters.push 'vite/entries', 'vite/clean_html'
 
     version do
-      self.release = '5.2.13'
-      self.base_url = 'https://vitejs.dev/'
+      self.release = '5.4.11'
+      self.base_url = 'https://vite.dev/'
     end
 
     version '4' do
-      self.release = '4.5.1'
-      self.base_url = 'https://v4.vitejs.dev/'
+      self.release = '4.5.5'
+      self.base_url = 'https://v4.vite.dev/'
     end
 
     version '3' do
-      self.release = '3.2.5'
-      self.base_url = 'https://v3.vitejs.dev/'
+      self.release = '3.2.11'
+      self.base_url = 'https://v3.vite.dev/'
     end
 
     def get_latest_version(opts)

From 7c5132afecf42b916aa6b0c9aba03e7da21e2464 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Mon, 18 Nov 2024 08:06:35 +0100
Subject: [PATCH 062/384] Separate React 17

---
 lib/docs/scrapers/react.rb | 47 ++++++++++++++++++++------------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/lib/docs/scrapers/react.rb b/lib/docs/scrapers/react.rb
index eeececf621..7ef60cc19b 100644
--- a/lib/docs/scrapers/react.rb
+++ b/lib/docs/scrapers/react.rb
@@ -2,37 +2,40 @@ module Docs
   class React < UrlScraper
     self.name = 'React'
     self.type = 'simple'
-    self.release = '18.2.0'
-    self.base_url = 'https://reactjs.org/docs/'
-    self.root_path = 'hello-world.html'
     self.links = {
-      home: 'https://reactjs.org/',
+      home: 'https://react.dev/',
       code: 'https://github.com/facebook/react'
     }
 
-    html_filters.push 'react/entries', 'react/clean_html'
+    version '17' do
+      self.release = '17.0.2'
+      self.base_url = 'https://17.reactjs.org/docs/'
+      self.root_path = 'hello-world.html'
+      html_filters.push 'react/entries', 'react/clean_html'
 
-    options[:skip] = %w(
-      codebase-overview.html
-      design-principles.html
-      how-to-contribute.html
-      implementation-notes.html
-    )
+      options[:skip] = %w(
+        codebase-overview.html
+        design-principles.html
+        how-to-contribute.html
+        implementation-notes.html
+      )
 
-    options[:replace_paths] = {
-      'more-about-refs.html' => 'refs-and-the-dom.html',
-      'interactivity-and-dynamic-uis.html' => 'state-and-lifecycle.html',
-      'working-with-the-browser.html' => 'refs-and-the-dom.html',
-      'top-level-api.html' => 'react-api.html',
-    }
+      options[:replace_paths] = {
+        'more-about-refs.html' => 'refs-and-the-dom.html',
+        'interactivity-and-dynamic-uis.html' => 'state-and-lifecycle.html',
+        'working-with-the-browser.html' => 'refs-and-the-dom.html',
+        'top-level-api.html' => 'react-api.html',
+      }
+
+      options[:attribution] = <<-HTML
+        &copy; 2013&ndash;present Facebook Inc.<br>
+        Licensed under the Creative Commons Attribution 4.0 International Public License.
+      HTML
+    end
 
-    options[:attribution] = <<-HTML
-      &copy; 2013&ndash;present Facebook Inc.<br>
-      Licensed under the Creative Commons Attribution 4.0 International Public License.
-    HTML
 
     def get_latest_version(opts)
-      doc = fetch_doc('https://reactjs.org/docs/getting-started.html', opts)
+      doc = fetch_doc('https://react.dev/', opts)
       doc.at_css('a[href="/versions"]').content.strip[1..-1]
     end
   end

From a5af2487ec1298fa3ed14167d9df9e60e3b3e108 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Mon, 18 Nov 2024 18:00:04 +0100
Subject: [PATCH 063/384] Update JavaScript documentation

---
 lib/docs/scrapers/mdn/javascript.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/mdn/javascript.rb b/lib/docs/scrapers/mdn/javascript.rb
index 48b0d1cd1e..e6aabdb1a9 100644
--- a/lib/docs/scrapers/mdn/javascript.rb
+++ b/lib/docs/scrapers/mdn/javascript.rb
@@ -3,7 +3,7 @@ class Javascript < Mdn
     prepend FixInternalUrlsBehavior
     prepend FixRedirectionsBehavior
 
-    # release = '2024-08-20'
+    # release = '2024-11-18'
     self.name = 'JavaScript'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference'
     self.links = {

From 2a5bbe8bb9c9cba026910208be472750be32e5cd Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 17:02:38 +0000
Subject: [PATCH 064/384] Bump rexml from 3.2.9 to 3.3.9

Bumps [rexml](https://github.com/ruby/rexml) from 3.2.9 to 3.3.9.
- [Release notes](https://github.com/ruby/rexml/releases)
- [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md)
- [Commits](https://github.com/ruby/rexml/compare/v3.2.9...v3.3.9)

---
updated-dependencies:
- dependency-name: rexml
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
---
 Gemfile.lock | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 0ee3e99ac8..6116289690 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -88,8 +88,7 @@ GEM
     rb-inotify (0.10.1)
       ffi (~> 1.0)
     redcarpet (3.6.0)
-    rexml (3.2.9)
-      strscan
+    rexml (3.3.9)
     rouge (1.11.1)
     rr (3.1.1)
     rss (0.3.1)
@@ -125,7 +124,6 @@ GEM
       unicode-display_width (>= 1.5, < 3.0)
       unicode_utils (~> 1.4)
     strings-ansi (0.2.0)
-    strscan (1.0.3)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
     terser (1.2.4)

From 7e8c19d2c7b3502376173fc110f9130a59ac265a Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Mon, 18 Nov 2024 18:44:23 +0100
Subject: [PATCH 065/384] Update WordPress documentation (6.7)

---
 lib/docs/filters/wordpress/clean_html.rb | 32 +++++++++++++++++-------
 lib/docs/filters/wordpress/entries.rb    |  6 +++--
 lib/docs/scrapers/wordpress.rb           |  6 ++---
 3 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/lib/docs/filters/wordpress/clean_html.rb b/lib/docs/filters/wordpress/clean_html.rb
index a7aeb47252..fba2c4c360 100644
--- a/lib/docs/filters/wordpress/clean_html.rb
+++ b/lib/docs/filters/wordpress/clean_html.rb
@@ -8,15 +8,29 @@ def call
         end
 
         article = at_css('article[id^="post-"]')
-        @doc = at_css('article[id^="post-"]') unless article.nil?
-
-        css('hr', '.screen-reader-text', '.table-of-contents',
-            '.anchor', '.toc-jump', '.source-code-links', '.user-notes',
-            '.show-more', '.hide-more').remove
-
-        header = at_css('h1')
-        header.content = header.content.strip
-        doc.prepend_child header
+        @doc = article unless article.nil?
+
+        css(
+          'hr',
+          '.screen-reader-text',
+          '.table-of-contents',
+          '.anchor',
+          '.toc-jump',
+          '.source-code-links',
+          '.user-notes',
+          '.show-more',
+          '.hide-more',
+          '.wp-block-wporg-sidebar-container',
+          'section[data-nosnippet="true"]',
+          # 'section:contains("before being able to contribute a note or feedback")',
+          ).remove
+
+        if at_css('.entry-content')
+          header = at_css('h1')
+          header.remove_attribute('style')
+          @doc = at_css('.entry-content')
+          doc.prepend_child header
+        end
 
         # Remove permalink
         css('h2 > a, h3 > a').each do |node|
diff --git a/lib/docs/filters/wordpress/entries.rb b/lib/docs/filters/wordpress/entries.rb
index ba539d6793..8acca62ad3 100644
--- a/lib/docs/filters/wordpress/entries.rb
+++ b/lib/docs/filters/wordpress/entries.rb
@@ -2,11 +2,13 @@ module Docs
   class Wordpress
     class EntriesFilter < Docs::EntriesFilter
       def get_name
-        at_css('.breadcrumbs .trail-end').content
+        at_css('h1').content
       end
 
       def get_type
-        if subpath.starts_with?('classes')
+        if subpath.starts_with?('classes') and subpath.count('/') == 3
+          'Methods'
+        elsif subpath.starts_with?('classes')
           'Classes'
         elsif subpath.starts_with?('hooks')
           'Hooks'
diff --git a/lib/docs/scrapers/wordpress.rb b/lib/docs/scrapers/wordpress.rb
index b15a4fd0e4..beb23ceeee 100644
--- a/lib/docs/scrapers/wordpress.rb
+++ b/lib/docs/scrapers/wordpress.rb
@@ -2,7 +2,7 @@ module Docs
   class Wordpress < UrlScraper
     self.name = 'WordPress'
     self.type = 'wordpress'
-    self.release = '6.1'
+    self.release = '6.7'
     self.base_url = 'https://developer.wordpress.org/reference/'
     self.initial_paths = %w(
       functions/
@@ -17,7 +17,7 @@ class Wordpress < UrlScraper
 
     html_filters.push 'wordpress/entries', 'wordpress/clean_html'
 
-    options[:container] = '#content-area'
+    options[:container] = 'main'
     options[:trailing_slash] = false
     options[:only_patterns] = [
       /\Afunctions\//,
@@ -32,7 +32,7 @@ class Wordpress < UrlScraper
     ]
 
     options[:attribution] = <<-HTML
-      &copy; 2003&ndash;2022 WordPress Foundation<br>
+      &copy; 2003&ndash;2024 WordPress Foundation<br>
       Licensed under the GNU GPLv2+ License.
     HTML
 

From 1b968af7834c20d089d7f3022f9aae1718e7f188 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:13:16 +0000
Subject: [PATCH 066/384] Update dependency sinatra to v4 [SECURITY]

---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 6116289690..a3acf6fa71 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -58,7 +58,7 @@ GEM
     mini_portile2 (2.8.7)
     minitest (5.25.1)
     multi_json (1.15.0)
-    mustermann (3.0.0)
+    mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
     nokogiri (1.16.7)
@@ -133,7 +133,7 @@ GEM
       eventmachine (~> 1.0, >= 1.0.4)
       rack (>= 1, < 3)
     thor (1.3.2)
-    tilt (2.3.0)
+    tilt (2.4.0)
     tty-pager (0.14.0)
       strings (~> 0.2.0)
       tty-screen (~> 0.8)

From 2bb4ed8fb885a0c99e30219785b59c89df9777e9 Mon Sep 17 00:00:00 2001
From: Rui Jiang <me@ruijiang.me>
Date: Mon, 18 Nov 2024 18:54:09 -0600
Subject: [PATCH 067/384] updated svelte version from 4 to 5

---
 Gemfile.lock                          |  4 +---
 lib/docs/filters/svelte/clean_html.rb | 14 ++++++++++++--
 lib/docs/filters/svelte/entries.rb    | 27 ++++++---------------------
 lib/docs/scrapers/svelte.rb           | 14 ++++++++------
 4 files changed, 27 insertions(+), 32 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 0ee3e99ac8..6116289690 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -88,8 +88,7 @@ GEM
     rb-inotify (0.10.1)
       ffi (~> 1.0)
     redcarpet (3.6.0)
-    rexml (3.2.9)
-      strscan
+    rexml (3.3.9)
     rouge (1.11.1)
     rr (3.1.1)
     rss (0.3.1)
@@ -125,7 +124,6 @@ GEM
       unicode-display_width (>= 1.5, < 3.0)
       unicode_utils (~> 1.4)
     strings-ansi (0.2.0)
-    strscan (1.0.3)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
     terser (1.2.4)
diff --git a/lib/docs/filters/svelte/clean_html.rb b/lib/docs/filters/svelte/clean_html.rb
index 693825f78a..07f0dd517c 100644
--- a/lib/docs/filters/svelte/clean_html.rb
+++ b/lib/docs/filters/svelte/clean_html.rb
@@ -2,11 +2,21 @@ module Docs
   class Svelte
     class CleanHtmlFilter < Filter
       def call
-        @doc = at_css('main .page.content')
+        @doc = at_css('main .page.content #docs-content')
+
+        # Remove title header
+        at_css('> header > div.breadcrumbs').remove()
+        # Remove extra input toggle
+        at_css('> aside.on-this-page input').remove()
+        # Remove "edit this page" link
+        at_css('> p.edit').remove()
+        # Remove footer navigation
+        at_css('> div.controls').remove()
+
         at_css('h1').content = 'Svelte' if root_page?
         css('pre').each do |node|
           node.content = node.css('.line').map(&:content).join("\n")
-          node['data-language'] = 'javascript'
+          node['data-language'] = 'typescript'
         end
         doc
       end
diff --git a/lib/docs/filters/svelte/entries.rb b/lib/docs/filters/svelte/entries.rb
index dcd66cc2c2..c349898a1f 100644
--- a/lib/docs/filters/svelte/entries.rb
+++ b/lib/docs/filters/svelte/entries.rb
@@ -2,29 +2,14 @@ module Docs
   class Svelte
     class EntriesFilter < Docs::EntriesFilter
       def get_type
-        at_css('ul.sidebar > li:has(.active) > span.section').content
+        page = at_css("main nav ul.sidebar li ul li a[href$='#{result[:path]}']")
+        category = page.ancestors('li')[1]
+        return category.css('h3').inner_text
       end
 
-      def additional_entries
-        subtype = nil
-        css('aside').remove
-        css('.category').remove
-        css('.controls').remove
-        css('.edit').remove
-        css('.permalink').remove
-        css('h2, h3, h4').each_with_object [] do |node, entries|
-          if node.name == 'h2'
-            subtype = nil
-          elsif node.name == 'h3'
-            subtype = node.content.strip
-            subtype = nil unless subtype[/Component directives|Element directives/]
-          end
-          next if type == 'Before we begin'
-          name = node.content.strip
-          name.concat " (#{subtype})" if subtype && node.name == 'h4'
-          next if name.starts_with?('Example')
-          entries << [name, node['id'], get_type]
-        end
+      def get_name
+        page = at_css("main nav ul.sidebar li ul li a[href$='#{result[:path]}']")
+        return page.inner_text
       end
     end
   end
diff --git a/lib/docs/scrapers/svelte.rb b/lib/docs/scrapers/svelte.rb
index c5900a0b90..aac8738920 100644
--- a/lib/docs/scrapers/svelte.rb
+++ b/lib/docs/scrapers/svelte.rb
@@ -3,26 +3,28 @@ class Svelte < UrlScraper
     self.name = 'Svelte'
     self.slug = 'svelte'
     self.type = 'simple'
+    self.root_path = '/'
     self.links = {
       home: 'https://svelte.dev/',
       code: 'https://github.com/sveltejs/svelte'
     }
 
-    self.root_path = 'introduction'
     options[:root_title] = 'Svelte'
 
     # https://github.com/sveltejs/svelte/blob/master/LICENSE.md
     options[:attribution] = <<-HTML
-      &copy; 2016–2023 Rich Harris and contributors<br>
+      &copy; 2016–2024 Rich Harris and contributors<br>
       Licensed under the MIT License.
     HTML
 
-    options[:skip] = %w(team.html plugins/)
-
-    self.base_url = 'https://svelte.dev/docs/'
+    self.base_url = 'https://svelte.dev/docs/svelte/'
     html_filters.push 'svelte/entries', 'svelte/clean_html'
-    
+
     version do
+      self.release = '5.2.3'
+    end
+
+    version '4' do
       self.release = '4.2.1'
     end
 

From ea00d3bfd13083fcfd435e18de3b0adeae9aa910 Mon Sep 17 00:00:00 2001
From: Rui Jiang <me@ruijiang.me>
Date: Mon, 18 Nov 2024 19:00:02 -0600
Subject: [PATCH 068/384] fixed gem lock

---
 Gemfile.lock | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 6116289690..0ee3e99ac8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -88,7 +88,8 @@ GEM
     rb-inotify (0.10.1)
       ffi (~> 1.0)
     redcarpet (3.6.0)
-    rexml (3.3.9)
+    rexml (3.2.9)
+      strscan
     rouge (1.11.1)
     rr (3.1.1)
     rss (0.3.1)
@@ -124,6 +125,7 @@ GEM
       unicode-display_width (>= 1.5, < 3.0)
       unicode_utils (~> 1.4)
     strings-ansi (0.2.0)
+    strscan (1.0.3)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
     terser (1.2.4)

From 9102197db09598dbf4fa9001bc3ec604b922c065 Mon Sep 17 00:00:00 2001
From: Rui Jiang <me@ruijiang.me>
Date: Mon, 18 Nov 2024 19:13:42 -0600
Subject: [PATCH 069/384] removed hover popup

---
 lib/docs/filters/svelte/clean_html.rb | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/docs/filters/svelte/clean_html.rb b/lib/docs/filters/svelte/clean_html.rb
index 07f0dd517c..cdc929ea4c 100644
--- a/lib/docs/filters/svelte/clean_html.rb
+++ b/lib/docs/filters/svelte/clean_html.rb
@@ -15,6 +15,8 @@ def call
 
         at_css('h1').content = 'Svelte' if root_page?
         css('pre').each do |node|
+          # Remove hover popup
+          node.css('.twoslash-popup-container').remove()
           node.content = node.css('.line').map(&:content).join("\n")
           node['data-language'] = 'typescript'
         end

From 7c7ddaeead951684d00ee477866c3ffa0922e4d6 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 16:34:27 +0100
Subject: [PATCH 070/384] Update Sequelize documentation (6.37.5)

---
 lib/docs/filters/sequelize/clean_html.rb | 2 +-
 lib/docs/scrapers/sequelize.rb           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/filters/sequelize/clean_html.rb b/lib/docs/filters/sequelize/clean_html.rb
index a7d9bc05b6..62e89b00d1 100644
--- a/lib/docs/filters/sequelize/clean_html.rb
+++ b/lib/docs/filters/sequelize/clean_html.rb
@@ -2,7 +2,7 @@ module Docs
   class Sequelize
     class CleanHtmlFilter < Filter
       def call
-        @doc = at_css('article', '.content')
+        @doc = at_css('article', '.content .self-detail', '.content')
 
         if at_css('header > h1')
           # Pull the header out of its container
diff --git a/lib/docs/scrapers/sequelize.rb b/lib/docs/scrapers/sequelize.rb
index f170abfeb1..8410c7efd0 100644
--- a/lib/docs/scrapers/sequelize.rb
+++ b/lib/docs/scrapers/sequelize.rb
@@ -30,7 +30,7 @@ def initial_urls
     end
 
     version '6' do
-      self.release = '6.23.2'
+      self.release = '6.37.5'
       self.base_url = "https://sequelize.org/docs/v6/"
       self.base_urls = [
         "https://sequelize.org/docs/v6/",

From 2edbd614a0682ac84ab435cc882254e576eee2be Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 17 Nov 2024 16:36:29 +0100
Subject: [PATCH 071/384] Update Matplotlib documentation (3.9.2)

---
 lib/docs/scrapers/matplotlib.rb | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/matplotlib.rb b/lib/docs/scrapers/matplotlib.rb
index 1486642ce2..5e30998c2b 100644
--- a/lib/docs/scrapers/matplotlib.rb
+++ b/lib/docs/scrapers/matplotlib.rb
@@ -20,8 +20,8 @@ class Matplotlib < UrlScraper
       Licensed under the Matplotlib License Agreement.
     HTML
 
-    version '3.7' do
-      self.release = '3.7.1'
+    version do
+      self.release = '3.9.2'
       self.base_urls = [
         "https://matplotlib.org/stable/api/",
         "https://matplotlib.org/stable/mpl_toolkits/mplot3d/",
@@ -29,6 +29,24 @@ class Matplotlib < UrlScraper
       ]
     end
 
+    version '3.8' do
+      self.release = '3.8.4'
+      self.base_urls = [
+        "https://matplotlib.org/#{release}/api/",
+        "https://matplotlib.org/#{release}/mpl_toolkits/mplot3d/",
+        "https://matplotlib.org/#{release}/mpl_toolkits/axes_grid/api/"
+      ]
+    end
+
+    version '3.7' do
+      self.release = '3.7.5'
+      self.base_urls = [
+        "https://matplotlib.org/#{release}/api/",
+        "https://matplotlib.org/#{release}/mpl_toolkits/mplot3d/",
+        "https://matplotlib.org/#{release}/mpl_toolkits/axes_grid/api/"
+      ]
+    end
+
     version '3.6' do
       self.release = '3.6.0'
       self.base_urls = [

From e18ddad165c65160de75d3284bebbd2a1795c9c9 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 19 Nov 2024 07:17:35 +0100
Subject: [PATCH 072/384] Update Support Tables documentation (1.0.30001680)

---
 lib/docs/scrapers/support_tables.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/support_tables.rb b/lib/docs/scrapers/support_tables.rb
index 4318edf31e..e181fd8fad 100644
--- a/lib/docs/scrapers/support_tables.rb
+++ b/lib/docs/scrapers/support_tables.rb
@@ -7,7 +7,7 @@ class SupportTables < Scraper
     self.name = 'Support Tables'
     self.slug = 'browser_support_tables'
     self.type = 'support_tables'
-    self.release = '1.0.30001642'
+    self.release = '1.0.30001680'
     self.base_url = 'https://github.com/Fyrd/caniuse/raw/main/'
 
     # https://github.com/Fyrd/caniuse/blob/main/LICENSE

From 811b9d13d70e038b2dc29bdcbe713f91fae4da8b Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 19 Nov 2024 13:09:36 +0100
Subject: [PATCH 073/384] Update RxJS documentation (7.8.1)

---
 lib/docs/scrapers/rxjs.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/rxjs.rb b/lib/docs/scrapers/rxjs.rb
index 69d2fffc5f..83827f97ad 100644
--- a/lib/docs/scrapers/rxjs.rb
+++ b/lib/docs/scrapers/rxjs.rb
@@ -4,7 +4,7 @@ module Docs
   class Rxjs < UrlScraper
     self.name = 'RxJS'
     self.type = 'rxjs'
-    self.release = '7.5.5'
+    self.release = '7.8.1'
     self.base_url = 'https://rxjs.dev/'
     self.root_path = 'guide/overview'
     self.links = {
@@ -16,7 +16,7 @@ class Rxjs < UrlScraper
 
     options[:follow_links] = false
     options[:only_patterns] = [/guide\//, /api\//]
-    options[:skip_patterns] = [/api\/([^\/]+)\.json/]
+    options[:skip_patterns] = [/api\/([^\/]+)\.json/, /api\/index/]
     options[:fix_urls_before_parse] = ->(url) do
       url.sub! %r{\A(\.\/)?guide/}, '/guide/'
       url.sub! %r{\Aapi/}, '/api/'

From 8b8ebda2071ca713c13854f5a2d63647f6658ce0 Mon Sep 17 00:00:00 2001
From: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Date: Tue, 19 Nov 2024 18:43:48 +0100
Subject: [PATCH 074/384] fix: use aliases from config

---
 assets/javascripts/templates/pages/help_tmpl.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/assets/javascripts/templates/pages/help_tmpl.js b/assets/javascripts/templates/pages/help_tmpl.js
index 2fa186c827..e155d82999 100644
--- a/assets/javascripts/templates/pages/help_tmpl.js
+++ b/assets/javascripts/templates/pages/help_tmpl.js
@@ -3,7 +3,7 @@ app.templates.helpPage = function () {
   const navKey = $.isMac() ? "cmd" : "alt";
   const arrowScroll = app.settings.get("arrowScroll");
 
-  const aliases = Object.entries(app.models.Entry.ALIASES);
+  const aliases = Object.entries(app.config.docs_aliases);
   const middle = Math.ceil(aliases.length / 2);
   const aliases_one = aliases.slice(0, middle);
   const aliases_two = aliases.slice(middle);

From d4034eea2d0098e64bfe037e4b7212d43ec96d42 Mon Sep 17 00:00:00 2001
From: Rui Jiang <me@ruijiang.me>
Date: Tue, 19 Nov 2024 21:23:53 -0600
Subject: [PATCH 075/384] updated eslint scraper

---
 lib/docs/filters/eslint/entries.rb |  7 ++++++-
 lib/docs/scrapers/eslint.rb        | 21 ++++++++++++++++++---
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/lib/docs/filters/eslint/entries.rb b/lib/docs/filters/eslint/entries.rb
index f5f0f345a2..e40cd7a559 100644
--- a/lib/docs/filters/eslint/entries.rb
+++ b/lib/docs/filters/eslint/entries.rb
@@ -10,7 +10,12 @@ def get_type
         if subpath.start_with?('rules')
           return 'Rules'
         else
-          at_css('nav.docs-index [aria-current="true"]').ancestors('li')[-1].at_css('a').content
+          type = at_css('nav.docs-index [aria-current="true"]').ancestors('li')[-1].at_css('a').content
+          # This specific entry is mispelled with a lowercase 'i'
+          if type.start_with?('integrate')
+            type = type.sub('integrate', 'Integrate')
+          end
+          return type
         end
       end
     end
diff --git a/lib/docs/scrapers/eslint.rb b/lib/docs/scrapers/eslint.rb
index 6d06983901..e3243171df 100644
--- a/lib/docs/scrapers/eslint.rb
+++ b/lib/docs/scrapers/eslint.rb
@@ -2,9 +2,9 @@ module Docs
   class Eslint < UrlScraper
     self.name = 'ESLint'
     self.type = 'simple'
-    self.release = '8.56.0'
+    self.release = '9.15.0'
     self.base_url = 'https://eslint.org/docs/latest/'
-    self.root_path = 'user-guide/getting-started'
+    self.root_path = '/'
     self.links = {
       home: 'https://eslint.org/',
       code: 'https://github.com/eslint/eslint'
@@ -14,7 +14,22 @@ class Eslint < UrlScraper
 
     options[:skip_patterns] = [/maintain/, /migrating/, /migrate/, /\Aversions/, /rule-deprecation/]
     options[:skip] = %w(about about/ versions)
-    options[:replace_paths] = { 'user-guide' => 'user-guide/' }
+    # A number of paths have a trailing slash, causing them to be suffixed by "index" during the NormalizePathsFilter
+    options[:replace_paths] = {
+      'configure/' => 'configure',
+      'contribute/' => 'contribute',
+      'contribute/architecture/' => 'contribute/architecture',
+      'extend/' => 'extend',
+      'flags/' => 'flags',
+      'integrate/' => 'integrate',
+      'rules/' => 'rules',
+      'use/' => 'use',
+      'use/formatters/' => 'use/formatters',
+      'use/configure/' => 'use/configure',
+      'use/configure/rules/' => 'use/configure/rules',
+      'use/core-concepts/' => 'use/core-concepts',
+      'use/troubleshooting/' => 'use/troubleshooting',
+    }
 
     options[:attribution] = <<-HTML
       &copy; OpenJS Foundation and other contributors<br>

From dfe89bb46011d1c21f54942c695fd80d65a6eceb Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 20 Nov 2024 22:12:06 +0100
Subject: [PATCH 076/384] Update ESLint documentation (9.15.0)

---
 lib/docs/filters/eslint/clean_html.rb | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/docs/filters/eslint/clean_html.rb b/lib/docs/filters/eslint/clean_html.rb
index 0737acef05..f347cef969 100644
--- a/lib/docs/filters/eslint/clean_html.rb
+++ b/lib/docs/filters/eslint/clean_html.rb
@@ -5,6 +5,7 @@ def call
         @doc = at_css('#main') if at_css('#main')
         @doc = at_css('.docs-main__content') if at_css('.docs-main__content')
 
+        css('.docs-toc').remove
         css('.eslint-ad').remove
         css('.glyphicon').remove
         css('hr', 'colgroup', 'td:empty').remove

From 4baf915b99038bcd56e0b11be7a9f865506cec12 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 20 Nov 2024 22:20:16 +0100
Subject: [PATCH 077/384] Update Playwright documentation (1.49.0)

---
 lib/docs/scrapers/playwright.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/playwright.rb b/lib/docs/scrapers/playwright.rb
index 2d4aa89100..c8e2c70e12 100644
--- a/lib/docs/scrapers/playwright.rb
+++ b/lib/docs/scrapers/playwright.rb
@@ -2,7 +2,7 @@ module Docs
   class Playwright < UrlScraper
     self.name = 'Playwright'
     self.type = 'simple'
-    self.release = '1.46.1'
+    self.release = '1.49.0'
     self.base_url = 'https://playwright.dev/docs/'
     self.root_path = 'intro'
     self.links = {

From 2216cb46cf6ba6dbf1ab6d104ca38e011be4e3ca Mon Sep 17 00:00:00 2001
From: Rui Jiang <me@ruijiang.me>
Date: Wed, 20 Nov 2024 17:26:35 -0600
Subject: [PATCH 078/384] updated yarn version (3.1.1 > 4.5.1)

---
 lib/docs/filters/yarn/clean_html_berry.rb | 41 ++++-------------------
 lib/docs/filters/yarn/entries_berry.rb    | 19 ++---------
 lib/docs/scrapers/yarn.rb                 | 17 +++++++---
 3 files changed, 22 insertions(+), 55 deletions(-)

diff --git a/lib/docs/filters/yarn/clean_html_berry.rb b/lib/docs/filters/yarn/clean_html_berry.rb
index 96b3ee53e2..8a28ce25a2 100644
--- a/lib/docs/filters/yarn/clean_html_berry.rb
+++ b/lib/docs/filters/yarn/clean_html_berry.rb
@@ -2,45 +2,18 @@ module Docs
   class Yarn
     class CleanHtmlBerryFilter < Filter
       def call
-        if slug.empty?
-          @doc = at_css('main')
-          css(
-            (['div:first-child'] * 3).join('>'), # Tagline
-            'img',
-            'hr', # Footer
-            'hr + div', # Footer
-          ).remove
-
-          css('a').each do |link|
-            link.name = 'div'
-            link.css('h3').each do |node|
-              node.replace("<h2><a href='#{link['href']}'>#{node.content}</a></h2>")
-            end
-          end
-
-          return doc
-        end
-
-        @doc = at_css('article')
-        # Heading & edit link
-        css('h1', 'h1 + a').remove unless slug.start_with?('configuration')
-
-        if slug.start_with?('cli')
-          css('.header-code').each do |node|
-            node.name = 'span'
-          end
-        end
-
-        if slug.start_with?('configuration')
-          css('h1', 'h2').each do |node|
-            node.name = node.name.sub(/\d/) { |i| i.to_i + 1 }
-          end
-        end
+        @doc = at_css('main .container div.theme-doc-markdown.markdown')
 
         css('*').each do |node|
           node.remove_attribute('style')
         end
 
+        css('pre').each do |node|
+          lang = node['class'][/language-(\w+)/, 1]
+          node['data-language'] = lang if lang
+          node.content = node.css('.token-line').map(&:content).join("\n")
+        end
+
         doc
       end
     end
diff --git a/lib/docs/filters/yarn/entries_berry.rb b/lib/docs/filters/yarn/entries_berry.rb
index 44c1e18ea3..6b99bfa60a 100644
--- a/lib/docs/filters/yarn/entries_berry.rb
+++ b/lib/docs/filters/yarn/entries_berry.rb
@@ -2,26 +2,11 @@ module Docs
   class Yarn
     class EntriesBerryFilter < Docs::EntriesFilter
       def get_name
-        if slug.start_with?('configuration')
-          filename = at_css('main .active code')
-          content = filename.content
-          return filename.parent.content.sub content, " (#{content})"
-        end
-
-        name = at_css('h1').content
-
-        if slug.start_with?('getting-started')
-          active_link = at_css('main .active')
-          links = active_link.parent.children.to_a
-          name.prepend "#{links.index(active_link) + 1}. "
-        end
-
-        name
+        at_css('main header h1').content
       end
 
       def get_type
-         return 'CLI' if slug.start_with?('sdks', 'pnpify')
-         at_css('header .active').content
+        at_css('nav.navbar a.navbar__item.navbar__link.navbar__link--active').content
       end
     end
   end
diff --git a/lib/docs/scrapers/yarn.rb b/lib/docs/scrapers/yarn.rb
index 8cc49260ee..9d20bc8ce4 100644
--- a/lib/docs/scrapers/yarn.rb
+++ b/lib/docs/scrapers/yarn.rb
@@ -13,15 +13,16 @@ class Yarn < UrlScraper
     HTML
 
     version 'Berry' do
-      self.release = '3.1.1'
+      self.release = '4.5.1'
       self.base_url = 'https://yarnpkg.com/'
       self.links = {
         home: 'https://yarnpkg.com/',
         code: 'https://github.com/yarnpkg/berry'
       }
-      html_filters.push 'yarn/entries_berry', 'yarn/clean_html_berry', 'title'
-      options[:skip] = ['features', 'cli', 'configuration', 'advanced']
-      options[:skip_patterns] = [/\Aapi/, /\Apackage/]
+      self.root_path = 'getting-started'
+      html_filters.push 'yarn/entries_berry', 'yarn/clean_html_berry'
+      options[:skip] = ['cli', 'cli/builder', 'cli/pnpify', 'cli/sdks', 'protocols']
+      options[:skip_patterns] = [/\Aapi/, /\Ablog/, /\Apackage/, /\Aassets/]
     end
 
     version 'Classic' do
@@ -38,5 +39,13 @@ class Yarn < UrlScraper
     def get_latest_version(opts)
       get_latest_github_release('yarnpkg', 'berry', opts)[/[\d.]+/]
     end
+
+    private
+
+    # Some pages contain null bytes and cause the parser to fail
+    def parse(response)
+      response.body.gsub!(/[\x00\u0000\0]/, '')
+      super
+    end
   end
 end

From ae7246ccc20c0b3f4d6544f50d1a740b5573bcea Mon Sep 17 00:00:00 2001
From: Esmaeil Vakili <evakili@users.noreply.github.com>
Date: Wed, 20 Nov 2024 11:21:30 +0330
Subject: [PATCH 079/384] update cmake to v3.31 and add latest version docs to
 the list

---
 lib/docs/scrapers/cmake.rb | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/cmake.rb b/lib/docs/scrapers/cmake.rb
index cf14b56235..bb2e4aae18 100644
--- a/lib/docs/scrapers/cmake.rb
+++ b/lib/docs/scrapers/cmake.rb
@@ -16,10 +16,39 @@ class Cmake < UrlScraper
     options[:skip_patterns] = [/\Agenerator/, /\Acpack_gen/, /\Ainclude/, /\Arelease/, /tutorial\/(\w*%20)+/]
 
     options[:attribution] = <<-HTML
-      &copy; 2000&ndash;2023 Kitware, Inc. and Contributors<br>
+      &copy; 2000&ndash;2024 Kitware, Inc. and Contributors<br>
       Licensed under the BSD 3-clause License.
     HTML
 
+    version do
+      self.base_url = "https://cmake.org/cmake/help/latest/"
+    end
+
+    version '3.31' do
+      self.release = '3.31'
+      self.base_url = "https://cmake.org/cmake/help/v#{self.version}/"
+    end
+
+    version '3.30' do
+      self.release = '3.30'
+      self.base_url = "https://cmake.org/cmake/help/v#{self.version}/"
+    end
+
+    version '3.29' do
+      self.release = '3.29'
+      self.base_url = "https://cmake.org/cmake/help/v#{self.version}/"
+    end
+
+    version '3.28' do
+      self.release = '3.28'
+      self.base_url = "https://cmake.org/cmake/help/v#{self.version}/"
+    end
+
+    version '3.27' do
+      self.release = '3.27'
+      self.base_url = "https://cmake.org/cmake/help/v#{self.version}/"
+    end
+
     version '3.26' do
       self.release = '3.26'
       self.base_url = "https://cmake.org/cmake/help/v#{self.version}/"

From 3caa196ea31ce2ad6f4c6a0f88abe3b48909c23f Mon Sep 17 00:00:00 2001
From: Esmaeil Vakili <evakili@users.noreply.github.com>
Date: Wed, 20 Nov 2024 11:47:23 +0330
Subject: [PATCH 080/384] update cmake icons

---
 public/icons/docs/cmake/16.png    | Bin 231 -> 718 bytes
 public/icons/docs/cmake/16@2x.png | Bin 392 -> 1632 bytes
 public/icons/docs/cmake/SOURCE    |   2 +-
 3 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/public/icons/docs/cmake/16.png b/public/icons/docs/cmake/16.png
index fe82b4bc2ebea007babde4ba1414ea4635346054..b0591445f183c50a2ccb2b704b03da4f76f462a2 100644
GIT binary patch
diff --git a/public/icons/docs/cmake/16@2x.png b/public/icons/docs/cmake/16@2x.png
index 4dcfc24c973cfdea47735f40cb43cd632288bd92..78df82f15b5d0feef6959ed03e9edfd280f1a42f 100644
GIT binary patch
diff --git a/public/icons/docs/cmake/SOURCE b/public/icons/docs/cmake/SOURCE
index dbfc5e6295..1f16be4cdd 100644
--- a/public/icons/docs/cmake/SOURCE
+++ b/public/icons/docs/cmake/SOURCE
@@ -1 +1 @@
-https://cmake.org/gitweb?p=cmake.git;a=blob_plain;f=Source/QtDialog/CMakeSetup.ico;hb=refs/heads/master
+https://gitlab.kitware.com/cmake/cmake/-/blob/v3.31.0/Source/QtDialog/CMakeSetup32.png

From d45d1435eb6c2dbdab32474df19fb9432cc92810 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 21 Nov 2024 19:26:35 +0100
Subject: [PATCH 081/384] Update Yarn documentation (4.5.1)

---
 lib/docs/scrapers/yarn.rb | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/yarn.rb b/lib/docs/scrapers/yarn.rb
index 9d20bc8ce4..6539c7d5ee 100644
--- a/lib/docs/scrapers/yarn.rb
+++ b/lib/docs/scrapers/yarn.rb
@@ -12,7 +12,7 @@ class Yarn < UrlScraper
       Licensed under the BSD License.
     HTML
 
-    version 'Berry' do
+    version do
       self.release = '4.5.1'
       self.base_url = 'https://yarnpkg.com/'
       self.links = {
@@ -25,6 +25,18 @@ class Yarn < UrlScraper
       options[:skip_patterns] = [/\Aapi/, /\Ablog/, /\Apackage/, /\Aassets/]
     end
 
+    version '3' do
+      self.release = '3.1.1'
+      self.base_url = 'https://v3.yarnpkg.com/'
+      self.links = {
+        home: 'https://v3.yarnpkg.com/',
+        code: 'https://github.com/yarnpkg/berry'
+      }
+      self.root_path = 'getting-started'
+      html_filters.push 'yarn/entries_berry', 'yarn/clean_html_berry', 'title'
+      options[:skip] = ['features', 'cli', 'configuration', 'advanced']
+      options[:skip_patterns] = [/\Aapi/, /\Apackage/]    end
+
     version 'Classic' do
       self.release = '1.22.17'
       self.base_url = 'https://classic.yarnpkg.com/en/docs/'

From 919425b8cf16003bb9632937d404ceab7f54fcf9 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 21 Nov 2024 22:09:37 +0100
Subject: [PATCH 082/384] Update PHP documentation (8.4)

---
 lib/docs/scrapers/php.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/php.rb b/lib/docs/scrapers/php.rb
index 6d38c70c22..b9900e8255 100644
--- a/lib/docs/scrapers/php.rb
+++ b/lib/docs/scrapers/php.rb
@@ -5,7 +5,7 @@ class Php < FileScraper
 
     self.name = 'PHP'
     self.type = 'php'
-    self.release = '8.3'
+    self.release = '8.4'
     self.base_url = 'https://www.php.net/manual/en/'
     self.root_path = 'index.html'
     self.initial_paths = %w(
@@ -62,7 +62,7 @@ class Php < FileScraper
     options[:skip_patterns] = [/mysqlnd/, /xdevapi/i]
 
     options[:attribution] = <<-HTML
-      &copy; 1997&ndash;2023 The PHP Documentation Group<br>
+      &copy; 1997&ndash;2024 The PHP Documentation Group<br>
       Licensed under the Creative Commons Attribution License v3.0 or later.
     HTML
 

From 18c6b7caeef09b706f2bb01ce6b487ebdeea8016 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 21 Nov 2024 21:43:41 +0000
Subject: [PATCH 083/384] chore(deps): update dependency minitest to v5.25.2

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index a3acf6fa71..a708f12b62 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -56,7 +56,7 @@ GEM
     logger (1.6.1)
     method_source (1.0.0)
     mini_portile2 (2.8.7)
-    minitest (5.25.1)
+    minitest (5.25.2)
     multi_json (1.15.0)
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)

From 5800216f1b3f8fe94a399373c91ef5938e939c4d Mon Sep 17 00:00:00 2001
From: Scott Goley <scottmgoley@gmail.com>
Date: Thu, 21 Nov 2024 21:49:50 -0500
Subject: [PATCH 084/384] +duckdb icons & source

---
 public/icons/docs/duckdb/16.png    | Bin 0 -> 902 bytes
 public/icons/docs/duckdb/16@2x.png | Bin 0 -> 1566 bytes
 public/icons/docs/duckdb/SOURCE    |   1 +
 3 files changed, 1 insertion(+)
 create mode 100644 public/icons/docs/duckdb/16.png
 create mode 100644 public/icons/docs/duckdb/16@2x.png
 create mode 100644 public/icons/docs/duckdb/SOURCE

diff --git a/public/icons/docs/duckdb/16.png b/public/icons/docs/duckdb/16.png
new file mode 100644
index 0000000000000000000000000000000000000000..855df72e07579463f4069f526928fcecf748a151
GIT binary patch
diff --git a/public/icons/docs/duckdb/16@2x.png b/public/icons/docs/duckdb/16@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..f128c8ca43e2ff3a6f91174530173a52f7857d89
GIT binary patch
diff --git a/public/icons/docs/duckdb/SOURCE b/public/icons/docs/duckdb/SOURCE
new file mode 100644
index 0000000000..286d1738f9
--- /dev/null
+++ b/public/icons/docs/duckdb/SOURCE
@@ -0,0 +1 @@
+https://github.com/duckdb/duckdb/tree/main/logo
\ No newline at end of file

From deedda316149dbde221788c8142499cdb43933f2 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 23 Nov 2024 14:44:32 +0100
Subject: [PATCH 085/384] Update DuckDB documentation (1.1.3)

---
 assets/javascripts/news.json           |  4 +++
 lib/docs/filters/duckdb/attribution.rb | 12 ++++++++
 lib/docs/filters/duckdb/clean_html.rb  | 21 +++++++------
 lib/docs/filters/duckdb/entries.rb     |  2 +-
 lib/docs/scrapers/duckdb.rb            | 41 +++++---------------------
 5 files changed, 34 insertions(+), 46 deletions(-)
 create mode 100644 lib/docs/filters/duckdb/attribution.rb

diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index e56bd8dd95..052f4918e5 100644
--- a/assets/javascripts/news.json
+++ b/assets/javascripts/news.json
@@ -1,4 +1,8 @@
 [
+  [
+    "2024-11-23",
+    "New documentation: <a href=\"/duckdb/\">DuckDB</a>"
+  ],
   [
     "2024-08-20",
     "New documentation: <a href=\"/man/\">Linux man pages</a>"
diff --git a/lib/docs/filters/duckdb/attribution.rb b/lib/docs/filters/duckdb/attribution.rb
new file mode 100644
index 0000000000..7591fdb8dd
--- /dev/null
+++ b/lib/docs/filters/duckdb/attribution.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Docs
+  class Duckdb
+    class AttributionFilter < Docs::AttributionFilter
+      def attribution_link
+        url = current_url.to_s.sub! 'http://localhost:8000', 'https://duckdb.org'
+        %(<a href="#{url}" class="_attribution-link">#{url}</a>)
+      end
+    end
+  end
+end
diff --git a/lib/docs/filters/duckdb/clean_html.rb b/lib/docs/filters/duckdb/clean_html.rb
index ae518c7b38..d739275e74 100644
--- a/lib/docs/filters/duckdb/clean_html.rb
+++ b/lib/docs/filters/duckdb/clean_html.rb
@@ -3,27 +3,26 @@ class Duckdb
     class CleanHtmlFilter < Filter
       def call
         # First extract the main content
-        @doc = at_css('main')
+        @doc = at_css('#main_content_wrap', 'main')
         return doc if @doc.nil?
 
+        doc.prepend_child at_css('.title').remove
+        at_css('.title').name = 'h1'
+
         # Remove navigation and header elements
-        css('.headerline', '.landingmenu', '.search_icon', '#sidebar', '.pagemeta', '.toc_menu', '.section-nav').remove
+        css('.headerline', '.headlinebar', '.landingmenu', '.search_icon', '#sidebar', '.pagemeta', '.toc_menu', '.section-nav').remove
 
         # Clean up code blocks
-        css('pre').each do |node|
-          # Detect language from class or parent div
-          if node['class']&.include?('sql') || node.at_css('code.sql')
-            node['data-language'] = 'sql'
-          elsif node['class']&.include?('language-sql')
-            node['data-language'] = 'sql'
-          end
+        css('div.highlighter-rouge').each do |node|
+          node['data-language'] = node['class'][/language-(\w+)/, 1] if node['class']
           node.content = node.content.strip
+          node.name = 'pre'
         end
 
-        # Remove unnecessary attributes but keep essential ones
+        # Remove unnecessary attributes
         css('div, span, p').each do |node|
           node.remove_attribute('style')
-          node.remove_attribute('class') unless node['class'] =~ /highlight/
+          node.remove_attribute('class')
         end
 
         # Remove empty elements
diff --git a/lib/docs/filters/duckdb/entries.rb b/lib/docs/filters/duckdb/entries.rb
index ea9290227f..cb98768aef 100644
--- a/lib/docs/filters/duckdb/entries.rb
+++ b/lib/docs/filters/duckdb/entries.rb
@@ -2,7 +2,7 @@ module Docs
   class Duckdb
     class EntriesFilter < Docs::EntriesFilter
       def get_name
-        at_css('h1')&.content || 'DuckDB'
+        at_css('h1', '.title').content
       end
 
       def get_type
diff --git a/lib/docs/scrapers/duckdb.rb b/lib/docs/scrapers/duckdb.rb
index a160b3ef21..98fb16ed22 100644
--- a/lib/docs/scrapers/duckdb.rb
+++ b/lib/docs/scrapers/duckdb.rb
@@ -8,7 +8,13 @@ class Duckdb < UrlScraper
       code: 'https://github.com/duckdb/duckdb'
     }
 
+    # https://duckdb.org/docs/guides/offline-copy.html
+    # curl -O https://duckdb.org/duckdb-docs.zip; bsdtar xf duckdb-docs.zip; cd duckdb-docs; python -m http.server
+    self.release = '1.1.3'
+    self.base_url = 'http://localhost:8000/docs/'
+
     html_filters.push 'duckdb/entries', 'duckdb/clean_html'
+    text_filters.replace 'attribution', 'duckdb/attribution'
 
     options[:container] = '.documentation'
     
@@ -29,41 +35,8 @@ class Duckdb < UrlScraper
       Licensed under the MIT License.
     HTML
 
-    version '1.1' do
-      self.release = '1.1.x'
-      self.base_url = 'http://localhost:8000/docs/'
-    end
-
-    # version '1.0' do
-    #     self.release = '1.0.x'
-    #     self.base_url = "https://duckdb.org/docs/archive/#{self.version}/"
-
-    #     html_filters.push 'duckdb/clean_html'
-    # end
-
-    # version '0.9' do
-    #     self.release = '0.9.x'
-    #     self.base_url = "https://duckdb.org/docs/archive/#{self.version}/"
-
-    #     html_filters.push 'duckdb/clean_html'
-    # end
-
-    # version '0.8' do
-    #     self.release = '0.8.x'
-    #     self.base_url = "https://duckdb.org/docs/archive/#{self.version}/"
-
-    #     html_filters.push 'duckdb/clean_html'
-    # end
-
-    # version '0.7' do
-    #     self.release = '0.7.x'
-    #     self.base_url = "https://duckdb.org/docs/archive/#{self.version}/"
-
-    #     html_filters.push 'duckdb/clean_html'
-    # end
-
     def get_latest_version(opts)
-      get_github_tags('duckdb', 'duckdb', opts)
+      get_github_tags('duckdb', 'duckdb', opts)[0]['name']
     end
   end
 end

From 0733738b00501c4964cbcdc406b95c56f5098988 Mon Sep 17 00:00:00 2001
From: Rui Jiang <me@ruijiang.me>
Date: Mon, 25 Nov 2024 21:27:06 -0600
Subject: [PATCH 086/384] updated deno version

---
 lib/docs/filters/deno/clean_html.rb | 28 +++++++++++--------------
 lib/docs/filters/deno/entries.rb    | 14 +++++++++++--
 lib/docs/scrapers/deno.rb           | 32 ++++++++++++++++++++++-------
 3 files changed, 49 insertions(+), 25 deletions(-)

diff --git a/lib/docs/filters/deno/clean_html.rb b/lib/docs/filters/deno/clean_html.rb
index c2b1befd46..46fc16e424 100644
--- a/lib/docs/filters/deno/clean_html.rb
+++ b/lib/docs/filters/deno/clean_html.rb
@@ -2,26 +2,22 @@ module Docs
   class Deno
     class CleanHtmlFilter < Filter
       def call
-        if root_page?
-          @doc = at_css('h2[id]').parent.parent
+        if result[:path].start_with?('api/deno/')
+          @doc = at_css('main')
         else
-          @doc = at_css('article')
+          @doc = at_css('main article .markdown-body')
         end
 
-        css('*[aria-label="Anchor"]').remove
-        css('pre', '.tw-1nkr705').each do |node|
-          node['data-language'] = 'typescript'
-          node.name = 'pre'
+        css('code').each do |node|
+          if node['class']
+            lang = node['class'][/language-(\w+)/, 1]
+          end
+          node['data-language'] = lang || 'ts'
+          node.remove_attribute('class')
         end
-        css('.tw-8ej7ai').each do |node|
-          code = node.at_css('.font-mono')
-          next unless code
-          code.parent.name = 'blockquote'
-          code.name = 'code'
-        end
-        css('*[class]').remove_attribute('class')
-        xpath('//a[text()="[src]"]').remove
-        
+
+        css('a.header-anchor').remove()
+
         doc
       end
     end
diff --git a/lib/docs/filters/deno/entries.rb b/lib/docs/filters/deno/entries.rb
index f088a83840..279086f3e6 100644
--- a/lib/docs/filters/deno/entries.rb
+++ b/lib/docs/filters/deno/entries.rb
@@ -3,11 +3,21 @@ class Deno
     class EntriesFilter < Docs::EntriesFilter
 
       def get_name
-        at_css('h1').content
+        if result[:path].start_with?('api/deno/')
+          at_css('main')['id'][/\Asymbol_([.\w]+)/, 1]
+        else
+          at_css('main article h1').content
+        end
       end
 
       def get_type
-        'Deno CLI APIs'
+        if result[:path].start_with?('api/deno/')
+          'API'
+        elsif result[:path].start_with?('runtime/reference/cli')
+          'CLI'
+        else
+          at_css('main article nav ul :first span').content
+        end
       end
 
     end
diff --git a/lib/docs/scrapers/deno.rb b/lib/docs/scrapers/deno.rb
index 1b00b7053d..3d76eadaf3 100644
--- a/lib/docs/scrapers/deno.rb
+++ b/lib/docs/scrapers/deno.rb
@@ -2,22 +2,40 @@ module Docs
   class Deno < UrlScraper
     self.name = 'Deno'
     self.type = 'simple'
-    self.release = '1.27.0'
-    self.base_url = 'https://doc.deno.land/deno/stable/'
     self.links = {
-      home: 'https://deno.land/',
+      home: 'https://deno.com/',
       code: 'https://github.com/denoland/deno'
     }
 
-    html_filters.push 'deno/entries', 'deno/clean_html'
-
     # https://github.com/denoland/manual/blob/main/LICENSE
     options[:attribution] = <<-HTML
-      &copy; 2018–2022 the Deno authors
+      &copy; 2018–2024 the Deno authors<br>
+      Licensed under the MIT License.
     HTML
 
+
+    html_filters.push 'deno/entries', 'deno/clean_html'
+
+    version '2' do
+      self.release = '2.1.1'
+      self.base_url = 'https://docs.deno.com/'
+      self.root_path = 'runtime'
+      options[:only_patterns] = [/\Aruntime/, /\Aapi\/deno\/~/, /\Adeploy/, /\Asubhosting/]
+      options[:skip_patterns] = [
+        /\Aruntime\/manual/,
+        /\Aapi\/deno\/.+\.prototype\z/, # all prototype pages get redirected to the main page
+        /\Aapi\/deno\/~\/Deno\.jupyter\.MediaBundle.+/, # docs unavailable
+        /\Aapi\/deno\/~\/Deno\.OpMetrics/, # deprecated in deno 2
+      ]
+      options[:trailing_slash] = false
+    end
+
+    version '1' do
+      self.release = '1.27.0'
+    end
+
     def get_latest_version(opts)
       get_latest_github_release('denoland', 'deno', opts)
-      end
+    end
   end
 end

From 1ee7402a63458e2f39625234e3de6165346651d6 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 27 Nov 2024 15:18:00 +0100
Subject: [PATCH 087/384] Update Vite documentation (6.0.1)

---
 lib/docs/scrapers/vite.rb | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vite.rb b/lib/docs/scrapers/vite.rb
index e6ed520327..937d09161c 100644
--- a/lib/docs/scrapers/vite.rb
+++ b/lib/docs/scrapers/vite.rb
@@ -22,10 +22,15 @@ class Vite < UrlScraper
     html_filters.push 'vite/entries', 'vite/clean_html'
 
     version do
-      self.release = '5.4.11'
+      self.release = '6.0.1'
       self.base_url = 'https://vite.dev/'
     end
 
+    version '5' do
+      self.release = '5.4.11'
+      self.base_url = 'https://v5.vite.dev/'
+    end
+
     version '4' do
       self.release = '4.5.5'
       self.base_url = 'https://v4.vite.dev/'

From a332b8a1037b10b68164a848da2cae9fdbc2ea07 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 30 Nov 2024 11:37:09 +0100
Subject: [PATCH 088/384] Update VueUse documentation (12.0.0)

---
 lib/docs/scrapers/vueuse.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vueuse.rb b/lib/docs/scrapers/vueuse.rb
index baf90b65e2..3933b60c55 100644
--- a/lib/docs/scrapers/vueuse.rb
+++ b/lib/docs/scrapers/vueuse.rb
@@ -22,7 +22,7 @@ class Vueuse < UrlScraper
       Licensed under the MIT License.
     HTML
 
-    self.release = '11.0.0'
+    self.release = '12.0.0'
     self.base_url = 'https://vueuse.org/'
     self.initial_paths = %w(functions.html)
     html_filters.push 'vueuse/entries', 'vite/clean_html', 'vueuse/clean_html'

From 75cce72b3f51307ae2f7ae642e06b333a039c1de Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 13:11:35 +0100
Subject: [PATCH 089/384] basic scraping for Reference

---
 lib/docs/filters/react/clean_html_react_dev.rb | 11 +++++++++++
 lib/docs/filters/react/entries_react_dev.rb    | 13 +++++++++++++
 lib/docs/scrapers/react.rb                     | 14 +++++++++++++-
 3 files changed, 37 insertions(+), 1 deletion(-)
 create mode 100644 lib/docs/filters/react/clean_html_react_dev.rb
 create mode 100644 lib/docs/filters/react/entries_react_dev.rb

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
new file mode 100644
index 0000000000..6e1e9f5cdd
--- /dev/null
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -0,0 +1,11 @@
+module Docs
+  class React
+    class CleanHtmlReactDevFilter < Filter
+      def call
+        @doc = at_css('article')
+
+        doc
+      end
+    end
+  end
+end
diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
new file mode 100644
index 0000000000..5807985de0
--- /dev/null
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -0,0 +1,13 @@
+module Docs
+  class React
+    class EntriesReactDevFilter < Docs::EntriesFilter
+      def get_name
+        at_css('article h1').content
+      end
+
+      def get_type
+        return 'TODO add types'
+      end
+    end
+  end
+end
diff --git a/lib/docs/scrapers/react.rb b/lib/docs/scrapers/react.rb
index 7ef60cc19b..02133b177e 100644
--- a/lib/docs/scrapers/react.rb
+++ b/lib/docs/scrapers/react.rb
@@ -7,6 +7,19 @@ class React < UrlScraper
       code: 'https://github.com/facebook/react'
     }
 
+    version do
+      self.release = '18.3.1'
+      # TODO add /learn
+      self.base_url = 'https://react.dev/reference'
+
+      html_filters.push 'react/entries_react_dev', 'react/clean_html_react_dev'
+
+      options[:attribution] = <<-HTML
+        &copy; 2013&ndash;present Facebook Inc.<br>
+        Licensed under the Creative Commons Attribution 4.0 International Public License.
+      HTML
+    end
+
     version '17' do
       self.release = '17.0.2'
       self.base_url = 'https://17.reactjs.org/docs/'
@@ -33,7 +46,6 @@ class React < UrlScraper
       HTML
     end
 
-
     def get_latest_version(opts)
       doc = fetch_doc('https://react.dev/', opts)
       doc.at_css('a[href="/versions"]').content.strip[1..-1]

From 60c02cf69f65b8e1506cd701dd7917bf7363f7a4 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 14:00:20 +0100
Subject: [PATCH 090/384] remove stylings, breadcrumbs

---
 lib/docs/filters/react/clean_html_react_dev.rb | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index 6e1e9f5cdd..07c47726fc 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -4,6 +4,21 @@ class CleanHtmlReactDevFilter < Filter
       def call
         @doc = at_css('article')
 
+        # Remove breadcrumbs before h1
+        css('h1').each do |node|
+          node.previous.remove
+        end
+
+        # Remove prev-next links
+        css('div.grid > a').each do |node|
+          node.remove
+        end
+
+        # Remove styling divs
+        css('div[class*="ps-0"]', 'div[class*="mx-"]', 'div[class*="px-"]', 'div[class=""]', 'div.cm-line').each do |node|
+          node.before(node.children).remove
+        end
+
         doc
       end
     end

From 76af8247d108e33e9a2e80064065dac77331e8ba Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Dec 2024 18:28:51 +0100
Subject: [PATCH 091/384] Update Rust documentation (1.83.0)

---
 lib/docs/scrapers/rust.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/rust.rb b/lib/docs/scrapers/rust.rb
index 7f86985835..23419f5837 100644
--- a/lib/docs/scrapers/rust.rb
+++ b/lib/docs/scrapers/rust.rb
@@ -3,7 +3,7 @@
 module Docs
   class Rust < UrlScraper
     self.type = 'rust'
-    self.release = '1.80.0'
+    self.release = '1.83.0'
     self.base_url = 'https://doc.rust-lang.org/'
     self.root_path = 'book/index.html'
     self.initial_paths = %w(

From 6cff40e729360f3f883556bb438dbb54c09f956c Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 20:21:09 +0100
Subject: [PATCH 092/384] more styling removal

---
 .../filters/react/clean_html_react_dev.rb     | 22 +++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index 07c47726fc..fb77fa144a 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -9,13 +9,27 @@ def call
           node.previous.remove
         end
 
-        # Remove prev-next links
-        css('div.grid > a').each do |node|
+        remove_selectors = [
+          'div.grid > a', # prev-next links
+           'button', # "show more" etc. buttons
+           'div.order-last', # code iframe containers
+           'a[title="Open in CodeSandbox"]', # codesandbox links
+        ]
+        css(*remove_selectors).each do |node|
           node.remove
         end
 
-        # Remove styling divs
-        css('div[class*="ps-0"]', 'div[class*="mx-"]', 'div[class*="px-"]', 'div[class=""]', 'div.cm-line').each do |node|
+        # Remove recipe blocks - TODO transform to outgoing link to docs
+        css('h4[id^="examples-"]').each do |node|
+          node.parent.parent.parent.remove
+        end
+
+        # Remove styling divs while lifting children
+        styling_prefixes = [
+          'ps-', 'mx-', 'my-', 'px-', 'py-', 'mb-', 'sp-', 'rounded-'
+        ]
+        selectors = styling_prefixes.map { |prefix| "div[class*=\"#{prefix}\"]" }
+        css(*selectors, 'div[class=""]', 'div.cm-line').each do |node|
           node.before(node.children).remove
         end
 

From 42ec919cd8f0feaf07b34b82ee16d61da1fdf83d Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 20:28:11 +0100
Subject: [PATCH 093/384] syntax highlighting

---
 lib/docs/filters/react/clean_html_react_dev.rb | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index fb77fa144a..dc9dcae1c2 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -33,6 +33,14 @@ def call
           node.before(node.children).remove
         end
 
+        # Syntax highlighting
+        css('pre br').each do |node|
+          node.replace("\n")
+        end
+        css('pre').each do |node|
+          node['data-language'] = 'jsx'
+        end
+
         doc
       end
     end

From 30ddc7bbaf106320090def89f40f952be7733574 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 20:36:04 +0100
Subject: [PATCH 094/384] sanitize titles - experimental tag

---
 lib/docs/filters/react/entries_react_dev.rb | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 5807985de0..2264985bc8 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -2,7 +2,9 @@ module Docs
   class React
     class EntriesReactDevFilter < Docs::EntriesFilter
       def get_name
-        at_css('article h1').content
+        canary_copy = '- This feature is available in the latest Canary'
+        name = at_css('article h1').content
+        return name.sub(canary_copy, ' (experimental)')
       end
 
       def get_type

From ef1cc8a8bbe4540a9cc201475f12bf4690d746ca Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 20:40:52 +0100
Subject: [PATCH 095/384] update icon

---
 public/icons/docs/react/16.png    | Bin 495 -> 872 bytes
 public/icons/docs/react/16@2x.png | Bin 830 -> 1674 bytes
 public/icons/docs/react/SOURCE    |   4 ++--
 3 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/public/icons/docs/react/16.png b/public/icons/docs/react/16.png
index 2d384517115ac7b1e6ea4af427549d3fe34d01b1..d24cb4f7655c83c8ed5fa830839780edd75500c5 100644
GIT binary patch
diff --git a/public/icons/docs/react/16@2x.png b/public/icons/docs/react/16@2x.png
index 016a0c3c87d04e2e08cad9d60860f3068812290a..953ae4cc3aba0f0cc7cb93bdf5578d4caeb88bfd 100644
GIT binary patch
diff --git a/public/icons/docs/react/SOURCE b/public/icons/docs/react/SOURCE
index bfd02fd2f4..e1aa2f5547 100644
--- a/public/icons/docs/react/SOURCE
+++ b/public/icons/docs/react/SOURCE
@@ -1,2 +1,2 @@
-https://es.m.wikipedia.org/wiki/React#/media/Archivo%3AReact.svg
-https://github.com/facebook/react/blob/master/docs/img/logo.svg
\ No newline at end of file
+https://github.com/reactjs/react.dev/blob/master/public/favicon-16x16.png
+https://github.com/reactjs/react.dev/blob/master/public/favicon-32x32.png

From df398bd145f43dc953d751c4f722924930ec1c0f Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 20:51:49 +0100
Subject: [PATCH 096/384] add categories

---
 lib/docs/filters/react/entries_react_dev.rb | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 2264985bc8..0c49a6d8cb 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -4,11 +4,12 @@ class EntriesReactDevFilter < Docs::EntriesFilter
       def get_name
         canary_copy = '- This feature is available in the latest Canary'
         name = at_css('article h1').content
-        return name.sub(canary_copy, ' (experimental)')
+        return name.sub(canary_copy, ' (Experimental)')
       end
 
       def get_type
-        return 'TODO add types'
+        breadcrumb_nodes = css('a.tracking-wide')
+        return breadcrumb_nodes.last.content || 'Miscellaneous'
       end
     end
   end

From fefde4e15bf2a77d35cb58912c74659e4659b117 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 22:49:46 +0100
Subject: [PATCH 097/384] add Learn pages

---
 lib/docs/filters/react/clean_html_react_dev.rb |  4 +++-
 lib/docs/filters/react/entries_react_dev.rb    |  7 +++++--
 lib/docs/scrapers/react.rb                     | 10 ++++++++--
 3 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index dc9dcae1c2..954dd9b37c 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -6,7 +6,9 @@ def call
 
         # Remove breadcrumbs before h1
         css('h1').each do |node|
-          node.previous.remove
+          if (node.previous)
+            node.previous.remove
+          end
         end
 
         remove_selectors = [
diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 0c49a6d8cb..0fda0c5aba 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -4,12 +4,15 @@ class EntriesReactDevFilter < Docs::EntriesFilter
       def get_name
         canary_copy = '- This feature is available in the latest Canary'
         name = at_css('article h1').content
-        return name.sub(canary_copy, ' (Experimental)')
+        return name.sub(canary_copy, ' (Canary)')
       end
 
       def get_type
         breadcrumb_nodes = css('a.tracking-wide')
-        return breadcrumb_nodes.last.content || 'Miscellaneous'
+        category = breadcrumb_nodes.last.content
+        is_learn_page = base_url.to_s.end_with?('learn')
+        prefix = is_learn_page ? 'Learn: ' : ''
+        return prefix + (category || 'Miscellaneous')
       end
     end
   end
diff --git a/lib/docs/scrapers/react.rb b/lib/docs/scrapers/react.rb
index 02133b177e..a24798da7e 100644
--- a/lib/docs/scrapers/react.rb
+++ b/lib/docs/scrapers/react.rb
@@ -1,5 +1,7 @@
 module Docs
   class React < UrlScraper
+    include MultipleBaseUrls
+
     self.name = 'React'
     self.type = 'simple'
     self.links = {
@@ -9,8 +11,12 @@ class React < UrlScraper
 
     version do
       self.release = '18.3.1'
-      # TODO add /learn
-      self.base_url = 'https://react.dev/reference'
+      host = 'https://react.dev'
+      self.base_urls = [
+        "#{host}/reference",
+        "#{host}/learn",
+      ]
+      self.initial_paths = %w(/react)
 
       html_filters.push 'react/entries_react_dev', 'react/clean_html_react_dev'
 

From 33aba064c175c61274c329033cc64cc39b85aef8 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 23:18:53 +0100
Subject: [PATCH 098/384] use single base URL for working crosslinks

---
 lib/docs/filters/react/entries_react_dev.rb |  2 +-
 lib/docs/scrapers/react.rb                  | 11 ++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 0fda0c5aba..358d6a8d36 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -10,7 +10,7 @@ def get_name
       def get_type
         breadcrumb_nodes = css('a.tracking-wide')
         category = breadcrumb_nodes.last.content
-        is_learn_page = base_url.to_s.end_with?('learn')
+        is_learn_page = path.start_with?('learn/')
         prefix = is_learn_page ? 'Learn: ' : ''
         return prefix + (category || 'Miscellaneous')
       end
diff --git a/lib/docs/scrapers/react.rb b/lib/docs/scrapers/react.rb
index a24798da7e..a4f0e0fe74 100644
--- a/lib/docs/scrapers/react.rb
+++ b/lib/docs/scrapers/react.rb
@@ -1,6 +1,5 @@
 module Docs
   class React < UrlScraper
-    include MultipleBaseUrls
 
     self.name = 'React'
     self.type = 'simple'
@@ -11,15 +10,13 @@ class React < UrlScraper
 
     version do
       self.release = '18.3.1'
-      host = 'https://react.dev'
-      self.base_urls = [
-        "#{host}/reference",
-        "#{host}/learn",
-      ]
-      self.initial_paths = %w(/react)
+      self.base_url = 'https://react.dev'
+      self.initial_paths = %w(/reference/react /learn)
 
       html_filters.push 'react/entries_react_dev', 'react/clean_html_react_dev'
 
+      options[:only_patterns] = [/\A\/learn/, /\A\/reference/]
+
       options[:attribution] = <<-HTML
         &copy; 2013&ndash;present Facebook Inc.<br>
         Licensed under the Creative Commons Attribution 4.0 International Public License.

From 7be6b3e7c462526d351e0f92d2683facb7ba5b53 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Sun, 1 Dec 2024 23:19:00 +0100
Subject: [PATCH 099/384] strip styling

---
 lib/docs/filters/react/clean_html_react_dev.rb | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index 954dd9b37c..2a5ce8a2a8 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -43,6 +43,9 @@ def call
           node['data-language'] = 'jsx'
         end
 
+        # Remove styling
+        css('*').remove_attr('class').remove_attr('style')
+
         doc
       end
     end

From 2e1f0a046292f6eb087fc6421e633044a8fd2331 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Mon, 2 Dec 2024 08:07:04 +0100
Subject: [PATCH 100/384] Address top-level page categories

---
 lib/docs/filters/react/entries_react_dev.rb | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 358d6a8d36..6979448980 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -2,17 +2,27 @@ module Docs
   class React
     class EntriesReactDevFilter < Docs::EntriesFilter
       def get_name
-        canary_copy = '- This feature is available in the latest Canary'
         name = at_css('article h1').content
-        return name.sub(canary_copy, ' (Canary)')
+        return update_canary_copy(name)
       end
 
       def get_type
         breadcrumb_nodes = css('a.tracking-wide')
-        category = breadcrumb_nodes.last.content
+        is_top_level_page = breadcrumb_nodes.length == 1
+        category = if is_top_level_page
+          # Category is the opened category in the sidebar
+          css('aside a.text-link div').first.content
+        else
+          breadcrumb_nodes.last.content
+        end
         is_learn_page = path.start_with?('learn/')
         prefix = is_learn_page ? 'Learn: ' : ''
-        return prefix + (category || 'Miscellaneous')
+        return update_canary_copy(prefix + (category || 'Miscellaneous'))
+      end
+
+      def update_canary_copy(string)
+        canary_copy = '- This feature is available in the latest Canary'
+        return string.sub(canary_copy, ' (Canary)')
       end
     end
   end

From e2d5b5244e92471b42c06e85e669a509efb806fb Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 2 Dec 2024 23:00:25 +0000
Subject: [PATCH 101/384] chore(deps): update dependency nokogiri to v1.16.8

---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index a708f12b62..3de9ac4975 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -55,13 +55,13 @@ GEM
     in_threads (1.6.0)
     logger (1.6.1)
     method_source (1.0.0)
-    mini_portile2 (2.8.7)
+    mini_portile2 (2.8.8)
     minitest (5.25.2)
     multi_json (1.15.0)
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.16.7)
+    nokogiri (1.16.8)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From 6fdccb2a7b6601b3528493209e35151d27f76b72 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 3 Dec 2024 20:45:19 +0000
Subject: [PATCH 102/384] chore(deps): update dependency minitest to v5.25.3

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 3de9ac4975..31cd8a00fb 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -56,7 +56,7 @@ GEM
     logger (1.6.1)
     method_source (1.0.0)
     mini_portile2 (2.8.8)
-    minitest (5.25.2)
+    minitest (5.25.3)
     multi_json (1.15.0)
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)

From 47a59dcd3e7f251a098ed0e675458302a187b7b0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 4 Dec 2024 04:22:46 +0000
Subject: [PATCH 103/384] chore(deps): update dependency minitest to v5.25.4

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 31cd8a00fb..2d90145415 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -56,7 +56,7 @@ GEM
     logger (1.6.1)
     method_source (1.0.0)
     mini_portile2 (2.8.8)
-    minitest (5.25.3)
+    minitest (5.25.4)
     multi_json (1.15.0)
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)

From cc09d64fd52c68ce08298e681a67ad58d4684e51 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 6 Dec 2024 22:58:19 +0000
Subject: [PATCH 104/384] chore(deps): update ruby/setup-ruby action to
 v1.203.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a23e7a6cda..555c390dd6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
+      uses: ruby/setup-ruby@2a18b06812b0e15bb916e1df298d3e740422c47e # v1.203.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 75c174474a..28c3c459f3 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
+      uses: ruby/setup-ruby@2a18b06812b0e15bb916e1df298d3e740422c47e # v1.203.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f7bcde5334..3ab4e676c9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
+      uses: ruby/setup-ruby@2a18b06812b0e15bb916e1df298d3e740422c47e # v1.203.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From de294da7edc1def1beb0ce200e8034f11ded42c2 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 7 Dec 2024 16:16:33 +0100
Subject: [PATCH 105/384] Update Deno documentation (2.1.1)

---
 lib/docs/filters/deno/clean_html.rb | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/docs/filters/deno/clean_html.rb b/lib/docs/filters/deno/clean_html.rb
index 46fc16e424..c3b3230bb8 100644
--- a/lib/docs/filters/deno/clean_html.rb
+++ b/lib/docs/filters/deno/clean_html.rb
@@ -8,12 +8,20 @@ def call
           @doc = at_css('main article .markdown-body')
         end
 
+        if at_css('.text-2xl')
+          doc.prepend_child at_css('.text-2xl').remove
+          at_css('.text-2xl').name = 'h1'
+        end
+
         css('code').each do |node|
           if node['class']
             lang = node['class'][/language-(\w+)/, 1]
           end
           node['data-language'] = lang || 'ts'
           node.remove_attribute('class')
+          if node.parent.name == 'div'
+            node.content = node.content.strip
+          end
         end
 
         css('a.header-anchor').remove()

From 28ac0a119bb8239c267c55a81c5af8cf003fc459 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 7 Dec 2024 16:19:03 +0100
Subject: [PATCH 106/384] Update Git documentation (2.47.1)

---
 lib/docs/scrapers/git.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/git.rb b/lib/docs/scrapers/git.rb
index 5b0d57c408..d8a289c1cb 100644
--- a/lib/docs/scrapers/git.rb
+++ b/lib/docs/scrapers/git.rb
@@ -1,7 +1,7 @@
 module Docs
   class Git < UrlScraper
     self.type = 'git'
-    self.release = '2.46.0'
+    self.release = '2.47.1'
     self.base_url = 'https://git-scm.com/docs'
     self.initial_paths = %w(/git.html)
     self.links = {

From 1f9cce1a4aed350f5b39df780281dd610b2a5783 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 7 Dec 2024 16:20:07 +0100
Subject: [PATCH 107/384] Update TypeScript documentation (5.7.2)

---
 lib/docs/scrapers/typescript.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/typescript.rb b/lib/docs/scrapers/typescript.rb
index 34003a1626..59398c8717 100644
--- a/lib/docs/scrapers/typescript.rb
+++ b/lib/docs/scrapers/typescript.rb
@@ -45,7 +45,7 @@ def initial_urls
     HTML
 
     version do
-      self.release = '5.6.3'
+      self.release = '5.7.2'
       self.base_urls = [
         'https://www.typescriptlang.org/docs/handbook/',
         'https://www.typescriptlang.org/'

From c05094f52ac75ce54e2a0a07ef44b2436babd7b4 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 7 Dec 2024 16:24:10 +0100
Subject: [PATCH 108/384] Update Octave documentation (9.2.0)

---
 lib/docs/scrapers/octave.rb | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/docs/scrapers/octave.rb b/lib/docs/scrapers/octave.rb
index def6541e80..085d6fd804 100644
--- a/lib/docs/scrapers/octave.rb
+++ b/lib/docs/scrapers/octave.rb
@@ -29,6 +29,11 @@ class Octave < UrlScraper
       Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
     HTML
 
+    version '9' do
+      self.release = '9.2.0'
+      self.base_url = "https://docs.octave.org/v#{self.release}/"
+    end
+
     version '8' do
       self.release = '8.1.0'
       self.base_url = "https://docs.octave.org/v#{self.release}/"

From f6e5ac7426dfd22bac02d6c0c04d10525a6b0374 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 8 Dec 2024 11:32:52 +0100
Subject: [PATCH 109/384] Update i3 documentation (4.24)

---
 lib/docs/scrapers/i3.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/i3.rb b/lib/docs/scrapers/i3.rb
index 8be9d35e30..899a718acf 100644
--- a/lib/docs/scrapers/i3.rb
+++ b/lib/docs/scrapers/i3.rb
@@ -3,7 +3,7 @@ class I3 < UrlScraper
     self.name = 'i3'
     self.type = 'simple'
     self.slug = 'i3'
-    self.release = '4.23'
+    self.release = '4.24'
     self.base_url = 'https://i3wm.org/docs/userguide.html'
     self.links = {
       home: 'https://i3wm.org/',

From 7d2346cbcc0af30cad211d916d23a950a3851e85 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 8 Dec 2024 11:33:55 +0100
Subject: [PATCH 110/384] Update Prettier documentation (3.4.2)

---
 lib/docs/scrapers/prettier.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/prettier.rb b/lib/docs/scrapers/prettier.rb
index 1660a7fdd9..98fbafa1c7 100644
--- a/lib/docs/scrapers/prettier.rb
+++ b/lib/docs/scrapers/prettier.rb
@@ -2,7 +2,7 @@ module Docs
   class Prettier < UrlScraper
     self.name = 'Prettier'
     self.type = 'simple'
-    self.release = '3.3.3'
+    self.release = '3.4.2'
     self.base_url = 'https://prettier.io/docs/en/'
     self.links = {
       home: 'https://prettier.io/',

From 4096bf94190321a76deaf68e398ff3e4ef69cbd2 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 8 Dec 2024 11:48:25 +0100
Subject: [PATCH 111/384] Update GCC documentation (14.2.0)

---
 lib/docs/filters/gnu/clean_html.rb   |  3 +++
 lib/docs/filters/gnu/entries.rb      |  1 +
 lib/docs/scrapers/gnu/gcc.rb         | 14 ++++++++++++--
 lib/docs/scrapers/gnu/gnu_fortran.rb |  7 ++++++-
 4 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/lib/docs/filters/gnu/clean_html.rb b/lib/docs/filters/gnu/clean_html.rb
index 4697126624..2966198c1c 100644
--- a/lib/docs/filters/gnu/clean_html.rb
+++ b/lib/docs/filters/gnu/clean_html.rb
@@ -2,7 +2,10 @@ module Docs
   class Gnu
     class CleanHtmlFilter < Filter
       def call
+        css('.nav-panel', '.copiable-link').remove
         heading = at_css('h1, h2, h3, h4, h5')
+        heading.content = heading.content
+        doc.prepend_child heading.remove
         heading_level = heading.name[/h(\d)/, 1].to_i
 
         css('h2, h3, h4, h5, h6').each do |node|
diff --git a/lib/docs/filters/gnu/entries.rb b/lib/docs/filters/gnu/entries.rb
index 5e3aab48ed..d17e543883 100644
--- a/lib/docs/filters/gnu/entries.rb
+++ b/lib/docs/filters/gnu/entries.rb
@@ -11,6 +11,7 @@ def initialize(*)
       def get_name
         name = at_css('h1').content
         name.sub! %r{\A([\d\.]*\d)}, '\1.'
+        name.remove! %r{\s*¶}
         name.split('—').first.strip
       end
 
diff --git a/lib/docs/scrapers/gnu/gcc.rb b/lib/docs/scrapers/gnu/gcc.rb
index 732e88e826..2d19b1204e 100644
--- a/lib/docs/scrapers/gnu/gcc.rb
+++ b/lib/docs/scrapers/gnu/gcc.rb
@@ -46,13 +46,23 @@ class Gcc < Gnu
       'Wtrigraphs.html' => 'Invocation.html'
     }
 
+    version '14' do
+      self.release = '14.2.0'
+      self.base_url = "https://gcc.gnu.org/onlinedocs/gcc-#{release}/gcc/"
+    end
+
+    version '14 CPP' do
+      self.release = '14.2.0'
+      self.base_url = "https://gcc.gnu.org/onlinedocs/gcc-#{release}/cpp/"
+    end
+
     version '13' do
-      self.release = '13.1.0'
+      self.release = '13.3.0'
       self.base_url = "https://gcc.gnu.org/onlinedocs/gcc-#{release}/gcc/"
     end
 
     version '13 CPP' do
-      self.release = '13.1.0'
+      self.release = '13.3.0'
       self.base_url = "https://gcc.gnu.org/onlinedocs/gcc-#{release}/cpp/"
     end
 
diff --git a/lib/docs/scrapers/gnu/gnu_fortran.rb b/lib/docs/scrapers/gnu/gnu_fortran.rb
index 757db49a3c..43e3f4f404 100644
--- a/lib/docs/scrapers/gnu/gnu_fortran.rb
+++ b/lib/docs/scrapers/gnu/gnu_fortran.rb
@@ -6,8 +6,13 @@ class GnuFortran < Gnu
       home: 'https://gcc.gnu.org/fortran/'
     }
 
+    version '14' do
+      self.release = '14.2.0'
+      self.base_url = "https://gcc.gnu.org/onlinedocs/gcc-#{release}/gfortran/"
+    end
+
     version '13' do
-      self.release = '13.1.0'
+      self.release = '13.3.0'
       self.base_url = "https://gcc.gnu.org/onlinedocs/gcc-#{release}/gfortran/"
     end
 

From 9a2cab305083a941b3c345b7ae6c437cd56d5b68 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 8 Dec 2024 11:51:18 +0100
Subject: [PATCH 112/384] Update Julia documentation (1.11.2)

---
 lib/docs/scrapers/julia.rb | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/julia.rb b/lib/docs/scrapers/julia.rb
index c31cdaea90..dc8d78a984 100644
--- a/lib/docs/scrapers/julia.rb
+++ b/lib/docs/scrapers/julia.rb
@@ -7,12 +7,23 @@ class Julia < UrlScraper
 
 
     options[:attribution] = <<-HTML
-      &copy; 2009&ndash;2023 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors<br>
+      &copy; 2009&ndash;2024 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors<br>
       Licensed under the MIT License.
     HTML
 
+    version '1.11' do
+      self.release = '1.11.2'
+      self.base_url = "https://docs.julialang.org/en/v#{version}/"
+      self.type = 'julia'
+
+      html_filters.push 'julia/entries', 'julia/clean_html'
+
+      options[:container] = '.docs-main'
+      options[:only_patterns] = [/\Amanual\//, /\Abase\//, /\Astdlib\//]
+    end
+
     version '1.10' do
-      self.release = '1.10.0.2'
+      self.release = '1.10.7'
       self.base_url = "https://docs.julialang.org/en/v#{version}/"
       self.type = 'julia'
 

From 9bdd8f6fd17f2f04042874660e7b45fcd5d8d140 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 8 Dec 2024 11:53:00 +0100
Subject: [PATCH 113/384] Update webpack documentation (5.97.1)

---
 lib/docs/scrapers/webpack.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/webpack.rb b/lib/docs/scrapers/webpack.rb
index 9980341e87..4d5c60fb2d 100644
--- a/lib/docs/scrapers/webpack.rb
+++ b/lib/docs/scrapers/webpack.rb
@@ -36,7 +36,7 @@ class Webpack < UrlScraper
     HTML
 
     version '5' do
-      self.release = '5.89.0'
+      self.release = '5.97.1'
       self.base_url = 'https://webpack.js.org/'
     end
 

From 7f33327fc57cdc0988fdffef7c327615822763b4 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 8 Dec 2024 12:38:51 +0100
Subject: [PATCH 114/384] Update Sass documentation (1.82.9)

---
 assets/stylesheets/pages/_yard.scss | 17 ++++++++++++++++-
 lib/docs/filters/sass/clean_html.rb | 18 +++++++++++-------
 lib/docs/scrapers/sass.rb           | 12 ++++++++----
 3 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/assets/stylesheets/pages/_yard.scss b/assets/stylesheets/pages/_yard.scss
index bb2fbc47c2..195059f768 100644
--- a/assets/stylesheets/pages/_yard.scss
+++ b/assets/stylesheets/pages/_yard.scss
@@ -1,5 +1,20 @@
 ._yard {
   @extend %simple;
 
-  .tag_title { font-weight: var(--boldFontWeight); }
+  .tag_title {
+    font-weight: var(--boldFontWeight);
+  }
+
+  .sl-c-description-list--horizontal * {
+    display: inline-block;
+    padding: 0;
+    margin: 0;
+    dt {
+      margin-left: 1rem;
+    }
+  }
+
+  .sl-c-callout--warning {
+    @extend %note, %note-orange;
+  }
 }
diff --git a/lib/docs/filters/sass/clean_html.rb b/lib/docs/filters/sass/clean_html.rb
index 5b17d4a9bd..d1b7bcb270 100644
--- a/lib/docs/filters/sass/clean_html.rb
+++ b/lib/docs/filters/sass/clean_html.rb
@@ -5,14 +5,13 @@ def call
         @doc = at_css('#main-content .typedoc', '#main-content')
 
         css('.sl-c-alert').remove
-
         css('.sl-l-medium-holy-grail__navigation').remove
-
         css('.sl-r-banner').remove
-
         css('.site-footer').remove
-
         css('.tsd-breadcrumb').remove
+        css('.sl-c-callout--warning > h3').remove
+        css('.ui-tabs-nav').remove
+        css('.sl-c-to-playground').remove
 
         # Add id to code blocks
         css('pre.signature').each do |node|
@@ -42,14 +41,19 @@ def call
         css('.visuallyhidden').remove
 
         ### Syntax Highlight ###
-        css('.highlight.scss', '.highlight.sass').each do |node|
+        css('.language-scss').each do |node|
           node['data-language'] = 'scss'
           node.content = node.content.strip
         end
 
-        css('.highlight.css').each do |node|
+        css('.language-sass').each do |node|
+          node['data-language'] = 'sass'
+          node.content = "// SASS\n#{node.content.strip}"
+        end
+
+        css('.language-css').each do |node|
           node['data-language'] = 'css'
-          node.content = node.content.strip
+          node.content = "/* CSS */\n#{node.content.strip}"
         end
 
         doc
diff --git a/lib/docs/scrapers/sass.rb b/lib/docs/scrapers/sass.rb
index 90be9e0539..d7b5954a08 100644
--- a/lib/docs/scrapers/sass.rb
+++ b/lib/docs/scrapers/sass.rb
@@ -1,7 +1,7 @@
 module Docs
   class Sass < UrlScraper
     self.type = 'yard'
-    self.release = '1.56.1'
+    self.release = '1.82.9'
     self.base_url = 'https://sass-lang.com/documentation'
     self.root_path = 'index.html'
     self.links = {
@@ -14,17 +14,21 @@ class Sass < UrlScraper
     options[:root_title] = false
 
     options[:skip_patterns] = [/breaking-changes/]
-
-    # options[:container] = '#main-content'
+    options[:trailing_slash] = false
 
     options[:attribution] = <<-HTML
-      &copy; 2006&ndash;2022 the Sass team, and numerous contributors<br>
+      &copy; 2006&ndash;2024 the Sass team, and numerous contributors<br>
       Licensed under the MIT License.
     HTML
+  
+    private
 
     def get_latest_version(opts)
       get_npm_version('sass', opts)
     end
 
+    def parse(response)
+      response.body.gsub! '<span class="widont">&nbsp;</span>', '&nbsp;'
+    end
   end
 end

From cf97ef05b78ad25a5b4b715e591f43a52dcac51e Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 8 Dec 2024 12:45:14 +0100
Subject: [PATCH 115/384] Update Python documentation (3.13.1)

---
 lib/docs/scrapers/python.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/python.rb b/lib/docs/scrapers/python.rb
index bd2c1dc176..9334e91433 100644
--- a/lib/docs/scrapers/python.rb
+++ b/lib/docs/scrapers/python.rb
@@ -28,7 +28,7 @@ class Python < UrlScraper
     HTML
 
     version '3.13' do
-      self.release = '3.13.0'
+      self.release = '3.13.1'
       self.base_url = "https://docs.python.org/#{self.version}/"
 
       html_filters.push 'python/entries_v3', 'sphinx/clean_html', 'python/clean_html'

From 29b9acbaf7196b59f555b387d0cd1992da9331da Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 8 Dec 2024 21:21:02 +0000
Subject: [PATCH 116/384] chore(deps): update dependency nokogiri to v1.17.0

---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 2d90145415..9f91251e25 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -61,7 +61,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.16.8)
+    nokogiri (1.17.0)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)
@@ -75,7 +75,7 @@ GEM
     pry-byebug (3.10.1)
       byebug (~> 11.0)
       pry (>= 0.13, < 0.15)
-    racc (1.7.3)
+    racc (1.8.1)
     rack (2.2.10)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)

From 7a510f6d8b127dd696492992b5079b12b8ef43c9 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Tue, 10 Dec 2024 21:56:00 +0100
Subject: [PATCH 117/384] remove dark images

---
 lib/docs/filters/react/clean_html_react_dev.rb | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index 2a5ce8a2a8..3371089aca 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -13,14 +13,18 @@ def call
 
         remove_selectors = [
           'div.grid > a', # prev-next links
-           'button', # "show more" etc. buttons
-           'div.order-last', # code iframe containers
-           'a[title="Open in CodeSandbox"]', # codesandbox links
+          'button', # "show more" etc. buttons
+          'div.order-last', # code iframe containers
+          'div.dark-image', # dark images
+          'a[title="Open in CodeSandbox"]', # codesandbox links
         ]
         css(*remove_selectors).each do |node|
           node.remove
         end
 
+        # Fix images not loading
+        css('img').remove_attr('srcset')
+
         # Remove recipe blocks - TODO transform to outgoing link to docs
         css('h4[id^="examples-"]').each do |node|
           node.parent.parent.parent.remove

From 94a7aa3c3447918caa94ddbad73a87eb8a686184 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Tue, 10 Dec 2024 23:13:26 +0100
Subject: [PATCH 118/384] use better top-level categories

---
 .../filters/react/clean_html_react_dev.rb     |  4 +---
 lib/docs/filters/react/entries_react_dev.rb   | 22 +++++++++----------
 2 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index 3371089aca..f8a27bcc78 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -31,9 +31,7 @@ def call
         end
 
         # Remove styling divs while lifting children
-        styling_prefixes = [
-          'ps-', 'mx-', 'my-', 'px-', 'py-', 'mb-', 'sp-', 'rounded-'
-        ]
+        styling_prefixes = %w[ps- mx- my- px- py- mb- sp- rounded-]
         selectors = styling_prefixes.map { |prefix| "div[class*=\"#{prefix}\"]" }
         css(*selectors, 'div[class=""]', 'div.cm-line').each do |node|
           node.before(node.children).remove
diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 6979448980..59dcd33438 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -2,21 +2,21 @@ module Docs
   class React
     class EntriesReactDevFilter < Docs::EntriesFilter
       def get_name
-        name = at_css('article h1').content
+        name = at_css('article h1')&.content
         return update_canary_copy(name)
       end
 
       def get_type
-        breadcrumb_nodes = css('a.tracking-wide')
-        is_top_level_page = breadcrumb_nodes.length == 1
-        category = if is_top_level_page
-          # Category is the opened category in the sidebar
-          css('aside a.text-link div').first.content
-        else
-          breadcrumb_nodes.last.content
-        end
-        is_learn_page = path.start_with?('learn/')
-        prefix = is_learn_page ? 'Learn: ' : ''
+        # Category is the opened category in the sidebar
+        category = css('a:has(> span.text-link) > div').first&.content
+        # The grey category in the sidebar
+        top_category = css('h3:has(~ li a.text-link)')
+                         .last&.content
+                         &.sub(/@.*$/, '') # remove version tag
+                         &.sub(/^./, &:upcase) # capitalize first letter
+                         &.concat(": ")
+        is_learn_page = path.start_with?('learn/') || slug == 'learn'
+        prefix = is_learn_page ? 'Learn: ' : top_category
         return update_canary_copy(prefix + (category || 'Miscellaneous'))
       end
 

From afd18f66af52e9dd0e51ab4834ea276d5ddad51b Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Wed, 11 Dec 2024 00:22:23 +0100
Subject: [PATCH 119/384] treat properly callouts

---
 assets/stylesheets/application.css.scss       |  1 +
 assets/stylesheets/pages/_react.scss          | 20 ++++++++++++++
 docs/adding-docs.md                           |  2 +-
 .../filters/react/clean_html_react_dev.rb     | 27 ++++++++++++++++---
 lib/docs/filters/react/entries_react_dev.rb   |  2 +-
 lib/docs/scrapers/react.rb                    |  2 +-
 6 files changed, 48 insertions(+), 6 deletions(-)
 create mode 100644 assets/stylesheets/pages/_react.scss

diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss
index dc2ee648da..3823cdc3d8 100644
--- a/assets/stylesheets/application.css.scss
+++ b/assets/stylesheets/application.css.scss
@@ -109,6 +109,7 @@
         'pages/qt',
         'pages/ramda',
         'pages/rdoc',
+        'pages/react',
         'pages/react_native',
         'pages/reactivex',
         'pages/redis',
diff --git a/assets/stylesheets/pages/_react.scss b/assets/stylesheets/pages/_react.scss
new file mode 100644
index 0000000000..e9f79b8487
--- /dev/null
+++ b/assets/stylesheets/pages/_react.scss
@@ -0,0 +1,20 @@
+._react {
+  @extend %simple;
+
+  .note {
+    @extend %note;
+  }
+
+  .note-orange {
+    @extend %note-orange;
+  }
+
+  .note-blue {
+    @extend %note-blue;
+  }
+
+  .note-green {
+    @extend %note-green;
+  }
+
+}
diff --git a/docs/adding-docs.md b/docs/adding-docs.md
index 971b91bece..5051d5ee31 100644
--- a/docs/adding-docs.md
+++ b/docs/adding-docs.md
@@ -13,7 +13,7 @@ Adding a documentation may look like a daunting task but once you get the hang o
 6. Generate the full documentation using the `thor docs:generate [my_doc] --force` command. Additionally, you can use the `--verbose` option to see which files are being created/updated/deleted (useful to see what changed since the last run), and the `--debug` option to see which URLs are being requested and added to the queue (useful to pin down which page adds unwanted URLs to the queue).
 7. Start the server, open the app, enable the documentation, and see how everything plays out.
 8. Tweak the scraper/filters and repeat 5) and 6) until the pages and metadata are ok.
-9. To customize the pages' styling, create an SCSS file in the `assets/stylesheets/pages/` directory and import it in both `application.css.scss` AND `application-dark.css.scss`. Both the file and CSS class should be named `_[type]` where [type] is equal to the scraper's `type` attribute (documentations with the same type share the same custom CSS and JS). Setting the type to `simple` will apply the general styling rules in `assets/stylesheets/pages/_simple.scss`, which can be used for documentations where little to no CSS changes are needed.
+9. To customize the pages' styling, create an SCSS file in the `assets/stylesheets/pages/` directory and import it in `application.css.scss`. Both the file and CSS class should be named `_[type]` where [type] is equal to the scraper's `type` attribute (documentations with the same type share the same custom CSS and JS). Setting the type to `simple` will apply the general styling rules in `assets/stylesheets/pages/_simple.scss`, which can be used for documentations where little to no CSS changes are needed.
 10. To add syntax highlighting or execute custom JavaScript on the pages, create a file in the `assets/javascripts/views/pages/` directory (take a look at the other files to see how it works).
 11. Add the documentation's icon in the `public/icons/docs/[my_doc]/` directory, in both 16x16 and 32x32-pixels formats. The icon spritesheet is automatically generated when you (re)start your local DevDocs instance.
 12. Add the documentation's copyright details to `options[:attribution]`. This is the data shown in the table on the [about](https://devdocs.io/about) page, and is ordered alphabetically. Please see an existing scraper for the typesetting.
diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index f8a27bcc78..77c2ae9f65 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -30,9 +30,30 @@ def call
           node.parent.parent.parent.remove
         end
 
+        # Transform callout blocks
+        class_transform = {
+          '.expandable-callout[class*=yellow]' => 'note note-orange', # pitfalls, experimental
+          '.expandable-callout[class*=green]' => 'note note-green', # note
+          '.bg-card' => 'note', # you will learn
+          'details' => 'note note-blue' # deep dive
+        }
+
+        class_transform.each do |old_class, new_class|
+          css(old_class).each do |node|
+            node.set_attribute('class', new_class)
+          end
+        end
+
+        # Transform h3 to h4 inside callouts
+        css('.note h3').each do |node|
+          new_node = Nokogiri::XML::Node.new('h4', @doc)
+          new_node.content = node.content
+          node.replace(new_node)
+        end
+
         # Remove styling divs while lifting children
         styling_prefixes = %w[ps- mx- my- px- py- mb- sp- rounded-]
-        selectors = styling_prefixes.map { |prefix| "div[class*=\"#{prefix}\"]" }
+        selectors = styling_prefixes.map { |prefix| "div[class*=\"#{prefix}\"]:not(.note)" }
         css(*selectors, 'div[class=""]', 'div.cm-line').each do |node|
           node.before(node.children).remove
         end
@@ -45,8 +66,8 @@ def call
           node['data-language'] = 'jsx'
         end
 
-        # Remove styling
-        css('*').remove_attr('class').remove_attr('style')
+        # Remove styling except for callouts and images
+        css('*:not([class*=image]):not(.note)').remove_attr('class').remove_attr('style')
 
         doc
       end
diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 59dcd33438..80b5aad064 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -16,7 +16,7 @@ def get_type
                          &.sub(/^./, &:upcase) # capitalize first letter
                          &.concat(": ")
         is_learn_page = path.start_with?('learn/') || slug == 'learn'
-        prefix = is_learn_page ? 'Learn: ' : top_category
+        prefix = is_learn_page ? 'Learn: ' : top_category || ''
         return update_canary_copy(prefix + (category || 'Miscellaneous'))
       end
 
diff --git a/lib/docs/scrapers/react.rb b/lib/docs/scrapers/react.rb
index a4f0e0fe74..d89cf6cb28 100644
--- a/lib/docs/scrapers/react.rb
+++ b/lib/docs/scrapers/react.rb
@@ -2,7 +2,7 @@ module Docs
   class React < UrlScraper
 
     self.name = 'React'
-    self.type = 'simple'
+    self.type = 'react'
     self.links = {
       home: 'https://react.dev/',
       code: 'https://github.com/facebook/react'

From 70c5489f52fb29a7b280f817baff9cde874b3952 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Wed, 11 Dec 2024 00:45:43 +0100
Subject: [PATCH 120/384] add search entries

---
 lib/docs/filters/react/entries_react_dev.rb | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 80b5aad064..f3efff4bf3 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -24,6 +24,18 @@ def update_canary_copy(string)
         canary_copy = '- This feature is available in the latest Canary'
         return string.sub(canary_copy, ' (Canary)')
       end
+
+      def additional_entries
+        excluded = %w(usage troubleshooting recap reference challenges alternatives)
+        entries =  []
+        css('article h2, article h3').map do |node|
+          next unless node.has_attribute?('id')
+          name = node.content.strip
+          next if excluded.include?(name.downcase)
+          entries << [name, node['id'], type]
+        end
+        return entries
+      end
     end
   end
 end

From ceaf48b4ba568bb711f02e4e647d718ee53c9ec4 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Wed, 11 Dec 2024 00:48:27 +0100
Subject: [PATCH 121/384] fix Canary callouts

---
 lib/docs/filters/react/clean_html_react_dev.rb | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index 77c2ae9f65..28cff5a4f8 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -34,6 +34,7 @@ def call
         class_transform = {
           '.expandable-callout[class*=yellow]' => 'note note-orange', # pitfalls, experimental
           '.expandable-callout[class*=green]' => 'note note-green', # note
+          '.expandable-callout[class*=gray]' => 'note', # canary
           '.bg-card' => 'note', # you will learn
           'details' => 'note note-blue' # deep dive
         }

From d6df6b5135bcbc33da292672d41fb0ddc66e8a64 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Wed, 11 Dec 2024 00:50:04 +0100
Subject: [PATCH 122/384] nice callout margins

---
 assets/stylesheets/pages/_react.scss | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/assets/stylesheets/pages/_react.scss b/assets/stylesheets/pages/_react.scss
index e9f79b8487..6bb32bdfe2 100644
--- a/assets/stylesheets/pages/_react.scss
+++ b/assets/stylesheets/pages/_react.scss
@@ -3,6 +3,10 @@
 
   .note {
     @extend %note;
+    h4 {
+      margin-top: .25rem;
+      margin-bottom: .5rem;
+    }
   }
 
   .note-orange {

From d8eb56811e2abe3dfbcbc18921f7ee6e1adc8ed5 Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Wed, 11 Dec 2024 00:51:10 +0100
Subject: [PATCH 123/384] fix warnings

---
 lib/docs/filters/react/clean_html_react_dev.rb |  2 +-
 lib/docs/filters/react/entries_react_dev.rb    | 12 ++++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index 28cff5a4f8..b593b09f3f 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -6,7 +6,7 @@ def call
 
         # Remove breadcrumbs before h1
         css('h1').each do |node|
-          if (node.previous)
+          if node.previous
             node.previous.remove
           end
         end
diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index f3efff4bf3..39edd7c987 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -3,7 +3,8 @@ class React
     class EntriesReactDevFilter < Docs::EntriesFilter
       def get_name
         name = at_css('article h1')&.content
-        return update_canary_copy(name)
+
+        update_canary_copy(name)
       end
 
       def get_type
@@ -17,12 +18,14 @@ def get_type
                          &.concat(": ")
         is_learn_page = path.start_with?('learn/') || slug == 'learn'
         prefix = is_learn_page ? 'Learn: ' : top_category || ''
-        return update_canary_copy(prefix + (category || 'Miscellaneous'))
+
+        update_canary_copy(prefix + (category || 'Miscellaneous'))
       end
 
       def update_canary_copy(string)
         canary_copy = '- This feature is available in the latest Canary'
-        return string.sub(canary_copy, ' (Canary)')
+
+        string.sub(canary_copy, ' (Canary)')
       end
 
       def additional_entries
@@ -34,7 +37,8 @@ def additional_entries
           next if excluded.include?(name.downcase)
           entries << [name, node['id'], type]
         end
-        return entries
+
+        entries
       end
     end
   end

From e67408b63ef6ebf32c6e271c616567300a3e49bd Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Wed, 11 Dec 2024 00:55:37 +0100
Subject: [PATCH 124/384] remove additional entries

---
 lib/docs/filters/react/entries_react_dev.rb | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/lib/docs/filters/react/entries_react_dev.rb b/lib/docs/filters/react/entries_react_dev.rb
index 39edd7c987..ce6da0e056 100644
--- a/lib/docs/filters/react/entries_react_dev.rb
+++ b/lib/docs/filters/react/entries_react_dev.rb
@@ -27,19 +27,6 @@ def update_canary_copy(string)
 
         string.sub(canary_copy, ' (Canary)')
       end
-
-      def additional_entries
-        excluded = %w(usage troubleshooting recap reference challenges alternatives)
-        entries =  []
-        css('article h2, article h3').map do |node|
-          next unless node.has_attribute?('id')
-          name = node.content.strip
-          next if excluded.include?(name.downcase)
-          entries << [name, node['id'], type]
-        end
-
-        entries
-      end
     end
   end
 end

From 0a1b28762201db26f836372db08f27a276d0fdef Mon Sep 17 00:00:00 2001
From: Gergely Gombos <gombosg@disroot.org>
Date: Wed, 11 Dec 2024 01:00:01 +0100
Subject: [PATCH 125/384] fix Ready to learn

---
 lib/docs/filters/react/clean_html_react_dev.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/filters/react/clean_html_react_dev.rb b/lib/docs/filters/react/clean_html_react_dev.rb
index b593b09f3f..1ad201cd34 100644
--- a/lib/docs/filters/react/clean_html_react_dev.rb
+++ b/lib/docs/filters/react/clean_html_react_dev.rb
@@ -46,7 +46,7 @@ def call
         end
 
         # Transform h3 to h4 inside callouts
-        css('.note h3').each do |node|
+        css('.note h3', '.note h2').each do |node|
           new_node = Nokogiri::XML::Node.new('h4', @doc)
           new_node.content = node.content
           node.replace(new_node)

From 7d2643260d1b9623624e454e8ae70603602230a3 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 12 Dec 2024 08:53:09 +0100
Subject: [PATCH 126/384] Update React documentation (19)

---
 lib/docs/scrapers/react.rb | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/lib/docs/scrapers/react.rb b/lib/docs/scrapers/react.rb
index d89cf6cb28..9bc1249cd5 100644
--- a/lib/docs/scrapers/react.rb
+++ b/lib/docs/scrapers/react.rb
@@ -8,19 +8,27 @@ class React < UrlScraper
       code: 'https://github.com/facebook/react'
     }
 
+    options[:attribution] = <<-HTML
+      &copy; 2013&ndash;present Facebook Inc.<br>
+      Licensed under the Creative Commons Attribution 4.0 International Public License.
+    HTML
+
     version do
-      self.release = '18.3.1'
+      self.release = '19'
       self.base_url = 'https://react.dev'
       self.initial_paths = %w(/reference/react /learn)
-
       html_filters.push 'react/entries_react_dev', 'react/clean_html_react_dev'
 
       options[:only_patterns] = [/\A\/learn/, /\A\/reference/]
+    end
+
+    version '18' do
+      self.release = '18.3.1'
+      self.base_url = 'https://18.react.dev'
+      self.initial_paths = %w(/reference/react /learn)
+      html_filters.push 'react/entries_react_dev', 'react/clean_html_react_dev'
 
-      options[:attribution] = <<-HTML
-        &copy; 2013&ndash;present Facebook Inc.<br>
-        Licensed under the Creative Commons Attribution 4.0 International Public License.
-      HTML
+      options[:only_patterns] = [/\A\/learn/, /\A\/reference/]
     end
 
     version '17' do
@@ -42,11 +50,6 @@ class React < UrlScraper
         'working-with-the-browser.html' => 'refs-and-the-dom.html',
         'top-level-api.html' => 'react-api.html',
       }
-
-      options[:attribution] = <<-HTML
-        &copy; 2013&ndash;present Facebook Inc.<br>
-        Licensed under the Creative Commons Attribution 4.0 International Public License.
-      HTML
     end
 
     def get_latest_version(opts)

From b0808fc0b3360346ba23f18da3d931debe46fcee Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 12 Dec 2024 07:55:32 +0000
Subject: [PATCH 127/384] chore(deps): update dependency activesupport to
 v7.2.2.1

---
 Gemfile.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 9f91251e25..540498e6c7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    activesupport (7.2.2)
+    activesupport (7.2.2.1)
       base64
       benchmark (>= 0.3)
       bigdecimal
@@ -53,7 +53,7 @@ GEM
       image_optim (~> 0.19)
     image_size (3.3.0)
     in_threads (1.6.0)
-    logger (1.6.1)
+    logger (1.6.2)
     method_source (1.0.0)
     mini_portile2 (2.8.8)
     minitest (5.25.4)
@@ -99,7 +99,7 @@ GEM
     sass-listen (4.0.0)
       rb-fsevent (~> 0.9, >= 0.9.4)
       rb-inotify (~> 0.9, >= 0.9.7)
-    securerandom (0.3.1)
+    securerandom (0.3.2)
     sinatra (3.2.0)
       mustermann (~> 3.0)
       rack (~> 2.2, >= 2.2.4)

From 5f77bcb2d59763ba122825ff23bd5d2e1a555ff1 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 12 Dec 2024 10:29:04 +0000
Subject: [PATCH 128/384] chore(deps): update dependency nokogiri to v1.17.1

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 540498e6c7..21689a96a8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -61,7 +61,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.17.0)
+    nokogiri (1.17.1)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From ad61caf6d0a52f6bfebc271ca0e395652e904b42 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 12 Dec 2024 23:03:56 +0000
Subject: [PATCH 129/384] chore(deps): update dependency nokogiri to v1.17.2

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 21689a96a8..078caf94ab 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -61,7 +61,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.17.1)
+    nokogiri (1.17.2)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From 51cbc24f22e0ca53a7c02a25af5f9ceb1920d6e1 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 13 Dec 2024 19:50:41 +0000
Subject: [PATCH 130/384] chore(deps): update ruby/setup-ruby action to
 v1.204.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 555c390dd6..4eefc897f9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2a18b06812b0e15bb916e1df298d3e740422c47e # v1.203.0
+      uses: ruby/setup-ruby@401c19e14f474b54450cd3905bb8b86e2c8509cf # v1.204.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 28c3c459f3..9f92295c57 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2a18b06812b0e15bb916e1df298d3e740422c47e # v1.203.0
+      uses: ruby/setup-ruby@401c19e14f474b54450cd3905bb8b86e2c8509cf # v1.204.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 3ab4e676c9..8b1ae487b5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2a18b06812b0e15bb916e1df298d3e740422c47e # v1.203.0
+      uses: ruby/setup-ruby@401c19e14f474b54450cd3905bb8b86e2c8509cf # v1.204.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 255207f7a6cd411ffd126339793efdaefa916ac4 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Fri, 13 Dec 2024 23:54:12 -0600
Subject: [PATCH 131/384] feat: add the GitHub action to create a Docker image
 and push to Docker's registry

---
 .github/workflows/docker-build.yml | 57 ++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 .github/workflows/docker-build.yml

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
new file mode 100644
index 0000000000..425c679ee2
--- /dev/null
+++ b/.github/workflows/docker-build.yml
@@ -0,0 +1,57 @@
+name: Build and Push Docker Images
+
+on:
+  schedule:
+    - cron: '0 0 1 * *'  # Run monthly on the 1st
+  workflow_dispatch:  # Allow manual triggers
+
+env:
+  REGISTRY: ghcr.io
+  IMAGE_NAME: ${{ github.repository }}
+
+jobs:
+  build-and-push:
+    runs-on: ubuntu-latest
+    permissions:
+      contents: read
+      packages: write
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      - name: Log in to the Container registry
+        uses: docker/login-action@v3
+        with:
+          registry: ${{ env.REGISTRY }}
+          username: ${{ github.actor }}
+          password: ${{ secrets.GITHUB_TOKEN }}
+
+      - name: Extract metadata for Docker
+        id: meta
+        uses: docker/metadata-action@v5
+        with:
+          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
+          tags: |
+            type=raw,value=latest
+            type=raw,value={{date 'YYYYMMDD'}}
+
+      - name: Build and push regular image
+        uses: docker/build-push-action@v5
+        with:
+          context: .
+          file: ./Dockerfile
+          push: true
+          tags: ${{ steps.meta.outputs.tags }}
+          labels: ${{ steps.meta.outputs.labels }}
+
+      - name: Build and push Alpine image
+        uses: docker/build-push-action@v5
+        with:
+          context: .
+          file: ./Dockerfile-alpine
+          push: true
+          tags: |
+            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine
+            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-{{date 'YYYYMMDD'}}
+          labels: ${{ steps.meta.outputs.labels }} 
\ No newline at end of file

From f09db5ef5e858f3c54c0c8dde1a9aecf7046dde0 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Sat, 14 Dec 2024 13:24:24 -0600
Subject: [PATCH 132/384] Update docker-build.yml

---
 .github/workflows/docker-build.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index 425c679ee2..f2dc866900 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -53,5 +53,5 @@ jobs:
           push: true
           tags: |
             ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine
-            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-{{date 'YYYYMMDD'}}
-          labels: ${{ steps.meta.outputs.labels }} 
\ No newline at end of file
+            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-${TAG_DATE}
+          labels: ${{ steps.meta.outputs.labels }} 

From 08b80c35be26b8815d310e9f3056d6633eef54a6 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Sat, 14 Dec 2024 14:23:08 -0600
Subject: [PATCH 133/384] Update docker-build.yml

---
 .github/workflows/docker-build.yml | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index f2dc866900..6b8dad0836 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -1,24 +1,25 @@
 name: Build and Push Docker Images
-
 on:
   schedule:
-    - cron: '0 0 1 * *'  # Run monthly on the 1st
+    - cron: '0 0 1 *'*  # Run monthly on the 1st
   workflow_dispatch:  # Allow manual triggers
-
 env:
   REGISTRY: ghcr.io
   IMAGE_NAME: ${{ github.repository }}
-
+  TAG_DATE: ${{ format('{0}{1}{2}', github.event.repository.pushed_at.substring(0,4), github.event.repository.pushed_at.substring(5,7), github.event.repository.pushed_at.substring(8,10)) }}
 jobs:
   build-and-push:
     runs-on: ubuntu-latest
     permissions:
       contents: read
       packages: write
-
     steps:
       - name: Checkout repository
         uses: actions/checkout@v4
+      
+      - name: Set current date
+        id: date
+        run: echo "DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV
 
       - name: Log in to the Container registry
         uses: docker/login-action@v3
@@ -34,7 +35,7 @@ jobs:
           images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
           tags: |
             type=raw,value=latest
-            type=raw,value={{date 'YYYYMMDD'}}
+            type=raw,value=${{ env.DATE }}
 
       - name: Build and push regular image
         uses: docker/build-push-action@v5
@@ -53,5 +54,5 @@ jobs:
           push: true
           tags: |
             ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine
-            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-${TAG_DATE}
-          labels: ${{ steps.meta.outputs.labels }} 
+            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-${{ env.DATE }}
+          labels: ${{ steps.meta.outputs.labels }}

From 63effa3ce4f499b755d9dd9ce21ab5d21fe45b43 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Sat, 14 Dec 2024 14:25:06 -0600
Subject: [PATCH 134/384] Update docker-build.yml

---
 .github/workflows/docker-build.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index 6b8dad0836..d548e6674a 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -1,8 +1,8 @@
 name: Build and Push Docker Images
 on:
   schedule:
-    - cron: '0 0 1 *'*  # Run monthly on the 1st
-  workflow_dispatch:  # Allow manual triggers
+    - cron: '0 0 1 * *'  # Run monthly on the 1st
+  workflow_dispatch:
 env:
   REGISTRY: ghcr.io
   IMAGE_NAME: ${{ github.repository }}

From 58085bec3f39235409d0d4fe8fcea7455a4271d3 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Sat, 14 Dec 2024 14:26:05 -0600
Subject: [PATCH 135/384] Update docker-build.yml

---
 .github/workflows/docker-build.yml | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index d548e6674a..611a50cf47 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -2,11 +2,10 @@ name: Build and Push Docker Images
 on:
   schedule:
     - cron: '0 0 1 * *'  # Run monthly on the 1st
-  workflow_dispatch:
+  workflow_dispatch:  # Allow manual triggers
 env:
   REGISTRY: ghcr.io
   IMAGE_NAME: ${{ github.repository }}
-  TAG_DATE: ${{ format('{0}{1}{2}', github.event.repository.pushed_at.substring(0,4), github.event.repository.pushed_at.substring(5,7), github.event.repository.pushed_at.substring(8,10)) }}
 jobs:
   build-and-push:
     runs-on: ubuntu-latest
@@ -16,10 +15,6 @@ jobs:
     steps:
       - name: Checkout repository
         uses: actions/checkout@v4
-      
-      - name: Set current date
-        id: date
-        run: echo "DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV
 
       - name: Log in to the Container registry
         uses: docker/login-action@v3
@@ -35,7 +30,7 @@ jobs:
           images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
           tags: |
             type=raw,value=latest
-            type=raw,value=${{ env.DATE }}
+            type=raw,value={{date 'YYYYMMDD'}}
 
       - name: Build and push regular image
         uses: docker/build-push-action@v5
@@ -54,5 +49,5 @@ jobs:
           push: true
           tags: |
             ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine
-            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-${{ env.DATE }}
+            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-{{date 'YYYYMMDD'}}
           labels: ${{ steps.meta.outputs.labels }}

From 018747014834ad099b1c093295ff1d7c09325dc5 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Sat, 14 Dec 2024 14:52:05 -0600
Subject: [PATCH 136/384] Update docker-build.yml

---
 .github/workflows/docker-build.yml | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index 611a50cf47..b917f7de1a 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -32,6 +32,15 @@ jobs:
             type=raw,value=latest
             type=raw,value={{date 'YYYYMMDD'}}
 
+      - name: Extract metadata for Alpine
+        id: meta-alpine
+        uses: docker/metadata-action@v5
+        with:
+          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
+          tags: |
+            type=raw,value=alpine
+            type=raw,prefix=alpine-,value={{date 'YYYYMMDD'}}
+
       - name: Build and push regular image
         uses: docker/build-push-action@v5
         with:
@@ -47,7 +56,5 @@ jobs:
           context: .
           file: ./Dockerfile-alpine
           push: true
-          tags: |
-            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine
-            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-{{date 'YYYYMMDD'}}
-          labels: ${{ steps.meta.outputs.labels }}
+          tags: ${{ steps.meta-alpine.outputs.tags }}
+          labels: ${{ steps.meta-alpine.outputs.labels }}

From 89334645fab186f1dcdb0be591453302a4a5322a Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Mon, 16 Dec 2024 18:15:52 -0600
Subject: [PATCH 137/384] update README with instructions for the GH action

---
 .github/workflows/docker-build.yml | 32 +++++++++++++--------------
 README.md                          | 35 ++++++++++++++++++++----------
 2 files changed, 40 insertions(+), 27 deletions(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index 425c679ee2..bea7e87f83 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -15,10 +15,21 @@ jobs:
     permissions:
       contents: read
       packages: write
+    strategy:
+      matrix:
+        variant:
+          - name: regular
+            file: Dockerfile
+            suffix: ''
+          - name: alpine
+            file: Dockerfile-alpine
+            suffix: '-alpine'
 
     steps:
       - name: Checkout repository
         uses: actions/checkout@v4
+        with:
+          persist-credentials: false
 
       - name: Log in to the Container registry
         uses: docker/login-action@v3
@@ -33,25 +44,14 @@ jobs:
         with:
           images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
           tags: |
-            type=raw,value=latest
-            type=raw,value={{date 'YYYYMMDD'}}
+            type=raw,value=latest${{ matrix.variant.suffix }}
+            type=raw,value={{date 'YYYYMMDD'}}${{ matrix.variant.suffix }}
 
-      - name: Build and push regular image
+      - name: Build and push image
         uses: docker/build-push-action@v5
         with:
           context: .
-          file: ./Dockerfile
+          file: ./${{ matrix.variant.file }}
           push: true
           tags: ${{ steps.meta.outputs.tags }}
-          labels: ${{ steps.meta.outputs.labels }}
-
-      - name: Build and push Alpine image
-        uses: docker/build-push-action@v5
-        with:
-          context: .
-          file: ./Dockerfile-alpine
-          push: true
-          tags: |
-            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine
-            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:alpine-{{date 'YYYYMMDD'}}
-          labels: ${{ steps.meta.outputs.labels }} 
\ No newline at end of file
+          labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/README.md b/README.md
index 54c9476102..97df20a1d8 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,30 @@ Keep track of development news:
 
 Unless you wish to contribute to the project, we recommend using the hosted version at [devdocs.io](https://devdocs.io). It's up-to-date and works offline out-of-the-box.
 
+### Using Docker (Recommended)
+
+The easiest way to run DevDocs locally is using Docker:
+
+```sh
+docker run --name devdocs -d -p 9292:9292 ghcr.io/freecodcamp/devdocs:latest
+```
+
+This will start DevDocs at [localhost:9292](http://localhost:9292). We provide both regular and Alpine-based images:
+- `ghcr.io/freecodcamp/devdocs:latest` - Standard image
+- `ghcr.io/freecodcamp/devdocs:latest-alpine` - Alpine-based (smaller size)
+
+Images are automatically built and updated monthly with the latest documentation.
+
+Alternatively, you can build the image yourself:
+
+```sh
+git clone https://github.com/freeCodeCamp/devdocs.git && cd devdocs
+docker build -t devdocs .
+docker run --name devdocs -d -p 9292:9292 devdocs
+```
+
+### Manual Installation
+
 DevDocs is made of two pieces: a Ruby scraper that generates the documentation and metadata, and a JavaScript app powered by a small Sinatra app.
 
 DevDocs requires Ruby 3.3.0 (defined in [`Gemfile`](./Gemfile)), libcurl, and a JavaScript runtime supported by [ExecJS](https://github.com/rails/execjs#readme) (included in OS X and Windows; [Node.js](https://nodejs.org/en/) on Linux). Once you have these installed, run the following commands:
@@ -38,17 +62,6 @@ The `thor docs:download` command is used to download pre-generated documentation
 
 **Note:** there is currently no update mechanism other than `git pull origin main` to update the code and `thor docs:download --installed` to download the latest version of the docs. To stay informed about new releases, be sure to [watch](https://github.com/freeCodeCamp/devdocs/subscription) this repository.
 
-Alternatively, DevDocs may be started as a Docker container:
-
-```sh
-# First, build the image
-git clone https://github.com/freeCodeCamp/devdocs.git && cd devdocs
-docker build -t thibaut/devdocs .
-
-# Finally, start a DevDocs container (access http://localhost:9292)
-docker run --name devdocs -d -p 9292:9292 thibaut/devdocs
-```
-
 ## Vision
 
 DevDocs aims to make reading and searching reference documentation fast, easy and enjoyable.

From 41841059881e1859b25aacd4357da23f2f8486fe Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 17 Dec 2024 17:10:55 +0000
Subject: [PATCH 138/384] chore(deps): pin dependencies

---
 .github/workflows/docker-build.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index fe413515a9..cd84ea4603 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -24,12 +24,12 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v4
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           persist-credentials: false
 
       - name: Log in to the Container registry
-        uses: docker/login-action@v3
+        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
         with:
           registry: ${{ env.REGISTRY }}
           username: ${{ github.actor }}
@@ -37,7 +37,7 @@ jobs:
 
       - name: Extract metadata for Docker
         id: meta
-        uses: docker/metadata-action@v5
+        uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5
         with:
           images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
           tags: |
@@ -45,7 +45,7 @@ jobs:
             type=raw,value={{date 'YYYYMMDD'}}${{ matrix.variant.suffix }}
 
       - name: Build and push image
-        uses: docker/build-push-action@v5
+        uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
         with:
           context: .
           file: ./${{ matrix.variant.file }}

From cdb9935298bc0d69f5c3338d714aa2639d33e504 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:22:15 +0000
Subject: [PATCH 139/384] chore(deps): update dependency erubi to v1.13.1

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 078caf94ab..5c6e89c03a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -28,7 +28,7 @@ GEM
     connection_pool (2.4.1)
     daemons (1.4.1)
     drb (2.2.1)
-    erubi (1.13.0)
+    erubi (1.13.1)
     ethon (0.16.0)
       ffi (>= 1.15.0)
     eventmachine (1.2.7)

From 42f5f550919b28a0ff296a8d234f31e46f7164e8 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 20 Dec 2024 18:00:42 +0000
Subject: [PATCH 140/384] chore(deps): update dependency sinatra to v4
 [security]

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 5c6e89c03a..282c4693f6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -133,7 +133,7 @@ GEM
       eventmachine (~> 1.0, >= 1.0.4)
       rack (>= 1, < 3)
     thor (1.3.2)
-    tilt (2.4.0)
+    tilt (2.5.0)
     tty-pager (0.14.0)
       strings (~> 0.2.0)
       tty-screen (~> 0.8)

From 34fe7e28cc26aa3893847f9660feed2619f2f9f4 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 23 Dec 2024 20:14:12 +0000
Subject: [PATCH 141/384] chore(deps): update dependency rack-test to v2.2.0

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 5c6e89c03a..df868a3718 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -81,7 +81,7 @@ GEM
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)
     rack-ssl-enforcer (0.2.9)
-    rack-test (2.1.0)
+    rack-test (2.2.0)
       rack (>= 1.3)
     rake (13.2.1)
     rb-fsevent (0.11.2)

From ed9e1be7fade937c35d9cf619d9a19668c182e8c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 23 Dec 2024 22:31:03 +0000
Subject: [PATCH 142/384] chore(deps): update ruby/setup-ruby action to
 v1.205.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4eefc897f9..1d1ebf340c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@401c19e14f474b54450cd3905bb8b86e2c8509cf # v1.204.0
+      uses: ruby/setup-ruby@540484a3c0f308b08619664ec40bf6c371d172c3 # v1.205.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 9f92295c57..2fd07e3d08 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@401c19e14f474b54450cd3905bb8b86e2c8509cf # v1.204.0
+      uses: ruby/setup-ruby@540484a3c0f308b08619664ec40bf6c371d172c3 # v1.205.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 8b1ae487b5..9caecfd7dc 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@401c19e14f474b54450cd3905bb8b86e2c8509cf # v1.204.0
+      uses: ruby/setup-ruby@540484a3c0f308b08619664ec40bf6c371d172c3 # v1.205.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 2f0ad7c09f9a1b238017611aee0a47ed640134c7 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Mon, 23 Dec 2024 22:44:04 -0600
Subject: [PATCH 143/384] Add documentation and support for three.js

---
 assets/stylesheets/pages/_threejs.scss |  56 ++++
 docs/file-scrapers.md                  |   8 +
 lib/docs/filters/threejs/clean_html.rb | 348 +++++++++++++++++++++++++
 lib/docs/filters/threejs/entries.rb    |  54 ++++
 lib/docs/scrapers/threejs.rb           |  85 ++++++
 5 files changed, 551 insertions(+)
 create mode 100644 assets/stylesheets/pages/_threejs.scss
 create mode 100644 lib/docs/filters/threejs/clean_html.rb
 create mode 100644 lib/docs/filters/threejs/entries.rb
 create mode 100644 lib/docs/scrapers/threejs.rb

diff --git a/assets/stylesheets/pages/_threejs.scss b/assets/stylesheets/pages/_threejs.scss
new file mode 100644
index 0000000000..32b39ce12f
--- /dev/null
+++ b/assets/stylesheets/pages/_threejs.scss
@@ -0,0 +1,56 @@
+._threejs {
+  // Code blocks
+  pre, code {
+    background-color: #f5f5f5;
+    border-radius: 3px;
+    padding: 0.2em 0.4em;
+  }
+
+  pre {
+    padding: 1em;
+    margin: 1em 0;
+    overflow: auto;
+
+    code {
+      background: none;
+      padding: 0;
+    }
+  }
+
+  // Links
+  a {
+    color: #049EF4;
+    text-decoration: none;
+
+    &:hover {
+      text-decoration: underline;
+    }
+  }
+
+  // Headings
+  h2 {
+    margin-top: 2em;
+    padding-bottom: 0.3em;
+    border-bottom: 1px solid #eaecef;
+  }
+
+  h3 {
+    margin-top: 1.5em;
+  }
+
+  // Tables
+  table {
+    border-collapse: collapse;
+    margin: 1em 0;
+    width: 100%;
+  }
+
+  th, td {
+    border: 1px solid #dfe2e5;
+    padding: 6px 13px;
+  }
+
+  tr:nth-child(2n) {
+    background-color: #f6f8fa;
+  }
+} 
\ No newline at end of file
diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index 2f8fd8f38e..cdfed33755 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -289,3 +289,11 @@ it to `docs/sqlite`
 ```sh
 curl https://sqlite.org/2022/sqlite-doc-3400000.zip | bsdtar --extract --file - --directory=docs/sqlite/ --strip-components=1
 ```
+
+## Three.js
+
+```sh
+git clone --depth 1 --branch r${VERSION} https://github.com/mrdoob/three.js.git
+mv three.js/docs/ docs/threejs~${VERSION}/
+rm -rf three.js/
+```
diff --git a/lib/docs/filters/threejs/clean_html.rb b/lib/docs/filters/threejs/clean_html.rb
new file mode 100644
index 0000000000..5a15b7b95d
--- /dev/null
+++ b/lib/docs/filters/threejs/clean_html.rb
@@ -0,0 +1,348 @@
+module Docs
+  class Threejs
+    class CleanHtmlFilter < Filter
+      def call
+        # Remove unnecessary elements
+        css('head, script, style').remove
+
+        # Add syntax highlighting CSS
+        style = doc.document.create_element('style')
+        style.content = <<-CSS
+          .highlight { background: #272b30; color: #e9ecef; border-radius: 4px; margin: 1em 0; }
+          .highlight pre { margin: 0; padding: 10px; }
+          .highlight .k { color: #cc7832; font-weight: bold; } /* Keyword */
+          .highlight .kd { color: #cc7832; font-weight: bold; } /* Keyword.Declaration */
+          .highlight .nb { color: #6897bb; } /* Name.Builtin */
+          .highlight .nx { color: #ffc66d; } /* Name.Other */
+          .highlight .nf { color: #ffc66d; } /* Name.Function */
+          .highlight .mi { color: #6897bb; } /* Literal.Number.Integer */
+          .highlight .s1 { color: #6a8759; } /* Literal.String.Single */
+          .highlight .s2 { color: #6a8759; } /* Literal.String.Double */
+          .highlight .c1 { color: #808080; font-style: italic; } /* Comment.Single */
+          .highlight .lineno { color: #606366; margin-right: 10px; -webkit-user-select: none; user-select: none; }
+          .highlight-javascript { padding: 0; }
+          
+          /* Method signatures */
+          .sig { padding: 5px 10px; }
+          .sig-name { color: #ffc66d; }
+          .sig-param { color: #e9ecef; }
+          .sig-param .sig-type { color: #6897bb; }
+          .sig-returns { color: #cc7832; }
+          .sig-returns .sig-type { color: #6897bb; }
+          .sig-paren { color: #e9ecef; }
+          .property .pre { color: #cc7832; }
+          
+          /* Inline code */
+          code.literal { background: #2b2b2b; padding: 2px 4px; border-radius: 3px; }
+          code.literal .pre { color: #e9ecef; }
+          
+          /* Links */
+          .reference { color: #6897bb; text-decoration: none; }
+          .reference:hover { text-decoration: underline; }
+          .reference.external { color: #6a8759; }
+          
+          /* Notes */
+          .admonition.note { background: #2b2b2b; padding: 12px 15px; border-left: 4px solid #6897bb; margin: 1em 0; }
+          .admonition-title { color: #6897bb; font-weight: bold; margin: 0 0 5px 0; }
+        CSS
+        doc.at_css('head') ? doc.at_css('head').add_child(style) : doc.add_child(style)
+
+        # Create a wrapper div for better styling
+        if root = at_css('body')
+          content = root.inner_html
+        else
+          content = doc.inner_html
+        end
+
+        # Create Django-like structure
+        content = <<-HTML
+          <div class="document">
+            <div class="documentwrapper">
+              <div class="bodywrapper">
+                <div class="body" role="main">
+                  #{content}
+                </div>
+              </div>
+            </div>
+          </div>
+        HTML
+
+        doc.inner_html = content
+
+        # Handle source links
+        css('h2').each do |node|
+          if node.content.strip == 'Source'
+            content = node.next_element&.inner_html
+            if content
+              # Clean up any existing formatting
+              content = content.gsub(/<[^>]+>/, '')
+              # Extract the path from the content
+              if content =~ /src\/(.*?)\.js/
+                path = "/#{$1}.js"
+                formatted_link = %Q(<a class="reference external" href="https://github.com/mrdoob/three.js/blob/master/src#{path}">src#{path}</a>)
+                node.next_element.inner_html = formatted_link if node.next_element
+              end
+            end
+          end
+        end
+
+        # Handle method signatures
+        css('h3').each do |node|
+          content = node.inner_html
+
+          # Handle [method:this methodName]( param1, param2, ... ) format
+          content = content.gsub(/\[method:this\s+([^\]]+)\]\s*\((.*?)\)/) do |match|
+            method_name, params_str = $1, $2
+            
+            # Format parameters
+            params = params_str.split(',').map do |param|
+              param = param.strip
+              if param.include?(' ')
+                type, name = param.split(' ', 2).map(&:strip)
+                "<span class='sig-param'><span class='sig-type'>#{type}</span> <span class='sig-name'>#{name}</span></span>"
+              else
+                "<span class='sig-param'>#{param}</span>"
+              end
+            end.join("<span class='sig-paren'>, </span>")
+
+            "<dt class='sig sig-object js' id='#{method_name}'>" \
+            "<span class='property'><span class='pre'>this</span></span>." \
+            "<span class='sig-name descname'>#{method_name}</span>" \
+            "<span class='sig-paren'>(</span>" \
+            "#{params}" \
+            "<span class='sig-paren'>)</span></dt>"
+          end
+
+          # Handle [method:returnType methodName]( param1, param2, ... ) format
+          content = content.gsub(/\[method:([^\s\]]+)\s+([^\]]+)\]\s*\((.*?)\)/) do |match|
+            return_type, method_name, params_str = $1, $2, $3
+            next if method_name.start_with?('this') # Skip if already handled above
+            
+            # Format parameters
+            params = params_str.split(',').map do |param|
+              param = param.strip
+              if param.include?(' ')
+                type, name = param.split(' ', 2).map(&:strip)
+                "<span class='sig-param'><span class='sig-type'>#{type}</span> <span class='sig-name'>#{name}</span></span>"
+              else
+                "<span class='sig-param'>#{param}</span>"
+              end
+            end.join("<span class='sig-paren'>, </span>")
+
+            "<dt class='sig sig-object js' id='#{method_name}'>" \
+            "<span class='sig-name descname'>#{method_name}</span>" \
+            "<span class='sig-paren'>(</span>" \
+            "#{params}" \
+            "<span class='sig-paren'>)</span>" \
+            "<span class='sig-returns'><span class='sig-colon'>:</span> " \
+            "<span class='sig-type'>#{return_type}</span></span></dt>"
+          end
+
+          # Handle [method:returnType methodName] format (no parameters)
+          content = content.gsub(/\[method:([^\s\]]+)\s+([^\]]+)\](?!\()/) do |match|
+            return_type, method_name = $1, $2
+            "<dt class='sig sig-object js' id='#{method_name}'>" \
+            "<span class='sig-name descname'>#{method_name}</span>" \
+            "<span class='sig-paren'>(</span>" \
+            "<span class='sig-paren'>)</span>" \
+            "<span class='sig-returns'><span class='sig-colon'>:</span> " \
+            "<span class='sig-type'>#{return_type}</span></span></dt>"
+          end
+
+          node.inner_html = content
+        end
+
+        # Handle [name] placeholders in headers and constructor
+        css('h1, h3').each do |node|
+          content = node.inner_html
+          
+          # Replace [name] with class name
+          content = content.gsub(/\[name\]/) do
+            name = slug.split('/').last.gsub('.html', '')
+            "<span class='descname'>#{name}</span>"
+          end
+          
+          # Format constructor parameters
+          content = content.gsub(/\[param:([^\]]+?)\s+([^\]]+?)\]/) do |match|
+            type, name = $1, $2
+            "<span class='sig-param'><span class='sig-type'>#{type}</span> <code class='sig-name'>#{name}</code></span>"
+          end
+          
+          node.inner_html = content
+        end
+
+        # Clean up property formatting
+        css('h3').each do |node|
+          node.inner_html = node.inner_html.gsub(/\[property:([^\]]+?)\s+([^\]]+?)\]/) do |match|
+            type, name = $1, $2
+            "<dt class='sig sig-object js'>" \
+            "<span class='sig-name descname'>#{name}</span>" \
+            "<span class='sig-colon'>:</span> " \
+            "<span class='sig-type'>#{type}</span></dt>"
+          end
+        end
+
+        # Clean up external links
+        css('*').each do |node|
+          next if node.text?
+          
+          # Handle example links [example:tag Title]
+          node.inner_html = node.inner_html.gsub(/\[example:([^\s\]]+)\s+([^\]]+)\]/) do |match|
+            tag, title = $1, $2
+            "<a class='reference external' href='https://threejs.org/examples/##{tag}'>#{title}</a>"
+          end
+
+          # Handle external links with [link:url text] format
+          node.inner_html = node.inner_html.gsub(/\[link:([^\s\]]+)\s+([^\]]+)\]/) do |match|
+            url, text = $1, $2
+            "<a class='reference external' href='#{url}'>#{text}</a>"
+          end
+
+          # Handle external links with [link:url] format
+          node.inner_html = node.inner_html.gsub(/\[link:([^\]]+)\]/) do |match|
+            url = $1
+            "<a class='reference external' href='#{url}'>#{url}</a>"
+          end
+
+          # Handle internal page links with text
+          node.inner_html = node.inner_html.gsub(/\[page:([^\]]+?)\s+([^\]]+?)\]/) do
+            path, text = $1, $2
+            "<a class='reference internal' href='#{path.downcase}'><code class='xref js js-#{path.downcase}'>#{text}</code></a>"
+          end
+
+          # Handle internal page links without text
+          node.inner_html = node.inner_html.gsub(/\[page:([^\]]+?)\]/) do |match|
+            path = $1
+            "<a class='reference internal' href='#{path.downcase}'><code class='xref js js-#{path.downcase}'>#{path}</code></a>"
+          end
+        end
+
+        # Fix all href attributes to be lowercase and remove .html
+        css('a[href]').each do |link|
+          next if link['href'].start_with?('http')
+          link['href'] = link['href'].remove('../').downcase.sub(/\.html$/, '')
+          link['class'] = 'reference internal'
+        end
+
+        # Add section classes
+        css('h2').each do |node|
+          node['class'] = 'section-title'
+          section = node.next_element
+          if section
+            wrapper = doc.document.create_element('div')
+            wrapper['class'] = 'section'
+            node.after(wrapper)
+            wrapper.add_child(node)
+            current = section
+            while current && current.name != 'h2'
+              next_el = current.next
+              wrapper.add_child(current)
+              current = next_el
+            end
+          end
+        end
+
+        # Format description paragraphs
+        css('p.desc').each do |node|
+          node['class'] = 'section-desc'
+        end
+
+        # Handle inline code/backticks in text
+        css('p, li, dt, dd').each do |node|
+          next if node.at_css('pre') # Skip if contains a code block
+          
+          # Replace backticks with proper code formatting
+          node.inner_html = node.inner_html.gsub(/`([^`]+)`/) do |match|
+            code = $1
+            "<code class='docutils literal notranslate'><span class='pre'>#{code}</span></code>"
+          end
+        end
+
+        # Handle inline code in property descriptions
+        css('.property-type').each do |node|
+          node.inner_html = node.inner_html.gsub(/`([^`]+)`/) do |match|
+            code = $1
+            "<code class='docutils literal notranslate'><span class='pre'>#{code}</span></code>"
+          end
+        end
+        
+        # Clean up code blocks
+        css('pre').each do |node|
+          wrapper = doc.document.create_element('div')
+          wrapper['class'] = 'highlight'
+          node.replace(wrapper)
+          
+          div = doc.document.create_element('div')
+          div['class'] = 'highlight-javascript notranslate'
+          wrapper.add_child(div)
+          
+          pre = doc.document.create_element('pre')
+          pre['class'] = ''
+          div.add_child(pre)
+
+          # Format the code content
+          code = node.content.strip
+          
+          # Add syntax highlighting spans
+          highlighted_code = highlight_javascript(code)
+          
+          pre.inner_html = highlighted_code
+        end
+
+        # Add proper heading IDs and classes
+        css('h1, h2, h3, h4').each do |node|
+          node['id'] ||= node.content.strip.downcase.gsub(/[^\w]+/, '-')
+          existing_class = node['class'].to_s
+          node['class'] = "#{existing_class} section-header"
+        end
+
+        # Remove interactive examples
+        css('.threejs_example_container').remove
+
+        # Add note styling
+        css('p').each do |node|
+          if node.content.start_with?('Note:')
+            wrapper = doc.document.create_element('div')
+            wrapper['class'] = 'admonition note'
+            
+            title = doc.document.create_element('p')
+            title['class'] = 'first admonition-title'
+            title.content = 'Note'
+            
+            content = doc.document.create_element('p')
+            content['class'] = 'last'
+            content.inner_html = node.inner_html.sub('Note:', '').strip
+            
+            wrapper.add_child(title)
+            wrapper.add_child(content)
+            node.replace(wrapper)
+          end
+        end
+
+        doc
+      end
+
+      private
+
+      def highlight_javascript(code)
+        code = code.gsub(/\b(function|return|var|let|const|if|else|for|while|do|switch|case|break|continue|new|try|catch|throw|this|typeof|instanceof|in|of|class|extends|super|import|export|default|null|undefined|true|false)\b/, '<span class="k">\1</span>') # keywords
+        code = code.gsub(/\b(\d+(\.\d+)?)\b/, '<span class="mi">\1</span>') # numbers
+        code = code.gsub(/'([^']*)'/, '<span class="s1">\'\1\'</span>') # single quotes
+        code = code.gsub(/"([^"]*)"/, '<span class="s2">"\1"</span>') # double quotes
+        code = code.gsub(/`([^`]*)`/, '<span class="s2">`\1`</span>') # template literals
+        code = code.gsub(/\/\/[^\n]*/, '<span class="c1">\0</span>') # single line comments
+        code = code.gsub(/\b(console|document|window|Array|Object|String|Number|Boolean|Function|Symbol|Map|Set|Promise|async|await)\b/, '<span class="nb">\1</span>') # built-ins
+        code = code.gsub(/([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/, '<span class="nx">\1</span>(') # function calls
+        code = code.gsub(/\b(addEventListener|querySelector|getElementById|setTimeout|setInterval)\b/, '<span class="nx">\1</span>') # common methods
+        
+        # Add line numbers
+        lines = code.split("\n")
+        numbered_lines = lines.map.with_index(1) do |line, i|
+          "<span class=\"lineno\">#{i}</span>#{line}"
+        end
+        
+        numbered_lines.join("\n")
+      end
+    end
+  end
+end 
\ No newline at end of file
diff --git a/lib/docs/filters/threejs/entries.rb b/lib/docs/filters/threejs/entries.rb
new file mode 100644
index 0000000000..fa14628eb4
--- /dev/null
+++ b/lib/docs/filters/threejs/entries.rb
@@ -0,0 +1,54 @@
+module Docs
+  class Threejs
+    class EntriesFilter < Docs::EntriesFilter
+      def get_name
+        # Try to get name from the title first
+        if title = at_css('.lesson-title h1')&.content
+          title
+        else
+          # Fallback to path-based name for API docs
+          slug.split('/').last.gsub('.html', '').titleize
+        end
+      end
+
+      def get_type
+        if slug.start_with?('api/en/')
+          # For API documentation, use the section as type
+          # e.g. "api/en/animation/AnimationAction" -> "Animation"
+          path_parts = slug.split('/')
+          if path_parts.length >= 3
+            path_parts[2].titleize
+          else
+            'API'
+          end
+        elsif slug.start_with?('manual/en/')
+          # For manual pages, get the section from the path
+          # e.g. "manual/en/introduction/Creating-a-scene" -> "Introduction"
+          path_parts = slug.split('/')
+          if path_parts.length >= 3
+            path_parts[2].titleize
+          else
+            'Manual'
+          end
+        else
+          'Other'
+        end
+      end
+
+      def additional_entries
+        entries = []
+        
+        # Get all methods and properties from h3 headings
+        css('h3').each do |node|
+          name = node.content.strip
+          # Skip if it's a constructor or doesn't have an ID
+          next if name == get_name || !node['id']
+          
+          entries << [name, node['id'], get_type]
+        end
+
+        entries
+      end
+    end
+  end
+end 
\ No newline at end of file
diff --git a/lib/docs/scrapers/threejs.rb b/lib/docs/scrapers/threejs.rb
new file mode 100644
index 0000000000..9f6a27cc9d
--- /dev/null
+++ b/lib/docs/scrapers/threejs.rb
@@ -0,0 +1,85 @@
+module Docs
+  class Threejs < FileScraper
+    self.name = 'Three.js'
+    self.type = 'threejs'
+    self.slug = 'threejs'
+    self.links = {
+      home: 'https://threejs.org/',
+      code: 'https://github.com/mrdoob/three.js'
+    }
+
+    html_filters.push 'threejs/entries', 'threejs/clean_html'
+
+    # The content is directly in the body
+    options[:container] = 'body'
+
+    options[:skip] = %w(
+      prettify.js
+      lesson.js
+      lang.css
+      lesson.css
+      editor.html
+      list.js
+      page.js
+    )
+
+    options[:only_patterns] = [
+      /\Aapi\/en\/.+\.html/,   # API documentation
+      /\Amanual\/en\/.+\.html/ # Manual pages
+    ]
+
+    options[:skip_patterns] = [
+      /examples/,
+      /\A_/,
+      /\Aresources\//,
+      /\Ascenes\//
+    ]
+
+    options[:attribution] = <<-HTML
+      &copy; 2010&ndash;#{Time.current.year} Three.js Authors<br>
+      Licensed under the MIT License.
+    HTML
+
+    self.class_attribute :release
+
+    version '160' do
+      self.release = '160'
+      self.base_url = "https://threejs.org/docs"
+    end
+
+    def get_latest_version(opts)
+      get_latest_github_release('mrdoob', 'three.js', opts)
+    end
+
+    def initial_paths
+      paths = []
+      json_path = File.expand_path("docs/threejs~#{self.release}/list.json")
+      json_content = File.read(json_path)
+      json_data = JSON.parse(json_content)
+
+      # Process both API and manual sections
+      process_documentation(json_data['en'], paths)
+      paths
+    end
+
+    private
+
+    def process_documentation(data, paths, prefix = '')
+      data.each do |category, items|
+        if items.is_a?(Hash)
+          if items.values.first.is_a?(String)
+            # This is a leaf node with actual pages
+            items.each do |name, path|
+              paths << "#{path}.html"
+            end
+          else
+            # This is a category with subcategories
+            items.each do |subcategory, subitems|
+              process_documentation(items, paths, "#{prefix}#{category}/")
+            end
+          end
+        end
+      end
+    end
+  end
+end 
\ No newline at end of file

From e08baefb529f229596fa75e1e002ec30049b42f1 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Mon, 23 Dec 2024 22:51:31 -0600
Subject: [PATCH 144/384] Add logos

---
 public/icons/docs/threejs/16.png    | Bin 0 -> 428 bytes
 public/icons/docs/threejs/16@2x.png | Bin 0 -> 986 bytes
 public/icons/docs/threejs/SOURCE    |   1 +
 3 files changed, 1 insertion(+)
 create mode 100644 public/icons/docs/threejs/16.png
 create mode 100644 public/icons/docs/threejs/16@2x.png
 create mode 100644 public/icons/docs/threejs/SOURCE

diff --git a/public/icons/docs/threejs/16.png b/public/icons/docs/threejs/16.png
new file mode 100644
index 0000000000000000000000000000000000000000..dd410d87321970ebfe066a22ae1ab5ccc806ae4d
GIT binary patch
diff --git a/public/icons/docs/threejs/16@2x.png b/public/icons/docs/threejs/16@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..a453c04d88b18f051cf77cb744dd4d96c377bafe
GIT binary patch
diff --git a/public/icons/docs/threejs/SOURCE b/public/icons/docs/threejs/SOURCE
new file mode 100644
index 0000000000..01efe7e30f
--- /dev/null
+++ b/public/icons/docs/threejs/SOURCE
@@ -0,0 +1 @@
+https://github.com/mrdoob/three.js/tree/dev/files
\ No newline at end of file

From 71729cfa4d1b24fe8260d87c7b6fca108095cb2d Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Mon, 23 Dec 2024 23:13:30 -0600
Subject: [PATCH 145/384] Updated instructions for downloading the
 documentation

---
 assets/stylesheets/pages/_threejs.scss | 56 --------------------------
 docs/file-scrapers.md                  | 11 +++--
 2 files changed, 8 insertions(+), 59 deletions(-)
 delete mode 100644 assets/stylesheets/pages/_threejs.scss

diff --git a/assets/stylesheets/pages/_threejs.scss b/assets/stylesheets/pages/_threejs.scss
deleted file mode 100644
index 32b39ce12f..0000000000
--- a/assets/stylesheets/pages/_threejs.scss
+++ /dev/null
@@ -1,56 +0,0 @@
-._threejs {
-  // Code blocks
-  pre, code {
-    background-color: #f5f5f5;
-    border-radius: 3px;
-    padding: 0.2em 0.4em;
-  }
-
-  pre {
-    padding: 1em;
-    margin: 1em 0;
-    overflow: auto;
-
-    code {
-      background: none;
-      padding: 0;
-    }
-  }
-
-  // Links
-  a {
-    color: #049EF4;
-    text-decoration: none;
-
-    &:hover {
-      text-decoration: underline;
-    }
-  }
-
-  // Headings
-  h2 {
-    margin-top: 2em;
-    padding-bottom: 0.3em;
-    border-bottom: 1px solid #eaecef;
-  }
-
-  h3 {
-    margin-top: 1.5em;
-  }
-
-  // Tables
-  table {
-    border-collapse: collapse;
-    margin: 1em 0;
-    width: 100%;
-  }
-
-  th, td {
-    border: 1px solid #dfe2e5;
-    padding: 6px 13px;
-  }
-
-  tr:nth-child(2n) {
-    background-color: #f6f8fa;
-  }
-} 
\ No newline at end of file
diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index cdfed33755..164b6f7d9d 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -291,9 +291,14 @@ curl https://sqlite.org/2022/sqlite-doc-3400000.zip | bsdtar --extract --file -
 ```
 
 ## Three.js
+Download the docs from https://github.com/mrdoob/three.js/tree/dev/files or run the following commands in your terminal:
+Make sure to set the version per the release tag (e.g. r160). Note that the r prefix is already included, only the version number is needed.
 
 ```sh
-git clone --depth 1 --branch r${VERSION} https://github.com/mrdoob/three.js.git
-mv three.js/docs/ docs/threejs~${VERSION}/
-rm -rf three.js/
+curl https://codeload.github.com/mrdoob/three.js/tar.gz/refs/tags/r${VERSION} > threejs.tar.gz
+tar -xzf threejs.tar.gz
+mkdir -p docs/threejs~${VERSION}
+mv three.js-r${VERSION}/docs/* docs/threejs~${VERSION}/
+rm -rf three.js-r${VERSION}/
+rm threejs.tar.gz
 ```

From 1a1973580c31d4c447f5d380e060f487a19cc2bf Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Mon, 23 Dec 2024 23:23:25 -0600
Subject: [PATCH 146/384] add page to the styling

---
 assets/stylesheets/application.css.scss | 1 +
 1 file changed, 1 insertion(+)

diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss
index 3823cdc3d8..d2887ba994 100644
--- a/assets/stylesheets/application.css.scss
+++ b/assets/stylesheets/application.css.scss
@@ -131,6 +131,7 @@
         'pages/tcl_tk',
         'pages/tensorflow',
         'pages/terraform',
+        'pages/threejs',
         'pages/typescript',
         'pages/underscore',
         'pages/vue',

From 58d3d7de0a5bb4b33d3011f5dd9a701861a5c66c Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Mon, 23 Dec 2024 23:26:23 -0600
Subject: [PATCH 147/384] add styling

---
 assets/stylesheets/pages/_threejs.scss | 47 ++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 assets/stylesheets/pages/_threejs.scss

diff --git a/assets/stylesheets/pages/_threejs.scss b/assets/stylesheets/pages/_threejs.scss
new file mode 100644
index 0000000000..8996ba0bf9
--- /dev/null
+++ b/assets/stylesheets/pages/_threejs.scss
@@ -0,0 +1,47 @@
+._threejs {
+    // Code blocks
+    pre, code {
+      background-color: #f5f5f5;
+      border-radius: 3px;
+      padding: 0.2em 0.4em;
+    }
+    pre {
+      padding: 1em;
+      margin: 1em 0;
+      overflow: auto;
+      code {
+        background: none;
+        padding: 0;
+      }
+    }
+    // Links
+    a {
+      color: #049EF4;
+      text-decoration: none;
+      &:hover {
+        text-decoration: underline;
+      }
+    }
+    // Headings
+    h2 {
+      margin-top: 2em;
+      padding-bottom: 0.3em;
+      border-bottom: 1px solid #eaecef;
+    }
+    h3 {
+      margin-top: 1.5em;
+    }
+    // Tables
+    table {
+      border-collapse: collapse;
+      margin: 1em 0;
+      width: 100%;
+    }
+    th, td {
+      border: 1px solid #dfe2e5;
+      padding: 6px 13px;
+    }
+    tr:nth-child(2n) {
+      background-color: #f6f8fa;
+    }
+  } 
\ No newline at end of file

From 15fcdc22bb201c8ff5f9560ca8fb14eaae3fe57f Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Tue, 24 Dec 2024 11:16:59 -0600
Subject: [PATCH 148/384] switched to the simple styling option

---
 lib/docs/filters/threejs/clean_html.rb | 70 ++------------------------
 lib/docs/scrapers/threejs.rb           |  2 +-
 2 files changed, 6 insertions(+), 66 deletions(-)

diff --git a/lib/docs/filters/threejs/clean_html.rb b/lib/docs/filters/threejs/clean_html.rb
index 5a15b7b95d..b66bc729d9 100644
--- a/lib/docs/filters/threejs/clean_html.rb
+++ b/lib/docs/filters/threejs/clean_html.rb
@@ -4,71 +4,7 @@ class CleanHtmlFilter < Filter
       def call
         # Remove unnecessary elements
         css('head, script, style').remove
-
-        # Add syntax highlighting CSS
-        style = doc.document.create_element('style')
-        style.content = <<-CSS
-          .highlight { background: #272b30; color: #e9ecef; border-radius: 4px; margin: 1em 0; }
-          .highlight pre { margin: 0; padding: 10px; }
-          .highlight .k { color: #cc7832; font-weight: bold; } /* Keyword */
-          .highlight .kd { color: #cc7832; font-weight: bold; } /* Keyword.Declaration */
-          .highlight .nb { color: #6897bb; } /* Name.Builtin */
-          .highlight .nx { color: #ffc66d; } /* Name.Other */
-          .highlight .nf { color: #ffc66d; } /* Name.Function */
-          .highlight .mi { color: #6897bb; } /* Literal.Number.Integer */
-          .highlight .s1 { color: #6a8759; } /* Literal.String.Single */
-          .highlight .s2 { color: #6a8759; } /* Literal.String.Double */
-          .highlight .c1 { color: #808080; font-style: italic; } /* Comment.Single */
-          .highlight .lineno { color: #606366; margin-right: 10px; -webkit-user-select: none; user-select: none; }
-          .highlight-javascript { padding: 0; }
-          
-          /* Method signatures */
-          .sig { padding: 5px 10px; }
-          .sig-name { color: #ffc66d; }
-          .sig-param { color: #e9ecef; }
-          .sig-param .sig-type { color: #6897bb; }
-          .sig-returns { color: #cc7832; }
-          .sig-returns .sig-type { color: #6897bb; }
-          .sig-paren { color: #e9ecef; }
-          .property .pre { color: #cc7832; }
-          
-          /* Inline code */
-          code.literal { background: #2b2b2b; padding: 2px 4px; border-radius: 3px; }
-          code.literal .pre { color: #e9ecef; }
-          
-          /* Links */
-          .reference { color: #6897bb; text-decoration: none; }
-          .reference:hover { text-decoration: underline; }
-          .reference.external { color: #6a8759; }
-          
-          /* Notes */
-          .admonition.note { background: #2b2b2b; padding: 12px 15px; border-left: 4px solid #6897bb; margin: 1em 0; }
-          .admonition-title { color: #6897bb; font-weight: bold; margin: 0 0 5px 0; }
-        CSS
-        doc.at_css('head') ? doc.at_css('head').add_child(style) : doc.add_child(style)
-
-        # Create a wrapper div for better styling
-        if root = at_css('body')
-          content = root.inner_html
-        else
-          content = doc.inner_html
-        end
-
-        # Create Django-like structure
-        content = <<-HTML
-          <div class="document">
-            <div class="documentwrapper">
-              <div class="bodywrapper">
-                <div class="body" role="main">
-                  #{content}
-                </div>
-              </div>
-            </div>
-          </div>
-        HTML
-
-        doc.inner_html = content
-
+        
         # Handle source links
         css('h2').each do |node|
           if node.content.strip == 'Source'
@@ -319,6 +255,10 @@ def call
           end
         end
 
+        # Remove the navigation arrows and links
+        css('.nav').remove if at_css('.nav')
+        # If the arrows are in a different container, adjust the selector accordingly
+        
         doc
       end
 
diff --git a/lib/docs/scrapers/threejs.rb b/lib/docs/scrapers/threejs.rb
index 9f6a27cc9d..5be458b8d8 100644
--- a/lib/docs/scrapers/threejs.rb
+++ b/lib/docs/scrapers/threejs.rb
@@ -1,7 +1,7 @@
 module Docs
   class Threejs < FileScraper
     self.name = 'Three.js'
-    self.type = 'threejs'
+    self.type = 'simple'
     self.slug = 'threejs'
     self.links = {
       home: 'https://threejs.org/',

From 21a04f9115937f24decad1fbd96fe12804487e95 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Tue, 24 Dec 2024 19:33:56 -0600
Subject: [PATCH 149/384] fix the clean_html file for optimizations

---
 lib/docs/filters/threejs/clean_html.rb | 61 ++++----------------------
 1 file changed, 8 insertions(+), 53 deletions(-)

diff --git a/lib/docs/filters/threejs/clean_html.rb b/lib/docs/filters/threejs/clean_html.rb
index b66bc729d9..ac1cb03690 100644
--- a/lib/docs/filters/threejs/clean_html.rb
+++ b/lib/docs/filters/threejs/clean_html.rb
@@ -4,6 +4,14 @@ class CleanHtmlFilter < Filter
       def call
         # Remove unnecessary elements
         css('head, script, style').remove
+        # Wrap code blocks with pre tags and add syntax highlighting
+        css('code').each do |node|
+          unless node.parent.name == 'pre'
+            pre = node.wrap('<pre>')
+            pre['data-language'] = 'javascript'
+            pre['class'] = 'language-javascript'
+          end
+        end
         
         # Handle source links
         css('h2').each do |node|
@@ -202,29 +210,6 @@ def call
           end
         end
         
-        # Clean up code blocks
-        css('pre').each do |node|
-          wrapper = doc.document.create_element('div')
-          wrapper['class'] = 'highlight'
-          node.replace(wrapper)
-          
-          div = doc.document.create_element('div')
-          div['class'] = 'highlight-javascript notranslate'
-          wrapper.add_child(div)
-          
-          pre = doc.document.create_element('pre')
-          pre['class'] = ''
-          div.add_child(pre)
-
-          # Format the code content
-          code = node.content.strip
-          
-          # Add syntax highlighting spans
-          highlighted_code = highlight_javascript(code)
-          
-          pre.inner_html = highlighted_code
-        end
-
         # Add proper heading IDs and classes
         css('h1, h2, h3, h4').each do |node|
           node['id'] ||= node.content.strip.downcase.gsub(/[^\w]+/, '-')
@@ -232,9 +217,6 @@ def call
           node['class'] = "#{existing_class} section-header"
         end
 
-        # Remove interactive examples
-        css('.threejs_example_container').remove
-
         # Add note styling
         css('p').each do |node|
           if node.content.start_with?('Note:')
@@ -254,35 +236,8 @@ def call
             node.replace(wrapper)
           end
         end
-
-        # Remove the navigation arrows and links
-        css('.nav').remove if at_css('.nav')
-        # If the arrows are in a different container, adjust the selector accordingly
-        
         doc
       end
-
-      private
-
-      def highlight_javascript(code)
-        code = code.gsub(/\b(function|return|var|let|const|if|else|for|while|do|switch|case|break|continue|new|try|catch|throw|this|typeof|instanceof|in|of|class|extends|super|import|export|default|null|undefined|true|false)\b/, '<span class="k">\1</span>') # keywords
-        code = code.gsub(/\b(\d+(\.\d+)?)\b/, '<span class="mi">\1</span>') # numbers
-        code = code.gsub(/'([^']*)'/, '<span class="s1">\'\1\'</span>') # single quotes
-        code = code.gsub(/"([^"]*)"/, '<span class="s2">"\1"</span>') # double quotes
-        code = code.gsub(/`([^`]*)`/, '<span class="s2">`\1`</span>') # template literals
-        code = code.gsub(/\/\/[^\n]*/, '<span class="c1">\0</span>') # single line comments
-        code = code.gsub(/\b(console|document|window|Array|Object|String|Number|Boolean|Function|Symbol|Map|Set|Promise|async|await)\b/, '<span class="nb">\1</span>') # built-ins
-        code = code.gsub(/([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/, '<span class="nx">\1</span>(') # function calls
-        code = code.gsub(/\b(addEventListener|querySelector|getElementById|setTimeout|setInterval)\b/, '<span class="nx">\1</span>') # common methods
-        
-        # Add line numbers
-        lines = code.split("\n")
-        numbered_lines = lines.map.with_index(1) do |line, i|
-          "<span class=\"lineno\">#{i}</span>#{line}"
-        end
-        
-        numbered_lines.join("\n")
-      end
     end
   end
 end 
\ No newline at end of file

From 8d0efa7c28aecc9a05c0d680b8c699934797080f Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Tue, 24 Dec 2024 19:36:03 -0600
Subject: [PATCH 150/384] update threejs doc version

---
 lib/docs/scrapers/threejs.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/threejs.rb b/lib/docs/scrapers/threejs.rb
index 5be458b8d8..bc792faeaa 100644
--- a/lib/docs/scrapers/threejs.rb
+++ b/lib/docs/scrapers/threejs.rb
@@ -42,8 +42,8 @@ class Threejs < FileScraper
 
     self.class_attribute :release
 
-    version '160' do
-      self.release = '160'
+    version '171' do
+      self.release = '171'
       self.base_url = "https://threejs.org/docs"
     end
 

From b7393f4d5504e6bd76995ec4734bce3fedeef17c Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Tue, 24 Dec 2024 20:57:03 -0600
Subject: [PATCH 151/384] update documentation for new folder location for json
 file

---
 docs/file-scrapers.md                  | 2 ++
 lib/docs/filters/threejs/clean_html.rb | 1 +
 lib/docs/scrapers/threejs.rb           | 4 +---
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index 164b6f7d9d..923bac2061 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -298,7 +298,9 @@ Make sure to set the version per the release tag (e.g. r160). Note that the r pr
 curl https://codeload.github.com/mrdoob/three.js/tar.gz/refs/tags/r${VERSION} > threejs.tar.gz
 tar -xzf threejs.tar.gz
 mkdir -p docs/threejs~${VERSION}
+mv three.js-r${VERSION}/list.json /tmp/list.json
 mv three.js-r${VERSION}/docs/* docs/threejs~${VERSION}/
+
 rm -rf three.js-r${VERSION}/
 rm threejs.tar.gz
 ```
diff --git a/lib/docs/filters/threejs/clean_html.rb b/lib/docs/filters/threejs/clean_html.rb
index ac1cb03690..abee6997c1 100644
--- a/lib/docs/filters/threejs/clean_html.rb
+++ b/lib/docs/filters/threejs/clean_html.rb
@@ -4,6 +4,7 @@ class CleanHtmlFilter < Filter
       def call
         # Remove unnecessary elements
         css('head, script, style').remove
+        
         # Wrap code blocks with pre tags and add syntax highlighting
         css('code').each do |node|
           unless node.parent.name == 'pre'
diff --git a/lib/docs/scrapers/threejs.rb b/lib/docs/scrapers/threejs.rb
index bc792faeaa..e596e03444 100644
--- a/lib/docs/scrapers/threejs.rb
+++ b/lib/docs/scrapers/threejs.rb
@@ -40,8 +40,6 @@ class Threejs < FileScraper
       Licensed under the MIT License.
     HTML
 
-    self.class_attribute :release
-
     version '171' do
       self.release = '171'
       self.base_url = "https://threejs.org/docs"
@@ -53,7 +51,7 @@ def get_latest_version(opts)
 
     def initial_paths
       paths = []
-      json_path = File.expand_path("docs/threejs~#{self.release}/list.json")
+      json_path = File.expand_path("/tmp/list.json")
       json_content = File.read(json_path)
       json_data = JSON.parse(json_content)
 

From a92e5144e50fe7d44c3216704357519a0a69b41f Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 25 Dec 2024 16:53:37 +0100
Subject: [PATCH 152/384] Update Ruby documentation (3.4.1)

---
 lib/docs/filters/rdoc/container.rb | 7 +++++--
 lib/docs/scrapers/rdoc/ruby.rb     | 6 +++++-
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/lib/docs/filters/rdoc/container.rb b/lib/docs/filters/rdoc/container.rb
index aea2b0f50f..4732b02a4e 100644
--- a/lib/docs/filters/rdoc/container.rb
+++ b/lib/docs/filters/rdoc/container.rb
@@ -13,8 +13,11 @@ def call
           meta = Nokogiri::XML::Node.new 'dl', doc.document
           meta['class'] = 'meta'
 
-          if parent = at_css('#parent-class-section')
-            meta << %(<dt>Parent:</dt><dd class="meta-parent">#{parent.at_css('.link').inner_html.strip}</dd>)
+          parent = at_css('#parent-class-section')
+          if parent && link = parent.at_css('.link')
+            meta << %(<dt>Parent:</dt><dd class="meta-parent">#{link.inner_html.strip}</dd>)
+          elsif parent && link = parent.at_css('a')
+            meta << %(<dt>Parent:</dt><dd class="meta-parent">#{link.to_html}</dd>)
           end
 
           if includes = at_css('#includes-section')
diff --git a/lib/docs/scrapers/rdoc/ruby.rb b/lib/docs/scrapers/rdoc/ruby.rb
index eef26f4182..630cb81e37 100644
--- a/lib/docs/scrapers/rdoc/ruby.rb
+++ b/lib/docs/scrapers/rdoc/ruby.rb
@@ -63,12 +63,16 @@ class Ruby < Rdoc
       /\AXMP/]
 
     options[:attribution] = <<-HTML
-      Ruby Core &copy; 1993&ndash;2022 Yukihiro Matsumoto<br>
+      Ruby Core &copy; 1993&ndash;2024 Yukihiro Matsumoto<br>
       Licensed under the Ruby License.<br>
       Ruby Standard Library &copy; contributors<br>
       Licensed under their own licenses.
     HTML
 
+    version '3.4' do
+      self.release = '3.4.1'
+    end
+
     version '3.3' do
       self.release = '3.3.0'
     end

From ef75950e576b5be6247c78b41c6b93b25ed59d68 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 25 Dec 2024 19:21:39 +0000
Subject: [PATCH 153/384] chore(deps): update dependency nokogiri to v1.18.0

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index df868a3718..fbe12c49d1 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -61,7 +61,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.17.2)
+    nokogiri (1.18.0)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From b218836a82b66db21beffc48df75744b15317fe9 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Wed, 25 Dec 2024 14:09:00 -0600
Subject: [PATCH 154/384] cleanup the code

---
 lib/docs/filters/threejs/clean_html.rb | 365 ++++++++++++-------------
 1 file changed, 180 insertions(+), 185 deletions(-)

diff --git a/lib/docs/filters/threejs/clean_html.rb b/lib/docs/filters/threejs/clean_html.rb
index abee6997c1..9b0de32445 100644
--- a/lib/docs/filters/threejs/clean_html.rb
+++ b/lib/docs/filters/threejs/clean_html.rb
@@ -1,243 +1,238 @@
 module Docs
   class Threejs
     class CleanHtmlFilter < Filter
+      PATTERNS = {
+        method_this: /\[method:this\s+([^\]]+)\]\s*\((.*?)\)/,
+        method_return: /\[method:([^\s\]]+)\s+([^\]]+)\]\s*\((.*?)\)/,
+        method_no_params: /\[method:([^\s\]]+)\s+([^\]]+)\](?!\()/,
+        property: /\[property:([^\]]+?)\s+([^\]]+?)\]/,
+        example_link: /\[example:([^\s\]]+)\s+([^\]]+)\]/,
+        external_link_text: /\[link:([^\s\]]+)\s+([^\]]+)\]/,
+        external_link: /\[link:([^\]]+)\]/,
+        page_link_text: /\[page:([^\]]+?)\s+([^\]]+?)\]/,
+        page_link: /\[page:([^\]]+?)\]/,
+        inline_code: /`([^`]+)`/,
+        name_placeholder: /\[name\]/,
+        constructor_param: /\[param:([^\]]+?)\s+([^\]]+?)\]/
+      }.freeze
+
       def call
-        # Remove unnecessary elements
+        remove_unnecessary_elements
+        wrap_code_blocks
+        process_sections
+        format_links
+        add_section_structure
+        format_notes
+        add_heading_attributes
+        doc
+      end
+
+      private
+
+      def remove_unnecessary_elements
         css('head, script, style').remove
-        
-        # Wrap code blocks with pre tags and add syntax highlighting
+      end
+
+      def wrap_code_blocks
         css('code').each do |node|
-          unless node.parent.name == 'pre'
-            pre = node.wrap('<pre>')
-            pre['data-language'] = 'javascript'
-            pre['class'] = 'language-javascript'
-          end
+          next if node.parent.name == 'pre'
+          pre = node.wrap('<pre>')
+          pre['data-language'] = pre['class'] = 'language-javascript'
         end
-        
+      end
+
+      def process_sections
         # Handle source links
         css('h2').each do |node|
-          if node.content.strip == 'Source'
-            content = node.next_element&.inner_html
-            if content
-              # Clean up any existing formatting
-              content = content.gsub(/<[^>]+>/, '')
-              # Extract the path from the content
-              if content =~ /src\/(.*?)\.js/
-                path = "/#{$1}.js"
-                formatted_link = %Q(<a class="reference external" href="https://github.com/mrdoob/three.js/blob/master/src#{path}">src#{path}</a>)
-                node.next_element.inner_html = formatted_link if node.next_element
-              end
-            end
-          end
+          next unless node.content.strip == 'Source'
+          handle_source_link(node)
         end
 
-        # Handle method signatures
+        # Handle method signatures and properties
         css('h3').each do |node|
           content = node.inner_html
-
-          # Handle [method:this methodName]( param1, param2, ... ) format
-          content = content.gsub(/\[method:this\s+([^\]]+)\]\s*\((.*?)\)/) do |match|
-            method_name, params_str = $1, $2
-            
-            # Format parameters
-            params = params_str.split(',').map do |param|
-              param = param.strip
-              if param.include?(' ')
-                type, name = param.split(' ', 2).map(&:strip)
-                "<span class='sig-param'><span class='sig-type'>#{type}</span> <span class='sig-name'>#{name}</span></span>"
-              else
-                "<span class='sig-param'>#{param}</span>"
-              end
-            end.join("<span class='sig-paren'>, </span>")
-
-            "<dt class='sig sig-object js' id='#{method_name}'>" \
-            "<span class='property'><span class='pre'>this</span></span>." \
-            "<span class='sig-name descname'>#{method_name}</span>" \
-            "<span class='sig-paren'>(</span>" \
-            "#{params}" \
-            "<span class='sig-paren'>)</span></dt>"
-          end
-
-          # Handle [method:returnType methodName]( param1, param2, ... ) format
-          content = content.gsub(/\[method:([^\s\]]+)\s+([^\]]+)\]\s*\((.*?)\)/) do |match|
-            return_type, method_name, params_str = $1, $2, $3
-            next if method_name.start_with?('this') # Skip if already handled above
-            
-            # Format parameters
-            params = params_str.split(',').map do |param|
-              param = param.strip
-              if param.include?(' ')
-                type, name = param.split(' ', 2).map(&:strip)
-                "<span class='sig-param'><span class='sig-type'>#{type}</span> <span class='sig-name'>#{name}</span></span>"
-              else
-                "<span class='sig-param'>#{param}</span>"
-              end
-            end.join("<span class='sig-paren'>, </span>")
-
-            "<dt class='sig sig-object js' id='#{method_name}'>" \
-            "<span class='sig-name descname'>#{method_name}</span>" \
-            "<span class='sig-paren'>(</span>" \
-            "#{params}" \
-            "<span class='sig-paren'>)</span>" \
-            "<span class='sig-returns'><span class='sig-colon'>:</span> " \
-            "<span class='sig-type'>#{return_type}</span></span></dt>"
-          end
-
-          # Handle [method:returnType methodName] format (no parameters)
-          content = content.gsub(/\[method:([^\s\]]+)\s+([^\]]+)\](?!\()/) do |match|
-            return_type, method_name = $1, $2
-            "<dt class='sig sig-object js' id='#{method_name}'>" \
-            "<span class='sig-name descname'>#{method_name}</span>" \
-            "<span class='sig-paren'>(</span>" \
-            "<span class='sig-paren'>)</span>" \
-            "<span class='sig-returns'><span class='sig-colon'>:</span> " \
-            "<span class='sig-type'>#{return_type}</span></span></dt>"
-          end
-
+          content = handle_method_signatures(content)
+          content = handle_properties(content)
           node.inner_html = content
         end
 
-        # Handle [name] placeholders in headers and constructor
+        # Handle name placeholders and constructor params
         css('h1, h3').each do |node|
           content = node.inner_html
-          
-          # Replace [name] with class name
-          content = content.gsub(/\[name\]/) do
-            name = slug.split('/').last.gsub('.html', '')
-            "<span class='descname'>#{name}</span>"
-          end
-          
-          # Format constructor parameters
-          content = content.gsub(/\[param:([^\]]+?)\s+([^\]]+?)\]/) do |match|
-            type, name = $1, $2
-            "<span class='sig-param'><span class='sig-type'>#{type}</span> <code class='sig-name'>#{name}</code></span>"
-          end
-          
+          content = handle_name_placeholders(content)
+          content = format_constructor_params(content)
           node.inner_html = content
         end
+      end
 
-        # Clean up property formatting
-        css('h3').each do |node|
-          node.inner_html = node.inner_html.gsub(/\[property:([^\]]+?)\s+([^\]]+?)\]/) do |match|
-            type, name = $1, $2
-            "<dt class='sig sig-object js'>" \
-            "<span class='sig-name descname'>#{name}</span>" \
-            "<span class='sig-colon'>:</span> " \
-            "<span class='sig-type'>#{type}</span></dt>"
+      def handle_source_link(node)
+        content = node.next_element&.inner_html
+        return unless content
+        content = content.gsub(/<[^>]+>/, '')
+        if content =~ /src\/(.*?)\.js/
+          path = "/#{$1}.js"
+          formatted_link = %Q(<a class="reference external" href="https://github.com/mrdoob/three.js/blob/master/src#{path}">src#{path}</a>)
+          node.next_element.inner_html = formatted_link if node.next_element
+        end
+      end
+
+      def handle_method_signatures(content)
+        content
+          .gsub(PATTERNS[:method_this]) { format_method_signature('this', $1, $2) }
+          .gsub(PATTERNS[:method_return]) do |match|
+            next if $2.start_with?('this')
+            format_method_signature($1, $2, $3, true)
           end
+          .gsub(PATTERNS[:method_no_params]) { format_method_signature($1, $2, nil, true) }
+      end
+
+      def format_method_signature(type_or_this, name, params_str, with_return = false)
+        params = if params_str
+          params_str.split(',').map { |param| format_parameter(param.strip) }.join("<span class='sig-paren'>, </span>")
         end
 
-        # Clean up external links
+        html = "<dt class='sig sig-object js' id='#{name}'>"
+        if type_or_this == 'this'
+          html << "<span class='property'><span class='pre'>this</span></span>."
+        end
+        html << "<span class='sig-name descname'>#{name}</span>" \
+               "<span class='sig-paren'>(</span>" \
+               "#{params}" \
+               "<span class='sig-paren'>)</span>"
+        if with_return
+          html << "<span class='sig-returns'><span class='sig-colon'>:</span> " \
+                 "<span class='sig-type'>#{type_or_this}</span></span>"
+        end
+        html << "</dt>"
+      end
+
+      def format_parameter(param)
+        if param.include?(' ')
+          type, name = param.split(' ', 2).map(&:strip)
+          "<span class='sig-param'><span class='sig-type'>#{type}</span> <span class='sig-name'>#{name}</span></span>"
+        else
+          "<span class='sig-param'>#{param}</span>"
+        end
+      end
+
+      def handle_properties(content)
+        content.gsub(PATTERNS[:property]) do |match|
+          type, name = $1, $2
+          "<dt class='sig sig-object js'>" \
+          "<span class='sig-name descname'>#{name}</span>" \
+          "<span class='sig-colon'>:</span> " \
+          "<span class='sig-type'>#{type}</span></dt>"
+        end
+      end
+
+      def handle_name_placeholders(content)
+        content.gsub(PATTERNS[:name_placeholder]) do
+          name = slug.split('/').last.gsub('.html', '')
+          "<span class='descname'>#{name}</span>"
+        end
+      end
+
+      def format_constructor_params(content)
+        content.gsub(PATTERNS[:constructor_param]) do |match|
+          type, name = $1, $2
+          "<span class='sig-param'><span class='sig-type'>#{type}</span> <code class='sig-name'>#{name}</code></span>"
+        end
+      end
+
+      def format_links
         css('*').each do |node|
           next if node.text?
           
-          # Handle example links [example:tag Title]
-          node.inner_html = node.inner_html.gsub(/\[example:([^\s\]]+)\s+([^\]]+)\]/) do |match|
-            tag, title = $1, $2
-            "<a class='reference external' href='https://threejs.org/examples/##{tag}'>#{title}</a>"
-          end
-
-          # Handle external links with [link:url text] format
-          node.inner_html = node.inner_html.gsub(/\[link:([^\s\]]+)\s+([^\]]+)\]/) do |match|
-            url, text = $1, $2
-            "<a class='reference external' href='#{url}'>#{text}</a>"
-          end
+          content = node.inner_html
+            .gsub(PATTERNS[:example_link]) { create_external_link("https://threejs.org/examples/##{$1}", $2) }
+            .gsub(PATTERNS[:external_link_text]) { create_external_link($1, $2) }
+            .gsub(PATTERNS[:external_link]) { create_external_link($1, $1) }
+            .gsub(PATTERNS[:page_link_text]) { create_internal_link($1, $2) }
+            .gsub(PATTERNS[:page_link]) { create_internal_link($1, $1) }
+          
+          node.inner_html = content
+        end
 
-          # Handle external links with [link:url] format
-          node.inner_html = node.inner_html.gsub(/\[link:([^\]]+)\]/) do |match|
-            url = $1
-            "<a class='reference external' href='#{url}'>#{url}</a>"
-          end
+        normalize_href_attributes
+      end
 
-          # Handle internal page links with text
-          node.inner_html = node.inner_html.gsub(/\[page:([^\]]+?)\s+([^\]]+?)\]/) do
-            path, text = $1, $2
-            "<a class='reference internal' href='#{path.downcase}'><code class='xref js js-#{path.downcase}'>#{text}</code></a>"
-          end
+      def create_external_link(url, text)
+        %Q(<a class='reference external' href='#{url}'>#{text}</a>)
+      end
 
-          # Handle internal page links without text
-          node.inner_html = node.inner_html.gsub(/\[page:([^\]]+?)\]/) do |match|
-            path = $1
-            "<a class='reference internal' href='#{path.downcase}'><code class='xref js js-#{path.downcase}'>#{path}</code></a>"
-          end
-        end
+      def create_internal_link(path, text)
+        %Q(<a class='reference internal' href='#{path.downcase}'><code class='xref js js-#{path.downcase}'>#{text}</code></a>)
+      end
 
-        # Fix all href attributes to be lowercase and remove .html
+      def normalize_href_attributes
         css('a[href]').each do |link|
           next if link['href'].start_with?('http')
           link['href'] = link['href'].remove('../').downcase.sub(/\.html$/, '')
           link['class'] = 'reference internal'
         end
+      end
 
-        # Add section classes
+      def add_section_structure
         css('h2').each do |node|
           node['class'] = 'section-title'
           section = node.next_element
-          if section
-            wrapper = doc.document.create_element('div')
-            wrapper['class'] = 'section'
-            node.after(wrapper)
-            wrapper.add_child(node)
-            current = section
-            while current && current.name != 'h2'
-              next_el = current.next
-              wrapper.add_child(current)
-              current = next_el
-            end
+          next unless section
+
+          wrapper = doc.document.create_element('div')
+          wrapper['class'] = 'section'
+          node.after(wrapper)
+          wrapper.add_child(node)
+          
+          current = section
+          while current && current.name != 'h2'
+            next_el = current.next
+            wrapper.add_child(current)
+            current = next_el
           end
         end
 
-        # Format description paragraphs
-        css('p.desc').each do |node|
-          node['class'] = 'section-desc'
-        end
+        css('p.desc').each { |node| node['class'] = 'section-desc' }
+      end
 
-        # Handle inline code/backticks in text
-        css('p, li, dt, dd').each do |node|
-          next if node.at_css('pre') # Skip if contains a code block
+      def format_notes
+        css('p').each do |node|
+          next unless node.content.start_with?('Note:')
           
-          # Replace backticks with proper code formatting
-          node.inner_html = node.inner_html.gsub(/`([^`]+)`/) do |match|
-            code = $1
-            "<code class='docutils literal notranslate'><span class='pre'>#{code}</span></code>"
-          end
+          wrapper = doc.document.create_element('div')
+          wrapper['class'] = 'admonition note'
+          
+          title = doc.document.create_element('p')
+          title['class'] = 'first admonition-title'
+          title.content = 'Note'
+          
+          content = doc.document.create_element('p')
+          content['class'] = 'last'
+          content.inner_html = node.inner_html.sub('Note:', '').strip
+          
+          wrapper.add_child(title)
+          wrapper.add_child(content)
+          node.replace(wrapper)
         end
+      end
 
-        # Handle inline code in property descriptions
-        css('.property-type').each do |node|
-          node.inner_html = node.inner_html.gsub(/`([^`]+)`/) do |match|
-            code = $1
-            "<code class='docutils literal notranslate'><span class='pre'>#{code}</span></code>"
-          end
-        end
-        
-        # Add proper heading IDs and classes
+      def add_heading_attributes
         css('h1, h2, h3, h4').each do |node|
           node['id'] ||= node.content.strip.downcase.gsub(/[^\w]+/, '-')
           existing_class = node['class'].to_s
           node['class'] = "#{existing_class} section-header"
         end
 
-        # Add note styling
-        css('p').each do |node|
-          if node.content.start_with?('Note:')
-            wrapper = doc.document.create_element('div')
-            wrapper['class'] = 'admonition note'
-            
-            title = doc.document.create_element('p')
-            title['class'] = 'first admonition-title'
-            title.content = 'Note'
-            
-            content = doc.document.create_element('p')
-            content['class'] = 'last'
-            content.inner_html = node.inner_html.sub('Note:', '').strip
-            
-            wrapper.add_child(title)
-            wrapper.add_child(content)
-            node.replace(wrapper)
+        format_inline_code
+      end
+
+      def format_inline_code
+        selectors = ['p', 'li', 'dt', 'dd', '.property-type'].join(', ')
+        css(selectors).each do |node|
+          next if node.at_css('pre')
+          node.inner_html = node.inner_html.gsub(PATTERNS[:inline_code]) do |match|
+            "<code class='docutils literal notranslate'><span class='pre'>#{$1}</span></code>"
           end
         end
-        doc
       end
     end
   end

From 8ec3a27b0149f67f52392187eb7ce9bb36789fea Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Wed, 25 Dec 2024 14:12:12 -0600
Subject: [PATCH 155/384] remove scss since using the simple style

---
 assets/stylesheets/application.css.scss |  1 -
 assets/stylesheets/pages/_threejs.scss  | 47 -------------------------
 2 files changed, 48 deletions(-)
 delete mode 100644 assets/stylesheets/pages/_threejs.scss

diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss
index d2887ba994..3823cdc3d8 100644
--- a/assets/stylesheets/application.css.scss
+++ b/assets/stylesheets/application.css.scss
@@ -131,7 +131,6 @@
         'pages/tcl_tk',
         'pages/tensorflow',
         'pages/terraform',
-        'pages/threejs',
         'pages/typescript',
         'pages/underscore',
         'pages/vue',
diff --git a/assets/stylesheets/pages/_threejs.scss b/assets/stylesheets/pages/_threejs.scss
deleted file mode 100644
index 8996ba0bf9..0000000000
--- a/assets/stylesheets/pages/_threejs.scss
+++ /dev/null
@@ -1,47 +0,0 @@
-._threejs {
-    // Code blocks
-    pre, code {
-      background-color: #f5f5f5;
-      border-radius: 3px;
-      padding: 0.2em 0.4em;
-    }
-    pre {
-      padding: 1em;
-      margin: 1em 0;
-      overflow: auto;
-      code {
-        background: none;
-        padding: 0;
-      }
-    }
-    // Links
-    a {
-      color: #049EF4;
-      text-decoration: none;
-      &:hover {
-        text-decoration: underline;
-      }
-    }
-    // Headings
-    h2 {
-      margin-top: 2em;
-      padding-bottom: 0.3em;
-      border-bottom: 1px solid #eaecef;
-    }
-    h3 {
-      margin-top: 1.5em;
-    }
-    // Tables
-    table {
-      border-collapse: collapse;
-      margin: 1em 0;
-      width: 100%;
-    }
-    th, td {
-      border: 1px solid #dfe2e5;
-      padding: 6px 13px;
-    }
-    tr:nth-child(2n) {
-      background-color: #f6f8fa;
-    }
-  } 
\ No newline at end of file

From 35b7c733670bab2f1c289d5f890f277a5c891c89 Mon Sep 17 00:00:00 2001
From: Chaitanya Rahalkar <chaitanyarahalkar4@gmail.com>
Date: Wed, 25 Dec 2024 14:19:54 -0600
Subject: [PATCH 156/384] update tmp folder to use the rails project temp
 folder

---
 docs/file-scrapers.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index 923bac2061..55ba555268 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -298,7 +298,7 @@ Make sure to set the version per the release tag (e.g. r160). Note that the r pr
 curl https://codeload.github.com/mrdoob/three.js/tar.gz/refs/tags/r${VERSION} > threejs.tar.gz
 tar -xzf threejs.tar.gz
 mkdir -p docs/threejs~${VERSION}
-mv three.js-r${VERSION}/list.json /tmp/list.json
+mv three.js-r${VERSION}/list.json tmp/list.json
 mv three.js-r${VERSION}/docs/* docs/threejs~${VERSION}/
 
 rm -rf three.js-r${VERSION}/

From 97ca46f0a8d7020449640f14606f42bfbf5a9cf3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 26 Dec 2024 12:03:04 +0000
Subject: [PATCH 157/384] chore(deps): update ruby/setup-ruby action to
 v1.206.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1d1ebf340c..f15a6ea092 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@540484a3c0f308b08619664ec40bf6c371d172c3 # v1.205.0
+      uses: ruby/setup-ruby@bfefad842bb982ff05b233bcbc1571d97a87e69f # v1.206.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 2fd07e3d08..358df7dc91 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@540484a3c0f308b08619664ec40bf6c371d172c3 # v1.205.0
+      uses: ruby/setup-ruby@bfefad842bb982ff05b233bcbc1571d97a87e69f # v1.206.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9caecfd7dc..cb6f3e85d6 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@540484a3c0f308b08619664ec40bf6c371d172c3 # v1.205.0
+      uses: ruby/setup-ruby@bfefad842bb982ff05b233bcbc1571d97a87e69f # v1.206.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 453769efc5ebb44de17fc271cc46df498912ca50 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 29 Dec 2024 22:40:44 +0000
Subject: [PATCH 158/384] chore(deps): update dependency nokogiri to v1.18.1

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index fbe12c49d1..d959191b1f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -61,7 +61,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.0)
+    nokogiri (1.18.1)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From 34a025014328d40c572bb1c2cb614abba18aa1c3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 30 Dec 2024 23:21:04 +0000
Subject: [PATCH 159/384] chore(deps): update ruby/setup-ruby action to
 v1.207.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f15a6ea092..4186e82309 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bfefad842bb982ff05b233bcbc1571d97a87e69f # v1.206.0
+      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 358df7dc91..f648bf1da3 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bfefad842bb982ff05b233bcbc1571d97a87e69f # v1.206.0
+      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index cb6f3e85d6..358a8b018e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bfefad842bb982ff05b233bcbc1571d97a87e69f # v1.206.0
+      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 38f4be018f357d09f9f5de081f9fa20db7c4cedb Mon Sep 17 00:00:00 2001
From: Stefan Breunig <307954+breunigs@users.noreply.github.com>
Date: Sun, 5 Jan 2025 14:11:46 +0100
Subject: [PATCH 160/384] Update Elixir documentation (1.18)

---
 lib/docs/filters/elixir/clean_html.rb |  4 +++-
 lib/docs/scrapers/elixir.rb           | 12 ++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/lib/docs/filters/elixir/clean_html.rb b/lib/docs/filters/elixir/clean_html.rb
index 6783afb25c..2d656ff65d 100644
--- a/lib/docs/filters/elixir/clean_html.rb
+++ b/lib/docs/filters/elixir/clean_html.rb
@@ -34,7 +34,9 @@ def api
             node.name = 'h3'
             node['id'] = id
 
-            source_href = node.at_css('a.icon-action[title="View Source"]').attr('href')
+            a = node.at_css('a.icon-action[title="View Source"]')
+            a ||= node.at_css('a.icon-action[aria-label="View Source"]')
+            source_href = a.attr('href')
 
             node.content = node.at_css('.signature').inner_text
             node << %(<a href="#{source_href}" class="source">Source</a>)
diff --git a/lib/docs/scrapers/elixir.rb b/lib/docs/scrapers/elixir.rb
index 47f361e695..14b3c1645c 100644
--- a/lib/docs/scrapers/elixir.rb
+++ b/lib/docs/scrapers/elixir.rb
@@ -30,6 +30,18 @@ def initial_urls
         "https://hexdocs.pm/mix/#{self.class.release}/Mix.html" ]
     end
 
+    version '1.18' do
+      self.release = '1.18.1'
+      self.base_urls = [
+        "https://hexdocs.pm/elixir/#{release}/",
+        "https://hexdocs.pm/eex/#{release}/",
+        "https://hexdocs.pm/ex_unit/#{release}/",
+        "https://hexdocs.pm/iex/#{release}/",
+        "https://hexdocs.pm/logger/#{release}/",
+        "https://hexdocs.pm/mix/#{release}/"
+      ]
+    end
+
     version '1.17' do
       self.release = '1.17.2'
       self.base_urls = [

From a2a3cb0a88055f9d0d2540901b402a0bdb9713fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Fri, 10 Jan 2025 13:27:07 +0100
Subject: [PATCH 161/384] Update crystal docs to 1.15.0

---
 lib/docs/scrapers/crystal.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index c06d2fa7df..ee92d0d8f5 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -2,7 +2,7 @@ module Docs
   class Crystal < UrlScraper
     include MultipleBaseUrls
     self.type = 'crystal'
-    self.release = '1.14.0'
+    self.release = '1.15.0'
     self.base_urls = [
       "https://crystal-lang.org/api/#{release}/",
       "https://crystal-lang.org/reference/#{release[0..2]}/",

From 8f57d64457ada032d6f75bf887bbaea3c653a6f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Fri, 10 Jan 2025 13:27:29 +0100
Subject: [PATCH 162/384] Bump copyright year

---
 lib/docs/scrapers/crystal.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index ee92d0d8f5..92faf4683f 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -34,7 +34,7 @@ def initial_urls
         HTML
       else
         <<-HTML
-          &copy; 2012&ndash;2024 Manas Technology Solutions.<br>
+          &copy; 2012&ndash;2025 Manas Technology Solutions.<br>
           Licensed under the Apache License, Version 2.0.
         HTML
       end

From 937326d437d3fbafcdb8b9f4432a2fa24e7feb0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Sat, 11 Jan 2025 10:08:42 +0100
Subject: [PATCH 163/384] Exclude non-existing Crystal/PointerPairingHeap from
 scraping

---
 lib/docs/scrapers/crystal.rb | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index 92faf4683f..caa178f2b0 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -21,6 +21,7 @@ def initial_urls
 
     options[:skip_patterns] = [
       %r{\ACrystal/System/},
+      %r{\ACrystal/PointerPairingHeap/},
       %r{\AIO/Evented.html\z},
       %r{\ARegex/PCRE2.html\z}
     ]

From a4067b6506faf52584fcedff85acca263a99821a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 11 Jan 2025 11:41:15 +0000
Subject: [PATCH 164/384] chore(deps): update dependency ruby to v3.4.1

---
 .ruby-version     | 2 +-
 .tool-versions    | 2 +-
 Dockerfile        | 2 +-
 Dockerfile-alpine | 2 +-
 Gemfile           | 2 +-
 Gemfile.lock      | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.ruby-version b/.ruby-version
index 9c25013dbb..47b322c971 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.3.6
+3.4.1
diff --git a/.tool-versions b/.tool-versions
index 5aa8e0c30b..041df9aa68 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1 @@
-ruby 3.3.6
+ruby 3.4.1
diff --git a/Dockerfile b/Dockerfile
index 7ec33c21b8..d52cd1de4c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:3.3.6
+FROM ruby:3.4.1
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
 
diff --git a/Dockerfile-alpine b/Dockerfile-alpine
index 1d258221a9..67b3d96836 100644
--- a/Dockerfile-alpine
+++ b/Dockerfile-alpine
@@ -1,4 +1,4 @@
-FROM ruby:3.3.6-alpine
+FROM ruby:3.4.1-alpine
 
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
diff --git a/Gemfile b/Gemfile
index 9079b2c955..59403526a8 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,5 @@
 source 'https://rubygems.org'
-ruby '3.3.6'
+ruby '3.4.1'
 
 gem 'activesupport', require: false
 gem 'html-pipeline'
diff --git a/Gemfile.lock b/Gemfile.lock
index 0707225d27..1ca44c060b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -187,7 +187,7 @@ DEPENDENCIES
   yajl-ruby
 
 RUBY VERSION
-   ruby 3.3.6p108
+   ruby 3.4.1p0
 
 BUNDLED WITH
    2.4.6

From ce09955658ff5557dac0c7cd2b778fd97a6b2af6 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 11 Jan 2025 12:43:45 +0100
Subject: [PATCH 165/384] Update manifest_test for Ruby 3.4.1

---
 test/lib/docs/core/manifest_test.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/lib/docs/core/manifest_test.rb b/test/lib/docs/core/manifest_test.rb
index 60d5ba90e3..1a06cf280c 100644
--- a/test/lib/docs/core/manifest_test.rb
+++ b/test/lib/docs/core/manifest_test.rb
@@ -64,7 +64,7 @@ class ManifestTest < Minitest::Spec
       it "includes the doc's meta representation" do
         json = manifest.as_json
         assert_equal 1, json.length
-        assert_equal "{\"name\"=>\"Test\", \"db_size\"=>776533, :attribution=>\"foo\", :alias=>nil}", json[0].to_s
+        assert_equal "{\"name\" => \"Test\", \"db_size\" => 776533, attribution: \"foo\", alias: nil}", json[0].to_s
       end
     end
 

From 746f67c19066976db2ac41ef4ef89e259c7c8e42 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 11 Jan 2025 12:45:01 +0100
Subject: [PATCH 166/384] `bundle update progress_bar` for Ruby 3.4.1

---
 Gemfile.lock | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 1ca44c060b..b3a40343d0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -36,7 +36,8 @@ GEM
     exifr (1.4.0)
     ffi (1.15.5)
     fspath (3.1.2)
-    highline (2.0.3)
+    highline (3.1.2)
+      reline
     html-pipeline (2.14.3)
       activesupport (>= 2)
       nokogiri (>= 1.4)
@@ -53,6 +54,7 @@ GEM
       image_optim (~> 0.19)
     image_size (3.3.0)
     in_threads (1.6.0)
+    io-console (0.8.0)
     logger (1.6.2)
     method_source (1.0.0)
     mini_portile2 (2.8.8)
@@ -88,6 +90,8 @@ GEM
     rb-inotify (0.10.1)
       ffi (~> 1.0)
     redcarpet (3.6.0)
+    reline (0.6.0)
+      io-console (~> 0.5)
     rexml (3.3.9)
     rouge (1.11.1)
     rr (3.1.1)

From 62d30c70f91b3bda334c993ca145434cbb8b2f76 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 11 Jan 2025 13:03:09 +0100
Subject: [PATCH 167/384] Update Bazel documentation (8.0.0)

---
 lib/docs/filters/bazel/clean_html.rb | 2 ++
 lib/docs/scrapers/bazel.rb           | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/lib/docs/filters/bazel/clean_html.rb b/lib/docs/filters/bazel/clean_html.rb
index d772908e32..ca827b36e9 100644
--- a/lib/docs/filters/bazel/clean_html.rb
+++ b/lib/docs/filters/bazel/clean_html.rb
@@ -7,8 +7,10 @@ def call
         css('devsite-feature-tooltip').remove
         css('devsite-thumb-rating').remove
         css('devsite-toc').remove
+        css('devsite-feedback').remove
         css('a.button-with-icon').remove
         css('button.devsite-heading-link').remove
+        css('.devsite-article-body > span:first-child[style="float: right; line-height: 36px"]').remove
         doc
       end
 
diff --git a/lib/docs/scrapers/bazel.rb b/lib/docs/scrapers/bazel.rb
index 3f2f944747..fe37137ab3 100644
--- a/lib/docs/scrapers/bazel.rb
+++ b/lib/docs/scrapers/bazel.rb
@@ -12,6 +12,11 @@ class Bazel < UrlScraper
     Licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License.
     HTML
 
+    version '8.0' do
+      self.release = '8.0.0'
+      self.base_url = 'https://bazel.build/versions/8.0.0/reference/be/'
+    end
+
     version '7.0' do
       self.release = '7.0.0'
       self.base_url = 'https://bazel.build/versions/7.0.0/reference/be/'

From 570b3f3ce0b66aaa6f8c854fe52dd92100018723 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 11 Jan 2025 13:18:32 +0100
Subject: [PATCH 168/384] Update FastAPI documentation (0.115.6)

---
 lib/docs/scrapers/fastapi.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/fastapi.rb b/lib/docs/scrapers/fastapi.rb
index ed85793406..d5b3f4e5d5 100644
--- a/lib/docs/scrapers/fastapi.rb
+++ b/lib/docs/scrapers/fastapi.rb
@@ -2,7 +2,7 @@ module Docs
   class Fastapi < UrlScraper
     self.name = 'FastAPI'
     self.type = 'fastapi'
-    self.release = '0.111.1'
+    self.release = '0.115.6'
     self.base_url = 'https://fastapi.tiangolo.com/'
     self.root_path = '/'
     self.links = {

From 3e95aa2cd782e699bde61d8a6d610df18b9b0e1f Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 11 Jan 2025 13:24:15 +0100
Subject: [PATCH 169/384] Update Ruby on Rails documentation (8.0.1)

---
 lib/docs/scrapers/rdoc/rails.rb | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/docs/scrapers/rdoc/rails.rb b/lib/docs/scrapers/rdoc/rails.rb
index 414bd4a537..03aad4a356 100644
--- a/lib/docs/scrapers/rdoc/rails.rb
+++ b/lib/docs/scrapers/rdoc/rails.rb
@@ -75,6 +75,10 @@ class Rails < Rdoc
       end
     end
 
+    version '8.0' do
+      self.release = '8.0.1'
+    end
+
     version '7.2' do
       self.release = '7.2.1'
     end

From 264b5cc2640411a18ba1747fc71ee09b632d7a58 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 11 Jan 2025 13:28:10 +0100
Subject: [PATCH 170/384] Update Ruby / Minitest documentation (5.25.4)

---
 docs/file-scrapers.md              | 11 +++++++++++
 lib/docs/scrapers/rdoc/minitest.rb |  7 +------
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index 2f8fd8f38e..9ab9739e2c 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -254,6 +254,17 @@ done
 
 ### Nokogiri
 ### Ruby / Minitest
+
+```sh
+git clone https://github.com/seattlerb/minitest
+cd minitest/
+bundle install
+bundle add rdoc hoe
+bundle exec rak docs
+cd ..
+cp -r minitest/docs $DEVDOCS/docs/minitest
+```
+
 ### Ruby on Rails
 * Download a release at https://github.com/rails/rails/releases or clone https://github.com/rails/rails.git (checkout to the branch of the rails' version that is going to be scraped)
 * Open `railties/lib/rails/api/task.rb` and comment out any code related to sdoc (`configure_sdoc`)
diff --git a/lib/docs/scrapers/rdoc/minitest.rb b/lib/docs/scrapers/rdoc/minitest.rb
index 2ff12cf496..a502343590 100644
--- a/lib/docs/scrapers/rdoc/minitest.rb
+++ b/lib/docs/scrapers/rdoc/minitest.rb
@@ -1,14 +1,9 @@
 module Docs
   class Minitest < Rdoc
-    # Instructions:
-    #   1. Run "gem update rdoc hoe"
-    #   2. Download the source code at https://github.com/seattlerb/minitest
-    #   3. Run "rake docs" (in the Minitest directory)
-    #   4. Copy the "docs" directory to "docs/minitest"
 
     self.name = 'Ruby / Minitest'
     self.slug = 'minitest'
-    self.release = '5.20.0'
+    self.release = '5.25.4'
     self.links = {
       code: 'https://github.com/minitest/minitest'
     }

From c70878abe04bbe8d031a8b8c42def2f2d7712c38 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 11 Jan 2025 15:51:47 +0100
Subject: [PATCH 171/384] Update scikit-learn documentation (1.6.1)

---
 lib/docs/filters/scikit_learn/clean_html.rb | 1 +
 lib/docs/scrapers/scikit_learn.rb           | 8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/lib/docs/filters/scikit_learn/clean_html.rb b/lib/docs/filters/scikit_learn/clean_html.rb
index 530df12dbe..afcd2c2a6b 100644
--- a/lib/docs/filters/scikit_learn/clean_html.rb
+++ b/lib/docs/filters/scikit_learn/clean_html.rb
@@ -2,6 +2,7 @@ module Docs
   class ScikitLearn
     class CleanHtmlFilter < Filter
       def call
+        @doc = at_css('main article', 'main')
         if root_page?
           css('.row').each do |node|
             html = '<dl>'
diff --git a/lib/docs/scrapers/scikit_learn.rb b/lib/docs/scrapers/scikit_learn.rb
index 45268c4b95..564b5a30a5 100644
--- a/lib/docs/scrapers/scikit_learn.rb
+++ b/lib/docs/scrapers/scikit_learn.rb
@@ -3,8 +3,9 @@ class ScikitLearn < UrlScraper
     self.name = 'scikit-learn'
     self.slug = 'scikit_learn'
     self.type = 'sphinx'
-    self.release = '1.1.3'
-    self.base_url = "https://scikit-learn.org/1.1/"
+    self.release = '1.6.1'
+    v = self.release[/\d+\.\d+/]
+    self.base_url = "https://scikit-learn.org/#{v}/"
     self.root_path = 'index.html'
     self.force_gzip = true
     self.links = {
@@ -14,7 +15,6 @@ class ScikitLearn < UrlScraper
 
     html_filters.push 'scikit_learn/entries', 'scikit_learn/clean_html', 'sphinx/clean_html', 'title'
 
-    options[:container] = ->(filter) { filter.root_page? ? 'body > .container' : '#sk-page-content-wrapper > .body' }
     options[:skip] = %w(modules/generated/sklearn.experimental.enable_iterative_imputer.html
                         modules/generated/sklearn.experimental.enable_hist_gradient_boosting.html)
     options[:only_patterns] = [/\Amodules/, /\Adatasets/, /\Atutorial/, /\Aauto_examples/]
@@ -24,7 +24,7 @@ class ScikitLearn < UrlScraper
     options[:max_image_size] = 256_000
 
     options[:attribution] = <<-HTML
-      &copy; 2007&ndash;2022 The scikit-learn developers<br>
+      &copy; 2007&ndash;2025 The scikit-learn developers<br>
       Licensed under the 3-clause BSD License.
     HTML
 

From 1dacda29a8ad1c6851c03a88522aa56ec07bac84 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sat, 11 Jan 2025 16:06:10 +0100
Subject: [PATCH 172/384] Update scikit-image documentation (0.25.0)

---
 lib/docs/filters/scikit_image/entries.rb | 3 ++-
 lib/docs/scrapers/scikit_image.rb        | 8 +++++---
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/lib/docs/filters/scikit_image/entries.rb b/lib/docs/filters/scikit_image/entries.rb
index 108eb2ce7f..f3ec975b33 100644
--- a/lib/docs/filters/scikit_image/entries.rb
+++ b/lib/docs/filters/scikit_image/entries.rb
@@ -3,7 +3,8 @@ class ScikitImage
     class EntriesFilter < Docs::EntriesFilter
       def get_name
         name = at_css('h1').content.strip
-        name.remove! "\u{00b6}"
+        name.delete_suffix! "¶"
+        name.delete_suffix! "#"
 
         if slug.start_with?('api')
           name.remove! 'Module: '
diff --git a/lib/docs/scrapers/scikit_image.rb b/lib/docs/scrapers/scikit_image.rb
index 368e03f71e..66014c0f43 100644
--- a/lib/docs/scrapers/scikit_image.rb
+++ b/lib/docs/scrapers/scikit_image.rb
@@ -3,8 +3,10 @@ class ScikitImage < UrlScraper
     self.name = 'scikit-image'
     self.slug = 'scikit_image'
     self.type = 'sphinx'
-    self.release = '0.18.1'
-    self.base_url = 'https://scikit-image.org/docs/0.18.x/'
+    self.release = '0.25.0'
+    v = self.release[/\d+\.\d+/]
+    self.base_url = "https://scikit-image.org/docs/#{v}.x/"
+    self.initial_paths = %w(/ /api/ /user_guide/)
     self.links = {
       home: 'https://scikit-image.org/',
       code: 'https://github.com/scikit-image/scikit-image'
@@ -12,7 +14,7 @@ class ScikitImage < UrlScraper
 
     html_filters.push 'scikit_image/entries', 'sphinx/clean_html'
 
-    options[:container] = '.span9'
+    options[:container] = 'main article'
     options[:skip] = %w(api_changes.html)
     options[:only_patterns] = [/\Aapi/, /\Auser_guide/]
 

From 251f92e291f0aa68f4aecd764bc0b41c3f5e6c77 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 15 Jan 2025 21:18:10 +0000
Subject: [PATCH 173/384] chore(deps): update ruby/setup-ruby action to
 v1.208.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4186e82309..e0c5685617 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
+      uses: ruby/setup-ruby@868b3f088412f139260f27f5b148179b9dd6b008 # v1.208.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index f648bf1da3..0eef028eda 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
+      uses: ruby/setup-ruby@868b3f088412f139260f27f5b148179b9dd6b008 # v1.208.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 358a8b018e..bbbab2a9f1 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
+      uses: ruby/setup-ruby@868b3f088412f139260f27f5b148179b9dd6b008 # v1.208.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 5fef97636a2c4c6289960044350b7800f2eef0ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Fri, 17 Jan 2025 09:16:05 +0100
Subject: [PATCH 174/384] Use fully qualified name

---
 lib/docs/filters/crystal/entries.rb | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/docs/filters/crystal/entries.rb b/lib/docs/filters/crystal/entries.rb
index 3727bdf2ff..151efbdc5f 100644
--- a/lib/docs/filters/crystal/entries.rb
+++ b/lib/docs/filters/crystal/entries.rb
@@ -16,8 +16,12 @@ def get_name
           name
         else
           return at_css('h1').content.strip unless at_css('.type-name')
-          name = at_css('.type-name').children.last.content.strip
+          name = at_css('.type-name').children.reject { |n| n.matches?('.kind') }
+          name.map! { |n| n.text.strip }
+          name.reject! &:empty?
+          name = name.join
           name.remove! %r{\(.*\)}
+          name.strip!
           name
         end
       end

From 081b3ea7dd9971ff509011a18c092531300525b3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 17 Jan 2025 13:42:11 +0000
Subject: [PATCH 175/384] chore(deps): update ruby/setup-ruby action to
 v1.209.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e0c5685617..bd921fcdbd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@868b3f088412f139260f27f5b148179b9dd6b008 # v1.208.0
+      uses: ruby/setup-ruby@7a6302104fbeea3c6aaa43b1b91e08f7d6623279 # v1.209.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 0eef028eda..74bf07e5ba 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@868b3f088412f139260f27f5b148179b9dd6b008 # v1.208.0
+      uses: ruby/setup-ruby@7a6302104fbeea3c6aaa43b1b91e08f7d6623279 # v1.209.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index bbbab2a9f1..a27e4f75cc 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@868b3f088412f139260f27f5b148179b9dd6b008 # v1.208.0
+      uses: ruby/setup-ruby@7a6302104fbeea3c6aaa43b1b91e08f7d6623279 # v1.209.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From a26af28a093126fd8db43db397371dfb053dc930 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 17 Jan 2025 20:24:06 +0000
Subject: [PATCH 176/384] chore(deps): update ruby/setup-ruby action to
 v1.210.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index bd921fcdbd..cc0117f3f7 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7a6302104fbeea3c6aaa43b1b91e08f7d6623279 # v1.209.0
+      uses: ruby/setup-ruby@1d542747a7bad621e02253945b8491142044d3b7 # v1.210.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 74bf07e5ba..e03ef32643 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7a6302104fbeea3c6aaa43b1b91e08f7d6623279 # v1.209.0
+      uses: ruby/setup-ruby@1d542747a7bad621e02253945b8491142044d3b7 # v1.210.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a27e4f75cc..d9460ec22a 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7a6302104fbeea3c6aaa43b1b91e08f7d6623279 # v1.209.0
+      uses: ruby/setup-ruby@1d542747a7bad621e02253945b8491142044d3b7 # v1.210.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 5883978fdaf19f77520b2223af2648f181edf282 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 18 Jan 2025 13:15:45 +0000
Subject: [PATCH 177/384] chore(deps): update ruby/setup-ruby action to
 v1.211.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cc0117f3f7..7c65b2ea4d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1d542747a7bad621e02253945b8491142044d3b7 # v1.210.0
+      uses: ruby/setup-ruby@87b48937c9ec5a4ccd60bd3c5177d64108125904 # v1.211.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index e03ef32643..e82eb8c54d 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1d542747a7bad621e02253945b8491142044d3b7 # v1.210.0
+      uses: ruby/setup-ruby@87b48937c9ec5a4ccd60bd3c5177d64108125904 # v1.211.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index d9460ec22a..d306b17e2d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1d542747a7bad621e02253945b8491142044d3b7 # v1.210.0
+      uses: ruby/setup-ruby@87b48937c9ec5a4ccd60bd3c5177d64108125904 # v1.211.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 61a4299c64055e4dc8fc8b8862499f8074230033 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 19 Jan 2025 00:50:34 +0000
Subject: [PATCH 178/384] chore(deps): update ruby/setup-ruby action to
 v1.213.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7c65b2ea4d..19b746f12c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@87b48937c9ec5a4ccd60bd3c5177d64108125904 # v1.211.0
+      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index e82eb8c54d..dec53a8a59 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@87b48937c9ec5a4ccd60bd3c5177d64108125904 # v1.211.0
+      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index d306b17e2d..2e64d09d06 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@87b48937c9ec5a4ccd60bd3c5177d64108125904 # v1.211.0
+      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From ee68e5aa68f3d4d353670c43eec72a613e23b96e Mon Sep 17 00:00:00 2001
From: Benjamin Cook <cookbenjamin@gmail.com>
Date: Sun, 19 Jan 2025 20:32:58 +1000
Subject: [PATCH 179/384] Fix a typo in the name of the docker image in the
 readme

---
 README.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 97df20a1d8..fa83c7e01b 100644
--- a/README.md
+++ b/README.md
@@ -25,12 +25,12 @@ Unless you wish to contribute to the project, we recommend using the hosted vers
 The easiest way to run DevDocs locally is using Docker:
 
 ```sh
-docker run --name devdocs -d -p 9292:9292 ghcr.io/freecodcamp/devdocs:latest
+docker run --name devdocs -d -p 9292:9292 ghcr.io/freecodecamp/devdocs:latest
 ```
 
 This will start DevDocs at [localhost:9292](http://localhost:9292). We provide both regular and Alpine-based images:
-- `ghcr.io/freecodcamp/devdocs:latest` - Standard image
-- `ghcr.io/freecodcamp/devdocs:latest-alpine` - Alpine-based (smaller size)
+- `ghcr.io/freecodecamp/devdocs:latest` - Standard image
+- `ghcr.io/freecodecamp/devdocs:latest-alpine` - Alpine-based (smaller size)
 
 Images are automatically built and updated monthly with the latest documentation.
 

From b6cb76486c6792ed4d675adbc1d03b505179852b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 19 Jan 2025 21:14:11 +0000
Subject: [PATCH 180/384] chore(deps): update dependency nokogiri to v1.18.2

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index b3a40343d0..59b7525838 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -63,7 +63,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.1)
+    nokogiri (1.18.2)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From 401aca0f3abad08debc0cf0a0ba43a14b2d4c70e Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 20 Jan 2025 13:59:48 +0000
Subject: [PATCH 181/384] chore(deps): update dependency terser to v1.2.5

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 59b7525838..dceb7f0a05 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -130,7 +130,7 @@ GEM
     strings-ansi (0.2.0)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
-    terser (1.2.4)
+    terser (1.2.5)
       execjs (>= 0.3.0, < 3)
     thin (1.8.2)
       daemons (~> 1.0, >= 1.0.9)

From afeaa76e793b50f9c3a2c4f9ac90cb92dbc75809 Mon Sep 17 00:00:00 2001
From: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Date: Tue, 21 Jan 2025 11:17:46 +0100
Subject: [PATCH 182/384] Revert "chore(deps): update ruby/setup-ruby action to
 v1.208.0"

This reverts commit 251f92e291f0aa68f4aecd764bc0b41c3f5e6c77.

Test to see if this fixes the deployments
---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 19b746f12c..4186e82309 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
+      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index dec53a8a59..f648bf1da3 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
+      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 2e64d09d06..358a8b018e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
+      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From a9d3e21d5424dcf5ae5609c971884a02c8dd1463 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 21 Jan 2025 10:20:32 +0000
Subject: [PATCH 183/384] chore(deps): update ruby/setup-ruby action to
 v1.213.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4186e82309..19b746f12c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
+      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index f648bf1da3..dec53a8a59 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
+      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 358a8b018e..2e64d09d06 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
+      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 855cc081c65cebb251da61f54daae535de912f53 Mon Sep 17 00:00:00 2001
From: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Date: Tue, 21 Jan 2025 12:17:23 +0100
Subject: [PATCH 184/384] fix: prevent compression with Accept-Encoding

It seems that (apparently randomly) the index.json files are getting
compressed and causing URI.open to fail. Possibly, it's a little
unclear.

Nonetheless, sending the "Accept-Encoding" of "identity" seems to do the
trick.
---
 lib/tasks/docs.thor | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/tasks/docs.thor b/lib/tasks/docs.thor
index 5b85a8b02c..6e953e4f50 100644
--- a/lib/tasks/docs.thor
+++ b/lib/tasks/docs.thor
@@ -239,7 +239,7 @@ class DocsCLI < Thor
           ['index.json', 'meta.json'].each do |filename|
             json = "https://documents.devdocs.io/#{doc.path}/#{filename}?#{time}"
             begin
-              URI.open(json) do |file|
+              URI.open(json, "Accept-Encoding" => "identity") do |file|
                 mutex.synchronize do
                   path = File.join(dir, filename)
                   File.write(path, file.read)

From 798a8af90237b1180719438005dbed20ebeb9769 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 21 Jan 2025 14:07:52 +0000
Subject: [PATCH 185/384] chore(deps): update dependency sinatra to v4
 [security]

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index dceb7f0a05..a0ab80a944 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -137,7 +137,7 @@ GEM
       eventmachine (~> 1.0, >= 1.0.4)
       rack (>= 1, < 3)
     thor (1.3.2)
-    tilt (2.5.0)
+    tilt (2.6.0)
     tty-pager (0.14.0)
       strings (~> 0.2.0)
       tty-screen (~> 0.8)

From 48bc1807e02427bf4e4c688248d7d070ffa50161 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 27 Jan 2025 18:33:13 +0000
Subject: [PATCH 186/384] chore(deps): update ruby/setup-ruby action to
 v1.214.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 19b746f12c..0abefe4fdc 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
+      uses: ruby/setup-ruby@1287d2b408066abada82d5ad1c63652e758428d9 # v1.214.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index dec53a8a59..e689dc63e6 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
+      uses: ruby/setup-ruby@1287d2b408066abada82d5ad1c63652e758428d9 # v1.214.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 2e64d09d06..35ca2244ed 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
+      uses: ruby/setup-ruby@1287d2b408066abada82d5ad1c63652e758428d9 # v1.214.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 9f62aa30cf82781848c281030ab57f8b67002e99 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 30 Jan 2025 13:46:47 +0000
Subject: [PATCH 187/384] chore(deps): update ruby/setup-ruby action to
 v1.215.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0abefe4fdc..b9a9d02c58 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1287d2b408066abada82d5ad1c63652e758428d9 # v1.214.0
+      uses: ruby/setup-ruby@2654679fe7f7c29875c669398a8ec0791b8a64a1 # v1.215.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index e689dc63e6..241d0563c9 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1287d2b408066abada82d5ad1c63652e758428d9 # v1.214.0
+      uses: ruby/setup-ruby@2654679fe7f7c29875c669398a8ec0791b8a64a1 # v1.215.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 35ca2244ed..68eeecffb9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1287d2b408066abada82d5ad1c63652e758428d9 # v1.214.0
+      uses: ruby/setup-ruby@2654679fe7f7c29875c669398a8ec0791b8a64a1 # v1.215.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From cb3bb1d76e32c677716ba157b054f5c98e57cd75 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 30 Jan 2025 19:12:37 +0100
Subject: [PATCH 188/384] Update JavaScript documentation

---
 lib/docs/filters/core/normalize_urls.rb | 2 +-
 lib/docs/scrapers/mdn/javascript.rb     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/filters/core/normalize_urls.rb b/lib/docs/filters/core/normalize_urls.rb
index cd1888a84c..9834b32d2a 100644
--- a/lib/docs/filters/core/normalize_urls.rb
+++ b/lib/docs/filters/core/normalize_urls.rb
@@ -42,7 +42,7 @@ def to_absolute_url(str)
     def fix_url(url)
       if context[:redirections]
         url = URL.parse(url)
-        path = url.path.downcase
+        path = url.path ? url.path.downcase : nil
 
         if context[:redirections].key?(path)
           url.path = context[:redirections][path]
diff --git a/lib/docs/scrapers/mdn/javascript.rb b/lib/docs/scrapers/mdn/javascript.rb
index e6aabdb1a9..5c9f4d0c1d 100644
--- a/lib/docs/scrapers/mdn/javascript.rb
+++ b/lib/docs/scrapers/mdn/javascript.rb
@@ -3,7 +3,7 @@ class Javascript < Mdn
     prepend FixInternalUrlsBehavior
     prepend FixRedirectionsBehavior
 
-    # release = '2024-11-18'
+    # release = '2025-01-30'
     self.name = 'JavaScript'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference'
     self.links = {

From a2b9b2a77ef5f8fc7370c85ce97bac28f0a0fd88 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 30 Jan 2025 19:27:02 +0100
Subject: [PATCH 189/384] Update MDN documentations

---
 assets/stylesheets/pages/_mdn.scss | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/assets/stylesheets/pages/_mdn.scss b/assets/stylesheets/pages/_mdn.scss
index 51f2b6c56b..9155df4534 100644
--- a/assets/stylesheets/pages/_mdn.scss
+++ b/assets/stylesheets/pages/_mdn.scss
@@ -28,6 +28,9 @@
 
   p > code, li > code { @extend %label; }
 
+  details { @extend %box; }
+  summary > div { display: inline; }
+
   > .note,
   .notecard, // MDN 2021
   .notice,

From 0214b5d528f7cadf6ae63e37750bfc677894bed8 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 30 Jan 2025 19:46:01 +0100
Subject: [PATCH 190/384] Update Web APIs documentation

---
 lib/docs/scrapers/mdn/dom.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/mdn/dom.rb b/lib/docs/scrapers/mdn/dom.rb
index 3023e20c88..322d65d03f 100644
--- a/lib/docs/scrapers/mdn/dom.rb
+++ b/lib/docs/scrapers/mdn/dom.rb
@@ -1,6 +1,6 @@
 module Docs
   class Dom < Mdn
-    # release = '2023-08-20'
+    # release = '2025-01-30'
     self.name = 'Web APIs'
     self.slug = 'dom'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/API'

From e0fdbc2812d75aa484e316b2ca73cf26b3e8a6ff Mon Sep 17 00:00:00 2001
From: Aoibhe Wilson <aoibhe@wilsons.io>
Date: Sat, 1 Feb 2025 16:32:12 +0100
Subject: [PATCH 191/384] Update Ruby Version in README

- reflects current version 3.4.1
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index fa83c7e01b..8337ed0336 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ docker run --name devdocs -d -p 9292:9292 devdocs
 
 DevDocs is made of two pieces: a Ruby scraper that generates the documentation and metadata, and a JavaScript app powered by a small Sinatra app.
 
-DevDocs requires Ruby 3.3.0 (defined in [`Gemfile`](./Gemfile)), libcurl, and a JavaScript runtime supported by [ExecJS](https://github.com/rails/execjs#readme) (included in OS X and Windows; [Node.js](https://nodejs.org/en/) on Linux). Once you have these installed, run the following commands:
+DevDocs requires Ruby 3.4.1 (defined in [`Gemfile`](./Gemfile)), libcurl, and a JavaScript runtime supported by [ExecJS](https://github.com/rails/execjs#readme) (included in OS X and Windows; [Node.js](https://nodejs.org/en/) on Linux). Once you have these installed, run the following commands:
 
 ```sh
 git clone https://github.com/freeCodeCamp/devdocs.git && cd devdocs

From 5add0f9b627e7dc246565d8753863515efdb7b90 Mon Sep 17 00:00:00 2001
From: Aoibhe Wilson <aoibhe@wilsons.io>
Date: Sat, 1 Feb 2025 16:33:19 +0100
Subject: [PATCH 192/384] [#1074] Make Language Specific Favicons Optional -
 adds noDocSpecificIcon property to app settings - adds option to user
 Settings page - updates setFaviconForDoc method to return early when setting
 is active

---
 assets/javascripts/app/settings.js                  | 2 ++
 assets/javascripts/lib/favicon.js                   | 2 +-
 assets/javascripts/templates/pages/settings_tmpl.js | 6 ++++++
 assets/javascripts/views/content/settings_page.js   | 1 +
 4 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/assets/javascripts/app/settings.js b/assets/javascripts/app/settings.js
index 1dbe344006..617830ecc9 100644
--- a/assets/javascripts/app/settings.js
+++ b/assets/javascripts/app/settings.js
@@ -16,6 +16,7 @@ app.Settings = class Settings {
     "autoInstall",
     "spaceScroll",
     "spaceTimeout",
+    "noDocSpecificIcon",
   ];
 
   static INTERNAL_KEYS = ["count", "schema", "version", "news"];
@@ -38,6 +39,7 @@ app.Settings = class Settings {
     theme: "auto",
     spaceScroll: 1,
     spaceTimeout: 0.5,
+    noDocSpecificIcon: false,
   };
 
   constructor() {
diff --git a/assets/javascripts/lib/favicon.js b/assets/javascripts/lib/favicon.js
index c4be8d743a..6b58016c64 100644
--- a/assets/javascripts/lib/favicon.js
+++ b/assets/javascripts/lib/favicon.js
@@ -19,7 +19,7 @@ const withImage = function (url, action) {
 };
 
 this.setFaviconForDoc = function (doc) {
-  if (currentSlug === doc.slug) {
+  if (currentSlug === doc.slug || app.settings.get("noDocSpecificIcon")) {
     return;
   }
 
diff --git a/assets/javascripts/templates/pages/settings_tmpl.js b/assets/javascripts/templates/pages/settings_tmpl.js
index 1fae3975c0..cfd30de1b2 100644
--- a/assets/javascripts/templates/pages/settings_tmpl.js
+++ b/assets/javascripts/templates/pages/settings_tmpl.js
@@ -66,6 +66,12 @@ app.templates.settingsPage = (settings) => `\
       }>Enable tracking cookies
       <small>With this checked, we enable Google Analytics and Gauges to collect anonymous traffic information.</small>
     </label>
+    <label class="_settings-label _hide-on-mobile">
+      <input type="checkbox" form="settings" name="noDocSpecificIcon"${
+        settings.noDocSpecificIcon ? " checked" : ""
+      }>Disable Language-specific Doc Favicons
+      <small>With this checked, we will display the default DevDocs icon for all pages.</small>
+    </label>
   </div>
 </div>
 
diff --git a/assets/javascripts/views/content/settings_page.js b/assets/javascripts/views/content/settings_page.js
index 8b1dd32c0b..46cacb3c16 100644
--- a/assets/javascripts/views/content/settings_page.js
+++ b/assets/javascripts/views/content/settings_page.js
@@ -20,6 +20,7 @@ app.views.SettingsPage = class SettingsPage extends app.View {
     settings.analyticsConsent = app.settings.get("analyticsConsent");
     settings.spaceScroll = app.settings.get("spaceScroll");
     settings.spaceTimeout = app.settings.get("spaceTimeout");
+    settings.noDocSpecificIcon = app.settings.get("noDocSpecificIcon");
     settings.autoSupported = app.settings.autoSupported;
     for (var layout of app.Settings.LAYOUTS) {
       settings[layout] = app.settings.hasLayout(layout);

From 86de8ae92d52e1f3e32e20fb472893f1bf07bff3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 4 Feb 2025 21:03:10 +0000
Subject: [PATCH 193/384] chore(deps): update ruby/setup-ruby action to
 v1.216.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b9a9d02c58..dc9c02c019 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2654679fe7f7c29875c669398a8ec0791b8a64a1 # v1.215.0
+      uses: ruby/setup-ruby@8388f20e6a9c43cd241131b678469a9f89579f37 # v1.216.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 241d0563c9..f8607f7010 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2654679fe7f7c29875c669398a8ec0791b8a64a1 # v1.215.0
+      uses: ruby/setup-ruby@8388f20e6a9c43cd241131b678469a9f89579f37 # v1.216.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 68eeecffb9..ef0572a478 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2654679fe7f7c29875c669398a8ec0791b8a64a1 # v1.215.0
+      uses: ruby/setup-ruby@8388f20e6a9c43cd241131b678469a9f89579f37 # v1.216.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From ada7e02ecd62695b368acc63222a231e7dae0539 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 5 Feb 2025 12:43:56 +0000
Subject: [PATCH 194/384] chore(deps): update ruby/setup-ruby action to
 v1.217.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index dc9c02c019..2283abfeb8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@8388f20e6a9c43cd241131b678469a9f89579f37 # v1.216.0
+      uses: ruby/setup-ruby@8711a86ab6f9aa72890da4123b2ef7283b6b22b6 # v1.217.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index f8607f7010..3bdcb24c79 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@8388f20e6a9c43cd241131b678469a9f89579f37 # v1.216.0
+      uses: ruby/setup-ruby@8711a86ab6f9aa72890da4123b2ef7283b6b22b6 # v1.217.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ef0572a478..b1f634fe27 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@8388f20e6a9c43cd241131b678469a9f89579f37 # v1.216.0
+      uses: ruby/setup-ruby@8711a86ab6f9aa72890da4123b2ef7283b6b22b6 # v1.217.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From d686f930dd9b35e308088a6ca4e1ff10e5943bc5 Mon Sep 17 00:00:00 2001
From: JC <Link_jon@hotmail.com>
Date: Wed, 5 Feb 2025 09:52:46 -0500
Subject: [PATCH 195/384] It's 2025

No one made an issue for it yet, and it is February.
I have noticed thus, problem is solved

(Almost a) duplicate of commit https://github.com/freeCodeCamp/devdocs/commit/07d88233f893b229f107c761ca5599a6c775dd68
---
 COPYRIGHT | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/COPYRIGHT b/COPYRIGHT
index 9c520b8749..374054bdbf 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,4 +1,4 @@
-Copyright 2013-2024 Thibaut Courouble and other contributors
+Copyright 2013-2025 Thibaut Courouble and other contributors
 
   This Source Code Form is subject to the terms of the Mozilla Public
   License, v. 2.0. If a copy of the MPL was not distributed with this

From 3ada96770eb0239fd8525b2e7ef193cc4441b6c3 Mon Sep 17 00:00:00 2001
From: Link_jon <Link_jon@hotmail.com>
Date: Wed, 5 Feb 2025 12:46:15 -0500
Subject: [PATCH 196/384] NOW It's 2025

---
 README.md                                        | 2 +-
 assets/javascripts/lib/license.js                | 2 +-
 assets/javascripts/templates/pages/about_tmpl.js | 2 +-
 assets/stylesheets/application.css.scss          | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index fa83c7e01b..d4b66959b8 100644
--- a/README.md
+++ b/README.md
@@ -195,7 +195,7 @@ Made something cool? Feel free to open a PR to add a new row to this table! You
 
 ## Copyright / License
 
-Copyright 2013–2024 Thibaut Courouble and [other contributors](https://github.com/freeCodeCamp/devdocs/graphs/contributors)
+Copyright 2013–2025 Thibaut Courouble and [other contributors](https://github.com/freeCodeCamp/devdocs/graphs/contributors)
 
 This software is licensed under the terms of the Mozilla Public License v2.0. See the [COPYRIGHT](./COPYRIGHT) and [LICENSE](./LICENSE) files.
 
diff --git a/assets/javascripts/lib/license.js b/assets/javascripts/lib/license.js
index 5c0d5fa443..15b42c98f4 100644
--- a/assets/javascripts/lib/license.js
+++ b/assets/javascripts/lib/license.js
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013-2024 Thibaut Courouble and other contributors
+ * Copyright 2013-2025 Thibaut Courouble and other contributors
  *
  * This source code is licensed under the terms of the Mozilla
  * Public License, v. 2.0, a copy of which may be obtained at:
diff --git a/assets/javascripts/templates/pages/about_tmpl.js b/assets/javascripts/templates/pages/about_tmpl.js
index 683bb54667..e3142da5fc 100644
--- a/assets/javascripts/templates/pages/about_tmpl.js
+++ b/assets/javascripts/templates/pages/about_tmpl.js
@@ -32,7 +32,7 @@ app.templates.aboutPage = function () {
 
 <h2 class="_block-heading" id="copyright">Copyright and License</h2>
 <p class="_note">
-  <strong>Copyright 2013&ndash;2024 Thibaut Courouble and <a href="https://github.com/freeCodeCamp/devdocs/graphs/contributors">other contributors</a></strong><br>
+  <strong>Copyright 2013&ndash;2025 Thibaut Courouble and <a href="https://github.com/freeCodeCamp/devdocs/graphs/contributors">other contributors</a></strong><br>
   This software is licensed under the terms of the Mozilla Public License v2.0.<br>
   You may obtain a copy of the source code at <a href="https://github.com/freeCodeCamp/devdocs">github.com/freeCodeCamp/devdocs</a>.<br>
   For more information, see the <a href="https://github.com/freeCodeCamp/devdocs/blob/main/COPYRIGHT">COPYRIGHT</a>
diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss
index 3823cdc3d8..ca75b69e4f 100644
--- a/assets/stylesheets/application.css.scss
+++ b/assets/stylesheets/application.css.scss
@@ -3,7 +3,7 @@
 //= depend_on sprites/docs.json
 
 /*!
- * Copyright 2013-2024 Thibaut Courouble and other contributors
+ * Copyright 2013-2025 Thibaut Courouble and other contributors
  *
  * This source code is licensed under the terms of the Mozilla
  * Public License, v. 2.0, a copy of which may be obtained at:

From fbd05dc462994595260ad7864152de5f70f191ea Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 6 Feb 2025 01:29:01 +0000
Subject: [PATCH 197/384] chore(deps): update ruby/setup-ruby action to
 v1.218.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2283abfeb8..59b5973433 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@8711a86ab6f9aa72890da4123b2ef7283b6b22b6 # v1.217.0
+      uses: ruby/setup-ruby@d781c1b4ed31764801bfae177617bb0446f5ef8d # v1.218.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 3bdcb24c79..c43048adda 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@8711a86ab6f9aa72890da4123b2ef7283b6b22b6 # v1.217.0
+      uses: ruby/setup-ruby@d781c1b4ed31764801bfae177617bb0446f5ef8d # v1.218.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b1f634fe27..15e9b7d315 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@8711a86ab6f9aa72890da4123b2ef7283b6b22b6 # v1.217.0
+      uses: ruby/setup-ruby@d781c1b4ed31764801bfae177617bb0446f5ef8d # v1.218.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 6bd2a0d1ea99d6fa3bf3b3d15710e6f61a2e0d1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Sat, 8 Feb 2025 08:12:48 +0100
Subject: [PATCH 198/384] Update crystal docs to 1.15.1

---
 lib/docs/scrapers/crystal.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index caa178f2b0..0ca20ab435 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -2,7 +2,7 @@ module Docs
   class Crystal < UrlScraper
     include MultipleBaseUrls
     self.type = 'crystal'
-    self.release = '1.15.0'
+    self.release = '1.15.1'
     self.base_urls = [
       "https://crystal-lang.org/api/#{release}/",
       "https://crystal-lang.org/reference/#{release[0..2]}/",

From a6724138297f6924bfe4a1068ca5721c47b2c138 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 08:34:45 +0100
Subject: [PATCH 199/384] Update Go documentation (1.24.0)

---
 lib/docs/scrapers/go.rb | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/go.rb b/lib/docs/scrapers/go.rb
index 767db080ec..2b795a8cf1 100644
--- a/lib/docs/scrapers/go.rb
+++ b/lib/docs/scrapers/go.rb
@@ -1,7 +1,7 @@
 module Docs
   class Go < UrlScraper
     self.type = 'go'
-    self.release = '1.23.0'
+    self.release = '1.24.0'
     self.base_url = 'https://golang.org/pkg/'
     self.links = {
       home: 'https://golang.org/',
@@ -10,10 +10,19 @@ class Go < UrlScraper
 
     # Run godoc locally, since https://golang.org/pkg/ redirects to https://pkg.go.dev/std with rate limiting / scraping protection.
 
-    # podman run --net host --rm -it docker.io/golang:1.23.0
+    # podman run --net host --rm -it docker.io/golang:1.24.0
     #podman# go install golang.org/x/tools/cmd/godoc@latest
     #podman# rm -r /usr/local/go/test/
     #podman# godoc -http 0.0.0.0:6060 -v
+
+    # or using alpine
+    # podman run --net host --rm -it alpine:latest
+    #podman# apk add curl
+    #podman# curl -LO https://go.dev/dl/go1.24.0.linux-amd64.tar.gz
+    #podman# tar xf go1.24.0.linux-amd64.tar.gz
+    #podman# go/bin/go install golang.org/x/tools/cmd/godoc@latest
+    #podman# /root/go/bin/godoc -http 0.0.0.0:6060 -v
+
     self.base_url = 'http://localhost:6060/pkg/'
 
     html_filters.push 'clean_local_urls'

From 1e61c7877e4fc8fbd1e775b34dceab050e6c49cd Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 08:49:50 +0100
Subject: [PATCH 200/384] Update Rust documentation (1.84.1)

---
 lib/docs/scrapers/rust.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/rust.rb b/lib/docs/scrapers/rust.rb
index 23419f5837..fbbb1415da 100644
--- a/lib/docs/scrapers/rust.rb
+++ b/lib/docs/scrapers/rust.rb
@@ -3,7 +3,7 @@
 module Docs
   class Rust < UrlScraper
     self.type = 'rust'
-    self.release = '1.83.0'
+    self.release = '1.84.1'
     self.base_url = 'https://doc.rust-lang.org/'
     self.root_path = 'book/index.html'
     self.initial_paths = %w(

From 726df58bcc4ed2f4aa867015dd4ade2f4fce72e1 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 08:51:30 +0100
Subject: [PATCH 201/384] Update jQuery UI documentation (1.14.1)

---
 lib/docs/scrapers/jquery/jquery_ui.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/jquery/jquery_ui.rb b/lib/docs/scrapers/jquery/jquery_ui.rb
index d4f66fefcc..eca46fe14e 100644
--- a/lib/docs/scrapers/jquery/jquery_ui.rb
+++ b/lib/docs/scrapers/jquery/jquery_ui.rb
@@ -2,7 +2,7 @@ module Docs
   class JqueryUi < Jquery
     self.name = 'jQuery UI'
     self.slug = 'jqueryui'
-    self.release = '1.13.0'
+    self.release = '1.14.1'
     self.base_url = 'https://api.jqueryui.com'
     self.root_path = '/category/all'
 

From 27ec5a0889a346f921823ac3bfac4f0e4826e611 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 08:53:52 +0100
Subject: [PATCH 202/384] Update Git documentation (2.48.1)

---
 lib/docs/scrapers/git.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/git.rb b/lib/docs/scrapers/git.rb
index d8a289c1cb..a3a0fff89b 100644
--- a/lib/docs/scrapers/git.rb
+++ b/lib/docs/scrapers/git.rb
@@ -1,7 +1,7 @@
 module Docs
   class Git < UrlScraper
     self.type = 'git'
-    self.release = '2.47.1'
+    self.release = '2.48.1'
     self.base_url = 'https://git-scm.com/docs'
     self.initial_paths = %w(/git.html)
     self.links = {

From e993bafc4719ebdefd6d9302445dbdf62be6c04c Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 08:59:31 +0100
Subject: [PATCH 203/384] Update VueUse documentation (12.5.0)

---
 lib/docs/filters/vueuse/entries.rb | 16 ++++++++++++++++
 lib/docs/scrapers/vueuse.rb        |  2 +-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/lib/docs/filters/vueuse/entries.rb b/lib/docs/filters/vueuse/entries.rb
index a3d0af56d3..2bd0e05de1 100644
--- a/lib/docs/filters/vueuse/entries.rb
+++ b/lib/docs/filters/vueuse/entries.rb
@@ -248,6 +248,10 @@ class EntriesFilter < Docs::EntriesFilter
               "text": "usePreferredReducedMotion",
               "link": "/core/usePreferredReducedMotion/"
             },
+            {
+              "text": "usePreferredReducedTransparency",
+              "link": "/core/usePreferredReducedTransparency/"
+            },
             {
               "text": "useScreenOrientation",
               "link": "/core/useScreenOrientation/"
@@ -264,6 +268,10 @@ class EntriesFilter < Docs::EntriesFilter
               "text": "useShare",
               "link": "/core/useShare/"
             },
+            {
+              "text": "useSSRWidth",
+              "link": "/core/useSSRWidth/"
+            },
             {
               "text": "useStyleTag",
               "link": "/core/useStyleTag/"
@@ -313,6 +321,10 @@ class EntriesFilter < Docs::EntriesFilter
               "text": "onClickOutside",
               "link": "/core/onClickOutside/"
             },
+            {
+              "text": "onElementRemoval",
+              "link": "/core/onElementRemoval/"
+            },
             {
               "text": "onKeyStroke",
               "link": "/core/onKeyStroke/"
@@ -788,6 +800,10 @@ class EntriesFilter < Docs::EntriesFilter
         {
           "text": "Time",
           "items": [
+            {
+              "text": "useCountdown",
+              "link": "/core/useCountdown/"
+            },
             {
               "text": "useDateFormat",
               "link": "/shared/useDateFormat/"
diff --git a/lib/docs/scrapers/vueuse.rb b/lib/docs/scrapers/vueuse.rb
index 3933b60c55..d9e6748c69 100644
--- a/lib/docs/scrapers/vueuse.rb
+++ b/lib/docs/scrapers/vueuse.rb
@@ -22,7 +22,7 @@ class Vueuse < UrlScraper
       Licensed under the MIT License.
     HTML
 
-    self.release = '12.0.0'
+    self.release = '12.5.0'
     self.base_url = 'https://vueuse.org/'
     self.initial_paths = %w(functions.html)
     html_filters.push 'vueuse/entries', 'vite/clean_html', 'vueuse/clean_html'

From 00649b9ebdc00aec3184e87184297a643e0afe6b Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 09:07:00 +0100
Subject: [PATCH 204/384] Update Haskell documentation (9.12.1)

---
 lib/docs/scrapers/haskell.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/haskell.rb b/lib/docs/scrapers/haskell.rb
index 9cfe7f66e4..8d822ece0f 100755
--- a/lib/docs/scrapers/haskell.rb
+++ b/lib/docs/scrapers/haskell.rb
@@ -59,7 +59,7 @@ class Haskell < UrlScraper
     end
 
     version '9' do
-      self.release = '9.4.2'
+      self.release = '9.12.1'
       self.base_url = "https://downloads.haskell.org/~ghc/#{release}/docs/"
       options[:container] = ->(filter) {filter.subpath.start_with?('users_guide') ? '.document' : '#content'}
     end

From a2d9d7ad4384017c2db6cc98b738c1078630721d Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 09:08:43 +0100
Subject: [PATCH 205/384] Update Flask documentation (3.1.1)

---
 lib/docs/scrapers/flask.rb | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/docs/scrapers/flask.rb b/lib/docs/scrapers/flask.rb
index 08655e7a95..11229a2574 100755
--- a/lib/docs/scrapers/flask.rb
+++ b/lib/docs/scrapers/flask.rb
@@ -18,6 +18,11 @@ class Flask < UrlScraper
       Licensed under the BSD 3-clause License.
     HTML
 
+    version do
+      self.release = '3.1.1'
+      self.base_url = "https://flask.palletsprojects.com/en/stable/"
+    end
+
     version '3.0' do
       self.release = '3.0.x'
       self.base_url = "https://flask.palletsprojects.com/en/#{self.release}/"

From 5a129d47786c62863e22f442a67ac271d83d895e Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 09:08:45 +0100
Subject: [PATCH 206/384] Update Werkzeug documentation (3.1.1)

---
 lib/docs/scrapers/werkzeug.rb | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/docs/scrapers/werkzeug.rb b/lib/docs/scrapers/werkzeug.rb
index 703797448d..d331ecd616 100755
--- a/lib/docs/scrapers/werkzeug.rb
+++ b/lib/docs/scrapers/werkzeug.rb
@@ -17,6 +17,11 @@ class Werkzeug < UrlScraper
       Licensed under the BSD 3-clause License.
     HTML
 
+    version do
+      self.release = '3.1.1'
+      self.base_url = "https://werkzeug.palletsprojects.com/en/latest/"
+    end
+
     version '3.0' do
       self.release = '3.0.x'
       self.base_url = "https://werkzeug.palletsprojects.com/en/#{self.release}/"

From 2499e17ea4c7bf04c04427454fe950e22e05a3fe Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 12 Feb 2025 09:20:16 +0100
Subject: [PATCH 207/384] Update Express documentation (4.21.2)

---
 lib/docs/filters/express/clean_html.rb | 2 +-
 lib/docs/scrapers/express.rb           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/filters/express/clean_html.rb b/lib/docs/filters/express/clean_html.rb
index 0d9c512787..01a6390972 100644
--- a/lib/docs/filters/express/clean_html.rb
+++ b/lib/docs/filters/express/clean_html.rb
@@ -3,7 +3,7 @@ class Express
     class CleanHtmlFilter < Filter
       def call
         i = 1
-        n = at_css("#navmenu a[href='#{result[:path].split('/').last}']").parent
+        n = at_css("#navmenu .submenu-content a[href='#{result[:path].split('/').last}']").parent
         i += 1 while n && n = n.previous_element
         at_css('h1')['data-level'] = i
 
diff --git a/lib/docs/scrapers/express.rb b/lib/docs/scrapers/express.rb
index 2f0a93cee3..724b771ff8 100644
--- a/lib/docs/scrapers/express.rb
+++ b/lib/docs/scrapers/express.rb
@@ -2,7 +2,7 @@ module Docs
   class Express < UrlScraper
     self.name = 'Express'
     self.type = 'express'
-    self.release = '4.18.1'
+    self.release = '4.21.2'
     self.base_url = 'https://expressjs.com/en/'
     self.root_path = '4x/api.html'
     self.initial_paths = %w(

From 479bd750895d8b23eb32f43b032c378fa4229c9a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 12 Feb 2025 10:40:42 +0000
Subject: [PATCH 208/384] chore(deps): update dependency rack to v2.2.11

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index a0ab80a944..e46c26250b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -78,7 +78,7 @@ GEM
       byebug (~> 11.0)
       pry (>= 0.13, < 0.15)
     racc (1.8.1)
-    rack (2.2.10)
+    rack (2.2.11)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)

From 8e718e71e98ca51db28f6eb33e3885eecb8a1736 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 12 Feb 2025 16:06:58 +0000
Subject: [PATCH 209/384] chore(deps): update ruby/setup-ruby action to
 v1.219.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 59b5973433..c41a6b289b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@d781c1b4ed31764801bfae177617bb0446f5ef8d # v1.218.0
+      uses: ruby/setup-ruby@f2f42b7848feff522ffa488a5236ba0a73bccbdd # v1.219.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index c43048adda..45b671bbe2 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@d781c1b4ed31764801bfae177617bb0446f5ef8d # v1.218.0
+      uses: ruby/setup-ruby@f2f42b7848feff522ffa488a5236ba0a73bccbdd # v1.219.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 15e9b7d315..5a30c1b268 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@d781c1b4ed31764801bfae177617bb0446f5ef8d # v1.218.0
+      uses: ruby/setup-ruby@f2f42b7848feff522ffa488a5236ba0a73bccbdd # v1.219.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From d12f240bca1aa691de6fa184f14441fbdbcde952 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 15 Feb 2025 13:48:46 +0000
Subject: [PATCH 210/384] chore(deps): update ruby/setup-ruby action to
 v1.220.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c41a6b289b..01f19ab6e0 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f2f42b7848feff522ffa488a5236ba0a73bccbdd # v1.219.0
+      uses: ruby/setup-ruby@28d088d34a0b0b7ba0823b7952c77004560a3a6f # v1.220.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 45b671bbe2..ea6255a8f1 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f2f42b7848feff522ffa488a5236ba0a73bccbdd # v1.219.0
+      uses: ruby/setup-ruby@28d088d34a0b0b7ba0823b7952c77004560a3a6f # v1.220.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5a30c1b268..9d93bd900e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f2f42b7848feff522ffa488a5236ba0a73bccbdd # v1.219.0
+      uses: ruby/setup-ruby@28d088d34a0b0b7ba0823b7952c77004560a3a6f # v1.220.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 07b131faa4beb0d5ef13ad1c0795197df82f9524 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 15 Feb 2025 17:52:34 +0000
Subject: [PATCH 211/384] chore(deps): update dependency ruby to v3.4.2

---
 .ruby-version     | 2 +-
 .tool-versions    | 2 +-
 Dockerfile        | 2 +-
 Dockerfile-alpine | 2 +-
 Gemfile           | 2 +-
 Gemfile.lock      | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.ruby-version b/.ruby-version
index 47b322c971..4d9d11cf50 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.4.1
+3.4.2
diff --git a/.tool-versions b/.tool-versions
index 041df9aa68..ae5ecdb2b3 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1 @@
-ruby 3.4.1
+ruby 3.4.2
diff --git a/Dockerfile b/Dockerfile
index d52cd1de4c..92c5964260 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:3.4.1
+FROM ruby:3.4.2
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
 
diff --git a/Dockerfile-alpine b/Dockerfile-alpine
index 67b3d96836..ce605eaab9 100644
--- a/Dockerfile-alpine
+++ b/Dockerfile-alpine
@@ -1,4 +1,4 @@
-FROM ruby:3.4.1-alpine
+FROM ruby:3.4.2-alpine
 
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
diff --git a/Gemfile b/Gemfile
index 59403526a8..be8dcb0b6c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,5 @@
 source 'https://rubygems.org'
-ruby '3.4.1'
+ruby '3.4.2'
 
 gem 'activesupport', require: false
 gem 'html-pipeline'
diff --git a/Gemfile.lock b/Gemfile.lock
index e46c26250b..6608eb1c59 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -191,7 +191,7 @@ DEPENDENCIES
   yajl-ruby
 
 RUBY VERSION
-   ruby 3.4.1p0
+   ruby 3.4.2p28
 
 BUNDLED WITH
    2.4.6

From 549c19ac83910c2f0d3315f7b953b54e30d97d7a Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Feb 2025 11:48:29 +0100
Subject: [PATCH 212/384] Typo

---
 lib/docs/filters/scala/entries_v2.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/filters/scala/entries_v2.rb b/lib/docs/filters/scala/entries_v2.rb
index ca3b6d1275..6f044644bc 100644
--- a/lib/docs/filters/scala/entries_v2.rb
+++ b/lib/docs/filters/scala/entries_v2.rb
@@ -71,7 +71,7 @@ def additional_entries
       # name from the HTML because companion object classes may be broken out into
       # their own entries (by the source documentation). When that happens,
       # we want to group these classes (like `scala.reflect.api.Annotations.Annotation`)
-      # under the package name, and not the fully-qualfied name which would
+      # under the package name, and not the fully-qualified name which would
       # include the companion object.
       def package_name
         name = package_drop_last(slug_parts)

From 4ad6715ec13819b4c0ba9a0bae3f0831b6620651 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Feb 2025 12:02:59 +0100
Subject: [PATCH 213/384] Add OpenLayers documentation (10.4.0)

---
 assets/javascripts/news.json              |   4 ++++
 assets/stylesheets/application.css.scss   |   1 +
 assets/stylesheets/pages/_openlayers.scss |  10 +++++++++
 lib/docs/filters/openlayers/clean_html.rb |  18 ++++++++++++++++
 lib/docs/filters/openlayers/entries.rb    |  22 ++++++++++++++++++++
 lib/docs/scrapers/openlayers.rb           |  24 ++++++++++++++++++++++
 public/icons/docs/openlayers/16.png       | Bin 0 -> 419 bytes
 public/icons/docs/openlayers/16@2x.png    | Bin 0 -> 840 bytes
 public/icons/docs/openlayers/SOURCE       |   2 ++
 9 files changed, 81 insertions(+)
 create mode 100644 assets/stylesheets/pages/_openlayers.scss
 create mode 100644 lib/docs/filters/openlayers/clean_html.rb
 create mode 100644 lib/docs/filters/openlayers/entries.rb
 create mode 100644 lib/docs/scrapers/openlayers.rb
 create mode 100644 public/icons/docs/openlayers/16.png
 create mode 100644 public/icons/docs/openlayers/16@2x.png
 create mode 100644 public/icons/docs/openlayers/SOURCE

diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index 052f4918e5..2c393d971b 100644
--- a/assets/javascripts/news.json
+++ b/assets/javascripts/news.json
@@ -1,4 +1,8 @@
 [
+  [
+    "2025-02-16",
+    "New documentation: <a href=\"/openlayers/\">OpenLayers</a>"
+  ],
   [
     "2024-11-23",
     "New documentation: <a href=\"/duckdb/\">DuckDB</a>"
diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss
index ca75b69e4f..b45e7b602e 100644
--- a/assets/stylesheets/application.css.scss
+++ b/assets/stylesheets/application.css.scss
@@ -97,6 +97,7 @@
         'pages/nushell',
         'pages/octave',
         'pages/openjdk',
+        'pages/openlayers',
         'pages/perl',
         'pages/phalcon',
         'pages/phaser',
diff --git a/assets/stylesheets/pages/_openlayers.scss b/assets/stylesheets/pages/_openlayers.scss
new file mode 100644
index 0000000000..50628b2ff3
--- /dev/null
+++ b/assets/stylesheets/pages/_openlayers.scss
@@ -0,0 +1,10 @@
+._openlayers {
+  @extend %simple;
+  .nameContainer {
+    @extend %block-label;
+    > * { display: inline-block; margin: 0; }
+    > .tag-source { float: right; }
+  }
+  .card { @extend %box; margin-bottom: 1rem; padding: 1rem; }
+  .signature, .type-signature { @extend %code; }
+}
diff --git a/lib/docs/filters/openlayers/clean_html.rb b/lib/docs/filters/openlayers/clean_html.rb
new file mode 100644
index 0000000000..713306c299
--- /dev/null
+++ b/lib/docs/filters/openlayers/clean_html.rb
@@ -0,0 +1,18 @@
+module Docs
+  class Openlayers
+    class CleanHtmlFilter < Filter
+      def call
+        @doc = at_css('section')
+    
+        at_css('h2').name = 'h1' if at_css('h2')
+
+        css('pre.prettyprint').each do |node|
+          node['data-language'] = node['class'].include?('html') ? 'html' : 'js'
+          node.content = node.content
+        end
+        
+        doc
+      end
+    end
+  end
+end
diff --git a/lib/docs/filters/openlayers/entries.rb b/lib/docs/filters/openlayers/entries.rb
new file mode 100644
index 0000000000..05e188502b
--- /dev/null
+++ b/lib/docs/filters/openlayers/entries.rb
@@ -0,0 +1,22 @@
+module Docs
+  class Openlayers
+    class EntriesFilter < Docs::EntriesFilter
+      def get_name
+        at_css('h2').text.split('~').last.strip
+      end
+
+      def get_type
+        slug[/ol_([^_]+)_/, 1] or 'ol'
+      end
+
+      def additional_entries
+        css('h4.name').each_with_object [] do |node, entries|
+          node['id'] = node.previous_element['id']
+          name = node.children.find {|n| n.text? }.text.strip
+          name.prepend "#{self.name}."
+          entries << [name, node['id']]
+        end
+      end
+    end
+  end
+end
diff --git a/lib/docs/scrapers/openlayers.rb b/lib/docs/scrapers/openlayers.rb
new file mode 100644
index 0000000000..1c957fbde1
--- /dev/null
+++ b/lib/docs/scrapers/openlayers.rb
@@ -0,0 +1,24 @@
+module Docs
+  class Openlayers < UrlScraper
+    self.name = 'OpenLayers'
+    self.type = 'openlayers'
+    self.slug = 'openlayers'
+    self.release = '10.4.0'
+    self.base_url = "https://openlayers.org/en/latest/apidoc/"
+    self.links = {
+      home: 'https://openlayers.org/',
+      code: 'https://github.com/openlayers/openlayers'
+    }
+
+    html_filters.push 'openlayers/entries', 'openlayers/clean_html'
+
+    options[:attribution] = <<-HTML
+      &copy; 2005-present, OpenLayers Contributors All rights reserved.
+      Licensed under the BSD 2-Clause License.
+    HTML
+
+    def get_latest_version(opts)
+      get_npm_version('ol', opts)
+    end
+  end
+end
diff --git a/public/icons/docs/openlayers/16.png b/public/icons/docs/openlayers/16.png
new file mode 100644
index 0000000000000000000000000000000000000000..fe90ebfbfba1e25db4758974593ef3a56ec3e23d
GIT binary patch
diff --git a/public/icons/docs/openlayers/16@2x.png b/public/icons/docs/openlayers/16@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..c39658a1350fa71e4099bc460939f5dfd90f0d36
GIT binary patch
diff --git a/public/icons/docs/openlayers/SOURCE b/public/icons/docs/openlayers/SOURCE
new file mode 100644
index 0000000000..74be1eaa84
--- /dev/null
+++ b/public/icons/docs/openlayers/SOURCE
@@ -0,0 +1,2 @@
+https://github.com/openlayers
+https://avatars.githubusercontent.com/u/240579?s=64

From a361d73e569d419ed395410e28b5d910211d1f05 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Feb 2025 12:07:49 +0100
Subject: [PATCH 214/384] Update Vite documentation (6.1.0)

---
 lib/docs/scrapers/vite.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vite.rb b/lib/docs/scrapers/vite.rb
index 937d09161c..4ca7b9d38f 100644
--- a/lib/docs/scrapers/vite.rb
+++ b/lib/docs/scrapers/vite.rb
@@ -22,7 +22,7 @@ class Vite < UrlScraper
     html_filters.push 'vite/entries', 'vite/clean_html'
 
     version do
-      self.release = '6.0.1'
+      self.release = '6.1.0'
       self.base_url = 'https://vite.dev/'
     end
 

From 19613ef1cd86dffc623dcde52f14cb5354a6e267 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Feb 2025 12:36:09 +0100
Subject: [PATCH 215/384] openlayers: remove inherited entries

---
 lib/docs/filters/openlayers/entries.rb | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/docs/filters/openlayers/entries.rb b/lib/docs/filters/openlayers/entries.rb
index 05e188502b..a325bdcd82 100644
--- a/lib/docs/filters/openlayers/entries.rb
+++ b/lib/docs/filters/openlayers/entries.rb
@@ -12,6 +12,7 @@ def get_type
       def additional_entries
         css('h4.name').each_with_object [] do |node, entries|
           node['id'] = node.previous_element['id']
+          next if node.at_css('.inherited')
           name = node.children.find {|n| n.text? }.text.strip
           name.prepend "#{self.name}."
           entries << [name, node['id']]

From 85039c6377593d87c722a47dae26189685b85a59 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 16 Feb 2025 22:55:35 +0000
Subject: [PATCH 216/384] chore(deps): update ruby/setup-ruby action to
 v1.221.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 01f19ab6e0..51acef9629 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28d088d34a0b0b7ba0823b7952c77004560a3a6f # v1.220.0
+      uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # v1.221.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index ea6255a8f1..137cec66fe 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28d088d34a0b0b7ba0823b7952c77004560a3a6f # v1.220.0
+      uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # v1.221.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9d93bd900e..70c3d4d2b9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@28d088d34a0b0b7ba0823b7952c77004560a3a6f # v1.220.0
+      uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # v1.221.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 2b63eba0da4400d7ac95cc954a0330e246d828bd Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 18 Feb 2025 22:50:34 +0000
Subject: [PATCH 217/384] chore(deps): update dependency nokogiri to v1.18.3

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 6608eb1c59..9ccdd742df 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -63,7 +63,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.2)
+    nokogiri (1.18.3)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From ddb8ff3acdf0dee141b78321a9d17062ddae80a0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 19 Feb 2025 16:50:49 +0000
Subject: [PATCH 218/384] chore(deps): update akhileshns/heroku-deploy action
 to v3.14.15

---
 .github/workflows/build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 51acef9629..10f4c0d15a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -19,7 +19,7 @@ jobs:
     - name: Run tests
       run: bundle exec rake
     - name: Deploy to Heroku
-      uses: akhileshns/heroku-deploy@581dd286c962b6972d427fcf8980f60755c15520 # v3.13.15
+      uses: akhileshns/heroku-deploy@e3eb99d45a8e2ec5dca08735e089607befa4bf28 # v3.14.15
       with:
         heroku_api_key: ${{secrets.HEROKU_API_KEY}}
         heroku_app_name: "devdocs"

From d426b47166e13266623a8d8c5079028a5d6dc562 Mon Sep 17 00:00:00 2001
From: Calum Smith <hello@calum.io>
Date: Thu, 20 Feb 2025 23:49:57 -0500
Subject: [PATCH 219/384] =?UTF-8?q?fix:=20open=20external=20links=20in=20d?=
 =?UTF-8?q?efault=20browser=20from=20macOS=20PWA=E2=80=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

…by using `window.open(url, "_blank", "noopener")` directly instead of a
now-rarely-needed workaround.

Fixes freeCodeCamp/devdocs#2438
---
 assets/javascripts/lib/util.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/assets/javascripts/lib/util.js b/assets/javascripts/lib/util.js
index 3aa301bce3..c8668d4fbc 100644
--- a/assets/javascripts/lib/util.js
+++ b/assets/javascripts/lib/util.js
@@ -457,13 +457,13 @@ $.noop = function () {};
 
 $.popup = function (value) {
   try {
+    window.open(value.href || value, "_blank", "noopener");
+  } catch (error) {
     const win = window.open();
     if (win.opener) {
       win.opener = null;
     }
     win.location = value.href || value;
-  } catch (error) {
-    window.open(value.href || value, "_blank");
   }
 };
 

From 5807a6f8b853abb604d3d07e2f35fe50ebf87327 Mon Sep 17 00:00:00 2001
From: ClasherKasten <cfb1470@gmail.com>
Date: Fri, 21 Feb 2025 17:03:03 +0100
Subject: [PATCH 220/384] Update Tensorflow and Tensorflow C++ (2.16)

---
 lib/docs/filters/tensorflow/clean_html.rb      | 3 +++
 lib/docs/scrapers/tensorflow/tensorflow.rb     | 5 +++++
 lib/docs/scrapers/tensorflow/tensorflow_cpp.rb | 5 +++++
 3 files changed, 13 insertions(+)

diff --git a/lib/docs/filters/tensorflow/clean_html.rb b/lib/docs/filters/tensorflow/clean_html.rb
index 6d594d709f..cc153320ea 100644
--- a/lib/docs/filters/tensorflow/clean_html.rb
+++ b/lib/docs/filters/tensorflow/clean_html.rb
@@ -46,6 +46,9 @@ def call
           node.replace("<p>#{node.to_html}</p>")
         end
 
+        css('span[slot="popout-heading"]').remove
+        css('span[slot="popout-contents"]').remove
+
         doc
       end
     end
diff --git a/lib/docs/scrapers/tensorflow/tensorflow.rb b/lib/docs/scrapers/tensorflow/tensorflow.rb
index fbd68abcd9..029fd99c38 100644
--- a/lib/docs/scrapers/tensorflow/tensorflow.rb
+++ b/lib/docs/scrapers/tensorflow/tensorflow.rb
@@ -19,6 +19,11 @@ class Tensorflow < UrlScraper
       Code samples licensed under the Apache 2.0 License.
     HTML
 
+    version '2.16' do
+      self.release = "2.16.1"
+      self.base_url = "https://www.tensorflow.org/api_docs/python/tf"
+    end
+
     version '2.9' do
       self.release = "2.9.1"
       self.base_url = "https://www.tensorflow.org/versions/r#{version}/api_docs/python/tf"
diff --git a/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb b/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
index e7dfbe9eee..b434199c82 100644
--- a/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
+++ b/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
@@ -3,6 +3,11 @@ class TensorflowCpp < Tensorflow
     self.name = 'TensorFlow C++'
     self.slug = 'tensorflow_cpp'
 
+    version '2.16' do
+      self.release = "2.16.1"
+      self.base_url = "https://www.tensorflow.org/api_docs/cc"
+    end
+
     version '2.9' do
       self.release = "2.9.1"
       self.base_url = "https://www.tensorflow.org/versions/r#{version}/api_docs/cc"

From 31ca6d46856350339fc8991c6eda08d9a872c357 Mon Sep 17 00:00:00 2001
From: ClasherKasten <cfb1470@gmail.com>
Date: Fri, 21 Feb 2025 20:30:53 +0100
Subject: [PATCH 221/384] Fix multiple version checks of scrapers.

- Docker
- Meteor
- Nix
- PHPUnit
- Redis
- Sass
- Trio
---
 lib/docs/scrapers/docker.rb  | 2 +-
 lib/docs/scrapers/meteor.rb  | 3 +--
 lib/docs/scrapers/nix.rb     | 4 +---
 lib/docs/scrapers/phpunit.rb | 4 ++--
 lib/docs/scrapers/redis.rb   | 3 +--
 lib/docs/scrapers/sass.rb    | 4 ++--
 lib/docs/scrapers/trio.rb    | 2 +-
 7 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/lib/docs/scrapers/docker.rb b/lib/docs/scrapers/docker.rb
index 070796aecb..bfc420a39e 100644
--- a/lib/docs/scrapers/docker.rb
+++ b/lib/docs/scrapers/docker.rb
@@ -96,7 +96,7 @@ class Docker < UrlScraper
 
     def get_latest_version(opts)
       doc = fetch_doc('https://docs.docker.com/engine/release-notes/', opts)
-      latest_version = doc.at_css('.DocSearch-content > h2 > a').content.strip
+      latest_version = doc.at_css('h2.scroll-mt-20 > a').content.strip
       latest_version.rpartition(' ')[-1]
     end
   end
diff --git a/lib/docs/scrapers/meteor.rb b/lib/docs/scrapers/meteor.rb
index a758d154aa..04cb929ee7 100644
--- a/lib/docs/scrapers/meteor.rb
+++ b/lib/docs/scrapers/meteor.rb
@@ -47,8 +47,7 @@ class Meteor < UrlScraper
     end
 
     def get_latest_version(opts)
-      doc = fetch_doc('https://docs.meteor.com/#/full/', opts)
-      doc.at_css('select.version-select > option').content
+      get_npm_version('meteor', opts)
     end
   end
 end
diff --git a/lib/docs/scrapers/nix.rb b/lib/docs/scrapers/nix.rb
index 5be27ffa29..b2ee5c8798 100644
--- a/lib/docs/scrapers/nix.rb
+++ b/lib/docs/scrapers/nix.rb
@@ -23,9 +23,7 @@ class Nix < UrlScraper
 
     def get_latest_version(opts)
       doc = fetch_doc('https://nixos.org/manual/nix/stable/', opts)
-      json = JSON.parse(doc.at_css('body')['data-nix-channels'])
-      channel = json.find { |c| c['channel'] == 'stable' }
-      channel['version']
+      doc.at_css('a.active')['href'].scan(/([0-9.]+)/)[0][0]
     end
   end
 end
diff --git a/lib/docs/scrapers/phpunit.rb b/lib/docs/scrapers/phpunit.rb
index 7bd1c603a8..dcd1c5f1f8 100644
--- a/lib/docs/scrapers/phpunit.rb
+++ b/lib/docs/scrapers/phpunit.rb
@@ -77,8 +77,8 @@ class Phpunit < UrlScraper
 
     def get_latest_version(opts)
       doc = fetch_doc('https://phpunit.readthedocs.io/', opts)
-      label = doc.at_css('.rst-current-version').content.strip
-      label.scan(/v: ([0-9.]+)/)[0][0]
+      label = doc.at_css('meta[name="readthedocs-version-slug"]')["content"]
+      label
     end
 
   end
diff --git a/lib/docs/scrapers/redis.rb b/lib/docs/scrapers/redis.rb
index d4c62b42d4..9c8e03b19b 100644
--- a/lib/docs/scrapers/redis.rb
+++ b/lib/docs/scrapers/redis.rb
@@ -22,8 +22,7 @@ class Redis < UrlScraper
 
     def get_latest_version(opts)
       body = fetch('http://download.redis.io/redis-stable/00-RELEASENOTES', opts)
-      body = body.lines[1..-1].join
-      body.scan(/Redis ([0-9.]+)/)[0][0]
+      body.scan(/Redis Community Edition ([0-9.]+)/)[0][0]
     end
 
     private
diff --git a/lib/docs/scrapers/sass.rb b/lib/docs/scrapers/sass.rb
index d7b5954a08..aaa7a5ad81 100644
--- a/lib/docs/scrapers/sass.rb
+++ b/lib/docs/scrapers/sass.rb
@@ -20,13 +20,13 @@ class Sass < UrlScraper
       &copy; 2006&ndash;2024 the Sass team, and numerous contributors<br>
       Licensed under the MIT License.
     HTML
-  
-    private
 
     def get_latest_version(opts)
       get_npm_version('sass', opts)
     end
 
+    private
+
     def parse(response)
       response.body.gsub! '<span class="widont">&nbsp;</span>', '&nbsp;'
     end
diff --git a/lib/docs/scrapers/trio.rb b/lib/docs/scrapers/trio.rb
index 141a408edd..e502fe7205 100644
--- a/lib/docs/scrapers/trio.rb
+++ b/lib/docs/scrapers/trio.rb
@@ -25,7 +25,7 @@ class Trio < UrlScraper
 
     def get_latest_version(opts)
       doc = fetch_doc('https://trio.readthedocs.io/en/stable/', opts)
-      doc.at_css('.rst-other-versions a[href^="/en/v"]').content[1..-1]
+      doc.at_css('div.trio-version').content[0..-1]
     end
   end
 end

From f71b8efb6a1bcc8202cf8403eb34c0adaad064db Mon Sep 17 00:00:00 2001
From: Adam Johnson <me@adamj.eu>
Date: Fri, 21 Feb 2025 22:57:10 +0000
Subject: [PATCH 222/384] Add Django 5.2

---
 lib/docs/scrapers/django.rb | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/docs/scrapers/django.rb b/lib/docs/scrapers/django.rb
index 906e93df64..8a6cba8bf6 100644
--- a/lib/docs/scrapers/django.rb
+++ b/lib/docs/scrapers/django.rb
@@ -34,6 +34,11 @@ class Django < FileScraper
       Licensed under the BSD License.
     HTML
 
+    version '5.2' do
+      self.release = '5.2'
+      self.base_url = "https://docs.djangoproject.com/en/#{self.version}/"
+    end
+
     version '5.1' do
       self.release = '5.1'
       self.base_url = "https://docs.djangoproject.com/en/#{self.version}/"

From e2336a1ce33bca75bc06c980a57f9b75dd880c0f Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 08:47:25 +0100
Subject: [PATCH 223/384] Update PHPUnit documentation (12.0)

---
 lib/docs/filters/phpunit/clean_html.rb |  2 +-
 lib/docs/scrapers/phpunit.rb           | 11 ++++++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/lib/docs/filters/phpunit/clean_html.rb b/lib/docs/filters/phpunit/clean_html.rb
index 5e36704c0f..dacb15874b 100644
--- a/lib/docs/filters/phpunit/clean_html.rb
+++ b/lib/docs/filters/phpunit/clean_html.rb
@@ -2,7 +2,7 @@ module Docs
   class Phpunit
     class CleanHtmlFilter < Filter
       def call
-        @doc = at_css('.section') if not root_page?
+        @doc = at_css('section') if not root_page?
 
         css('pre').each do |node|
           node['class'] = 'highlight'
diff --git a/lib/docs/scrapers/phpunit.rb b/lib/docs/scrapers/phpunit.rb
index dcd1c5f1f8..12efbbfcba 100644
--- a/lib/docs/scrapers/phpunit.rb
+++ b/lib/docs/scrapers/phpunit.rb
@@ -17,12 +17,21 @@ class Phpunit < UrlScraper
     options[:title] = false
 
     options[:attribution] = <<-HTML
-      &copy; 2005&ndash;2020 Sebastian Bergmann<br>
+      &copy; 2005&ndash;2025 Sebastian Bergmann<br>
       Licensed under the Creative Commons Attribution 3.0 Unported License.
     HTML
 
     FILTERS = %w(phpunit/clean_html phpunit/entries title)
 
+    version do
+      self.release = '12.0'
+      self.base_url = "https://docs.phpunit.de/en/#{release}/"
+
+      html_filters.push FILTERS
+
+      options[:container] = '.document'
+    end
+
     version '9' do
       self.release = '9.5'
       self.base_url = "https://phpunit.readthedocs.io/en/#{release}/"

From 3eda8d283542139e90c9d14ceeab5b9f156d17fd Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 08:50:42 +0100
Subject: [PATCH 224/384] Update Sass documentation (1.85.0)

---
 lib/docs/scrapers/sass.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/sass.rb b/lib/docs/scrapers/sass.rb
index aaa7a5ad81..d0c0a93537 100644
--- a/lib/docs/scrapers/sass.rb
+++ b/lib/docs/scrapers/sass.rb
@@ -1,7 +1,7 @@
 module Docs
   class Sass < UrlScraper
     self.type = 'yard'
-    self.release = '1.82.9'
+    self.release = '1.85.0'
     self.base_url = 'https://sass-lang.com/documentation'
     self.root_path = 'index.html'
     self.links = {
@@ -17,7 +17,7 @@ class Sass < UrlScraper
     options[:trailing_slash] = false
 
     options[:attribution] = <<-HTML
-      &copy; 2006&ndash;2024 the Sass team, and numerous contributors<br>
+      &copy; 2006&ndash;2025 the Sass team, and numerous contributors<br>
       Licensed under the MIT License.
     HTML
 

From d851473407caaa0a5bc754c0ed33572056933ae4 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 08:51:43 +0100
Subject: [PATCH 225/384] Update Trio documentation (0.29.0)

---
 lib/docs/scrapers/trio.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/trio.rb b/lib/docs/scrapers/trio.rb
index e502fe7205..701f9c23b0 100644
--- a/lib/docs/scrapers/trio.rb
+++ b/lib/docs/scrapers/trio.rb
@@ -1,7 +1,7 @@
 module Docs
   class Trio < UrlScraper
     self.type = 'simple'
-    self.release = '0.22.2'
+    self.release = '0.29.0'
     self.base_url = "https://trio.readthedocs.io/en/v#{self.release}/"
     self.root_path = 'index.html'
     self.links = {

From 82a03cb7404270bcc9d90cf4fb010dc87d82336a Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 09:10:18 +0100
Subject: [PATCH 226/384] Update TensorFlow documentation (2.18.0)

---
 lib/docs/scrapers/tensorflow/tensorflow.rb     | 4 ++--
 lib/docs/scrapers/tensorflow/tensorflow_cpp.rb | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/docs/scrapers/tensorflow/tensorflow.rb b/lib/docs/scrapers/tensorflow/tensorflow.rb
index 029fd99c38..9d3cdb58de 100644
--- a/lib/docs/scrapers/tensorflow/tensorflow.rb
+++ b/lib/docs/scrapers/tensorflow/tensorflow.rb
@@ -19,8 +19,8 @@ class Tensorflow < UrlScraper
       Code samples licensed under the Apache 2.0 License.
     HTML
 
-    version '2.16' do
-      self.release = "2.16.1"
+    version do
+      self.release = "2.18.0"
       self.base_url = "https://www.tensorflow.org/api_docs/python/tf"
     end
 
diff --git a/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb b/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
index b434199c82..6fe3c86a3e 100644
--- a/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
+++ b/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
@@ -3,8 +3,8 @@ class TensorflowCpp < Tensorflow
     self.name = 'TensorFlow C++'
     self.slug = 'tensorflow_cpp'
 
-    version '2.16' do
-      self.release = "2.16.1"
+    version do
+      self.release = "2.18.0"
       self.base_url = "https://www.tensorflow.org/api_docs/cc"
     end
 

From ba294a12de116d024588ec982ce2bfe35202de07 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 09:31:35 +0100
Subject: [PATCH 227/384] Use navigator.clipboard.writeText

---
 assets/javascripts/lib/util.js                 | 18 ------------------
 assets/javascripts/views/content/entry_page.js |  7 +++----
 2 files changed, 3 insertions(+), 22 deletions(-)

diff --git a/assets/javascripts/lib/util.js b/assets/javascripts/lib/util.js
index c8668d4fbc..5226262d0c 100644
--- a/assets/javascripts/lib/util.js
+++ b/assets/javascripts/lib/util.js
@@ -526,21 +526,3 @@ $.highlight = function (el, options) {
   el.classList.add(options.className);
   setTimeout(() => el.classList.remove(options.className), options.delay);
 };
-
-$.copyToClipboard = function (string) {
-  let result;
-  const textarea = document.createElement("textarea");
-  textarea.style.position = "fixed";
-  textarea.style.opacity = 0;
-  textarea.value = string;
-  document.body.appendChild(textarea);
-  try {
-    textarea.select();
-    result = !!document.execCommand("copy");
-  } catch (error) {
-    result = false;
-  } finally {
-    document.body.removeChild(textarea);
-  }
-  return result;
-};
diff --git a/assets/javascripts/views/content/entry_page.js b/assets/javascripts/views/content/entry_page.js
index 95920878ee..280017ae15 100644
--- a/assets/javascripts/views/content/entry_page.js
+++ b/assets/javascripts/views/content/entry_page.js
@@ -217,10 +217,9 @@ app.views.EntryPage = class EntryPage extends app.View {
       this.load();
     } else if (target.classList.contains("_pre-clip")) {
       $.stopEvent(event);
-      target.classList.add(
-        $.copyToClipboard(target.parentNode.textContent)
-          ? "_pre-clip-success"
-          : "_pre-clip-error",
+      navigator.clipboard.writeText(target.parentNode.textContent).then(
+        () => target.classList.add("_pre-clip-success"),
+        () => target.classList.add("_pre-clip-error"),
       );
       setTimeout(() => (target.className = "_pre-clip"), 2000);
     }

From 8f29e60669fc42a3cf123e7a39ca184c50646683 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 09:35:21 +0100
Subject: [PATCH 228/384] Use Object.entries

---
 .../javascripts/views/content/entry_page.js   | 25 +++++++------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/assets/javascripts/views/content/entry_page.js b/assets/javascripts/views/content/entry_page.js
index 280017ae15..961d90e1fa 100644
--- a/assets/javascripts/views/content/entry_page.js
+++ b/assets/javascripts/views/content/entry_page.js
@@ -96,16 +96,9 @@ app.views.EntryPage = class EntryPage extends app.View {
       return content;
     }
 
-    const links = (() => {
-      const result = [];
-      for (var link in this.entry.doc.links) {
-        var url = this.entry.doc.links[link];
-        result.push(
-          `<a href="${url}" class="_links-link">${EntryPage.LINKS[link]}</a>`,
-        );
-      }
-      return result;
-    })();
+    const links = Object.entries(this.entry.doc.links).map(([link, url]) => {
+      return `<a href="${url}" class="_links-link">${EntryPage.LINKS[link]}</a>`;
+    });
 
     return `<p class="_links">${links.join("")}</p>${content}`;
   }
@@ -203,8 +196,8 @@ app.views.EntryPage = class EntryPage extends app.View {
   }
 
   restore() {
-    let path;
-    if (this.cacheMap[(path = this.entry.filePath())]) {
+    const path = this.entry.filePath();
+    if (this.cacheMap[[path]]) {
       this.render(this.cacheMap[path], true);
       return true;
     }
@@ -226,8 +219,8 @@ app.views.EntryPage = class EntryPage extends app.View {
   }
 
   onAltC() {
-    let link;
-    if (!(link = this.find("._attribution:last-child ._attribution-link"))) {
+    const link = this.find("._attribution:last-child ._attribution-link");
+    if (!link) {
       return;
     }
     console.log(link.href + location.hash);
@@ -235,8 +228,8 @@ app.views.EntryPage = class EntryPage extends app.View {
   }
 
   onAltO() {
-    let link;
-    if (!(link = this.find("._attribution:last-child ._attribution-link"))) {
+    const link = this.find("._attribution:last-child ._attribution-link");
+    if (!link) {
       return;
     }
     this.delay(() => $.popup(link.href + location.hash));

From 6dbe834e5706d6918d08793cd668395d4049aeb7 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 09:57:41 +0100
Subject: [PATCH 229/384] Update Three.js documentation (173)

---
 assets/javascripts/news.json           |  4 ++++
 lib/docs/filters/threejs/clean_html.rb | 18 ++++--------------
 lib/docs/scrapers/threejs.rb           | 16 +++++++---------
 3 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index 2c393d971b..b6c061b01e 100644
--- a/assets/javascripts/news.json
+++ b/assets/javascripts/news.json
@@ -1,4 +1,8 @@
 [
+  [
+    "2025-02-23",
+    "New documentation: <a href=\"/threejs/\">Three.js</a>"
+  ],
   [
     "2025-02-16",
     "New documentation: <a href=\"/openlayers/\">OpenLayers</a>"
diff --git a/lib/docs/filters/threejs/clean_html.rb b/lib/docs/filters/threejs/clean_html.rb
index 9b0de32445..01f43bc4d0 100644
--- a/lib/docs/filters/threejs/clean_html.rb
+++ b/lib/docs/filters/threejs/clean_html.rb
@@ -36,8 +36,8 @@ def remove_unnecessary_elements
       def wrap_code_blocks
         css('code').each do |node|
           next if node.parent.name == 'pre'
-          pre = node.wrap('<pre>')
-          pre['data-language'] = pre['class'] = 'language-javascript'
+          node.wrap('<pre>')
+          node.parent['data-language'] = 'javascript'
         end
       end
 
@@ -45,7 +45,8 @@ def process_sections
         # Handle source links
         css('h2').each do |node|
           next unless node.content.strip == 'Source'
-          handle_source_link(node)
+          node.next_element.remove
+          node.remove
         end
 
         # Handle method signatures and properties
@@ -65,17 +66,6 @@ def process_sections
         end
       end
 
-      def handle_source_link(node)
-        content = node.next_element&.inner_html
-        return unless content
-        content = content.gsub(/<[^>]+>/, '')
-        if content =~ /src\/(.*?)\.js/
-          path = "/#{$1}.js"
-          formatted_link = %Q(<a class="reference external" href="https://github.com/mrdoob/three.js/blob/master/src#{path}">src#{path}</a>)
-          node.next_element.inner_html = formatted_link if node.next_element
-        end
-      end
-
       def handle_method_signatures(content)
         content
           .gsub(PATTERNS[:method_this]) { format_method_signature('this', $1, $2) }
diff --git a/lib/docs/scrapers/threejs.rb b/lib/docs/scrapers/threejs.rb
index e596e03444..c3ef9bc25d 100644
--- a/lib/docs/scrapers/threejs.rb
+++ b/lib/docs/scrapers/threejs.rb
@@ -1,5 +1,5 @@
 module Docs
-  class Threejs < FileScraper
+  class Threejs < UrlScraper
     self.name = 'Three.js'
     self.type = 'simple'
     self.slug = 'threejs'
@@ -40,20 +40,18 @@ class Threejs < FileScraper
       Licensed under the MIT License.
     HTML
 
-    version '171' do
-      self.release = '171'
-      self.base_url = "https://threejs.org/docs"
-    end
+    self.release = '173'
+    self.base_url = "https://threejs.org/docs"
 
     def get_latest_version(opts)
-      get_latest_github_release('mrdoob', 'three.js', opts)
+      get_latest_github_release('mrdoob', 'three.js', opts)[1..]
     end
 
     def initial_paths
       paths = []
-      json_path = File.expand_path("/tmp/list.json")
-      json_content = File.read(json_path)
-      json_data = JSON.parse(json_content)
+      url = 'https://threejs.org/docs/list.json'
+      response = Request.run(url)
+      json_data = JSON.parse(response.body)
 
       # Process both API and manual sections
       process_documentation(json_data['en'], paths)

From 568e7c77eb95db4297674e9c645d89c1d99cb289 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 10:15:07 +0100
Subject: [PATCH 230/384] Update esbuild documentation (0.25.0)

---
 lib/docs/scrapers/esbuild.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/esbuild.rb b/lib/docs/scrapers/esbuild.rb
index a396d38061..3ae03c63d6 100644
--- a/lib/docs/scrapers/esbuild.rb
+++ b/lib/docs/scrapers/esbuild.rb
@@ -16,7 +16,7 @@ class Esbuild < UrlScraper
       Licensed under the MIT License.
     HTML
 
-    self.release = '0.23.1'
+    self.release = '0.25.0'
     self.base_url = 'https://esbuild.github.io/'
     html_filters.push 'esbuild/clean_html', 'esbuild/entries'
 

From 75ed540df8e680b4474e4bcd01967b865caa3126 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 10:15:35 +0100
Subject: [PATCH 231/384] Update Rust documentation (1.85.0)

---
 lib/docs/scrapers/rust.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/rust.rb b/lib/docs/scrapers/rust.rb
index fbbb1415da..1b832d8756 100644
--- a/lib/docs/scrapers/rust.rb
+++ b/lib/docs/scrapers/rust.rb
@@ -3,7 +3,7 @@
 module Docs
   class Rust < UrlScraper
     self.type = 'rust'
-    self.release = '1.84.1'
+    self.release = '1.85.0'
     self.base_url = 'https://doc.rust-lang.org/'
     self.root_path = 'book/index.html'
     self.initial_paths = %w(

From 1305b4ae58b0e22ea38d7426004a472d3fde9e84 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 23 Feb 2025 15:17:17 +0100
Subject: [PATCH 232/384] Update TensorFlow documentation (2.16.1)

The documentation on https://www.tensorflow.org/versions does not match
the latest release on https://github.com/tensorflow/tensorflow/releases.

See also: https://github.com/freeCodeCamp/devdocs/pull/2440#issuecomment-2676859096
---
 lib/docs/scrapers/tensorflow/tensorflow.rb     | 5 +++--
 lib/docs/scrapers/tensorflow/tensorflow_cpp.rb | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/docs/scrapers/tensorflow/tensorflow.rb b/lib/docs/scrapers/tensorflow/tensorflow.rb
index 9d3cdb58de..770d35b87c 100644
--- a/lib/docs/scrapers/tensorflow/tensorflow.rb
+++ b/lib/docs/scrapers/tensorflow/tensorflow.rb
@@ -20,7 +20,7 @@ class Tensorflow < UrlScraper
     HTML
 
     version do
-      self.release = "2.18.0"
+      self.release = "2.16.1"
       self.base_url = "https://www.tensorflow.org/api_docs/python/tf"
     end
 
@@ -45,7 +45,8 @@ class Tensorflow < UrlScraper
     end
 
     def get_latest_version(opts)
-      get_latest_github_release('tensorflow', 'tensorflow', opts)
+      doc = fetch_doc(self.base_url, opts)
+      doc.title[/TensorFlow v([.\d]+)/, 1]
     end
 
     private
diff --git a/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb b/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
index 6fe3c86a3e..9839dafbe1 100644
--- a/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
+++ b/lib/docs/scrapers/tensorflow/tensorflow_cpp.rb
@@ -4,7 +4,7 @@ class TensorflowCpp < Tensorflow
     self.slug = 'tensorflow_cpp'
 
     version do
-      self.release = "2.18.0"
+      self.release = "2.16.1"
       self.base_url = "https://www.tensorflow.org/api_docs/cc"
     end
 

From df4b3fdb14883e5c0a6888e23bb6e744cc63163b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 25 Feb 2025 22:44:37 +0000
Subject: [PATCH 233/384] Update dependency redcarpet to v3.6.1

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 9ccdd742df..6ac4dba67c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -89,7 +89,7 @@ GEM
     rb-fsevent (0.11.2)
     rb-inotify (0.10.1)
       ffi (~> 1.0)
-    redcarpet (3.6.0)
+    redcarpet (3.6.1)
     reline (0.6.0)
       io-console (~> 0.5)
     rexml (3.3.9)

From ccb4e9cc81af2551dbac0576f16f641239df279b Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 26 Feb 2025 19:35:14 +0000
Subject: [PATCH 234/384] Update docker/metadata-action digest to 902fa8e

---
 .github/workflows/docker-build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index cd84ea4603..ef03b89a04 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -37,7 +37,7 @@ jobs:
 
       - name: Extract metadata for Docker
         id: meta
-        uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5
+        uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
         with:
           images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
           tags: |

From ff9ac9d7f72dc089fce1af08fd1acd5d715c6fed Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 4 Mar 2025 11:26:13 +0000
Subject: [PATCH 235/384] Update dependency rack to v2.2.12

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 6ac4dba67c..c648323e19 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -78,7 +78,7 @@ GEM
       byebug (~> 11.0)
       pry (>= 0.13, < 0.15)
     racc (1.8.1)
-    rack (2.2.11)
+    rack (2.2.12)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)

From 2790f1d033a99f8d37c278eff14c9d1a7ee7cc80 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 5 Mar 2025 22:19:24 +0000
Subject: [PATCH 236/384] Update ruby/setup-ruby action to v1.222.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 10f4c0d15a..eeff921e23 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # v1.221.0
+      uses: ruby/setup-ruby@277ba2a127aba66d45bad0fa2dc56f80dbfedffa # v1.222.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 137cec66fe..e1088bf2b1 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # v1.221.0
+      uses: ruby/setup-ruby@277ba2a127aba66d45bad0fa2dc56f80dbfedffa # v1.222.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 70c3d4d2b9..13a4d952eb 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # v1.221.0
+      uses: ruby/setup-ruby@277ba2a127aba66d45bad0fa2dc56f80dbfedffa # v1.222.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From fd4682c7b6b1b6e2dd1961b63f3d39a8dbb8b52c Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 6 Mar 2025 09:51:31 +0100
Subject: [PATCH 237/384] Update Python documentation (3.13.2)

---
 lib/docs/filters/sphinx/clean_html.rb | 2 +-
 lib/docs/scrapers/python.rb           | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/docs/filters/sphinx/clean_html.rb b/lib/docs/filters/sphinx/clean_html.rb
index 36bb96d9eb..9e08c76688 100644
--- a/lib/docs/filters/sphinx/clean_html.rb
+++ b/lib/docs/filters/sphinx/clean_html.rb
@@ -24,7 +24,7 @@ def call
           lang = 'php' if lang == 'ci'|| lang == 'html+php'
           lang = 'markup' if lang == 'html+django'
           lang = 'bash' if lang == 'bash'
-          lang = 'python' if lang == 'default' || lang.start_with?('python') || lang.start_with?('ipython')
+          lang = 'python' if lang == 'default' || lang == 'pycon' || lang.start_with?('python') || lang.start_with?('ipython')
           pre['data-language'] = lang
           node.replace(pre)
         end
diff --git a/lib/docs/scrapers/python.rb b/lib/docs/scrapers/python.rb
index 9334e91433..781b0df9a2 100644
--- a/lib/docs/scrapers/python.rb
+++ b/lib/docs/scrapers/python.rb
@@ -23,26 +23,26 @@ class Python < UrlScraper
       library/sunau.html)
 
     options[:attribution] = <<-HTML
-      &copy; 2001&ndash;2024 Python Software Foundation<br>
+      &copy; 2001&ndash;2025 Python Software Foundation<br>
       Licensed under the PSF License.
     HTML
 
     version '3.13' do
-      self.release = '3.13.1'
+      self.release = '3.13.2'
       self.base_url = "https://docs.python.org/#{self.version}/"
 
       html_filters.push 'python/entries_v3', 'sphinx/clean_html', 'python/clean_html'
     end
 
     version '3.12' do
-      self.release = '3.12.5'
+      self.release = '3.12.9'
       self.base_url = "https://docs.python.org/#{self.version}/"
 
       html_filters.push 'python/entries_v3', 'sphinx/clean_html', 'python/clean_html'
     end
 
     version '3.11' do
-      self.release = '3.11.7'
+      self.release = '3.11.11'
       self.base_url = "https://docs.python.org/#{self.version}/"
 
       html_filters.push 'python/entries_v3', 'sphinx/clean_html', 'python/clean_html'

From 01bcf585682cfa7b873d78c24029a9285e942031 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Mon, 10 Mar 2025 20:35:37 +0100
Subject: [PATCH 238/384] Update Backbone.js documentation (1.6.0)

---
 lib/docs/scrapers/backbone.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/backbone.rb b/lib/docs/scrapers/backbone.rb
index cff7b7c217..f7cfdaa457 100644
--- a/lib/docs/scrapers/backbone.rb
+++ b/lib/docs/scrapers/backbone.rb
@@ -3,7 +3,7 @@ class Backbone < UrlScraper
     self.name = 'Backbone.js'
     self.slug = 'backbone'
     self.type = 'underscore'
-    self.release = '1.5.0'
+    self.release = '1.6.0'
     self.base_url = 'https://backbonejs.org'
     self.links = {
       home: 'https://backbonejs.org/',
@@ -17,7 +17,7 @@ class Backbone < UrlScraper
     options[:skip_links] = true
 
     options[:attribution] = <<-HTML
-      &copy; 2010&ndash;2023 Jeremy Ashkenas, DocumentCloud<br>
+      &copy; 2010&ndash;2024 Jeremy Ashkenas, DocumentCloud<br>
       Licensed under the MIT License.
     HTML
 

From ee145d748f61a679084e8c1cb754511e62a4f9d4 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Mon, 10 Mar 2025 20:57:00 +0100
Subject: [PATCH 239/384] Fix Docs.aliases

---
 lib/docs.rb               | 12 ++++++------
 lib/docs/core/manifest.rb |  2 +-
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/docs.rb b/lib/docs.rb
index f8ab6a039f..a09aae76df 100644
--- a/lib/docs.rb
+++ b/lib/docs.rb
@@ -112,31 +112,31 @@ def self.aliases
     {
       'angular' => 'ng',
       'angular.js' => 'ng',
-      'backbone.js' => 'bb',
-      'c++' => 'cpp',
+      'backbone' => 'bb',
+      'cpp' => 'c++',
       'coffeescript' => 'cs',
       'crystal' => 'cr',
       'elixir' => 'ex',
       'javascript' => 'js',
       'julia' => 'jl',
       'jquery' => '$',
-      'knockout.js' => 'ko',
+      'knockout' => 'ko',
       'kubernetes' => 'k8s',
       'less' => 'ls',
       'lodash' => '_',
-      'löve' => 'love',
+      'love' => 'löve',
       'marionette' => 'mn',
       'markdown' => 'md',
       'matplotlib' => 'mpl',
       'modernizr' => 'mdr',
-      'moment.js' => 'mt',
+      'moment' => 'mt',
       'openjdk' => 'java',
       'nginx' => 'ngx',
       'numpy' => 'np',
       'pandas' => 'pd',
       'postgresql' => 'pg',
       'python' => 'py',
-      'ruby.on.rails' => 'ror',
+      'rails' => 'ror',
       'ruby' => 'rb',
       'rust' => 'rs',
       'sass' => 'scss',
diff --git a/lib/docs/core/manifest.rb b/lib/docs/core/manifest.rb
index ac3162ca09..80dc45baa8 100644
--- a/lib/docs/core/manifest.rb
+++ b/lib/docs/core/manifest.rb
@@ -20,7 +20,7 @@ def as_json
         if doc.options[:attribution].is_a?(String)
           json[:attribution] = doc.options[:attribution].strip
         end
-        json[:alias] = Docs.aliases[doc.slug]
+        json[:alias] = Docs.aliases[doc.slug[/^[^~]+/, 0]]
         result << json
       end
     end

From 9ff5ff43f1676f5941ebf0c278b4e487bebf01b8 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 10 Mar 2025 23:03:28 +0000
Subject: [PATCH 240/384] Update dependency rack to v2.2.13

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index c648323e19..be4c1dfc6e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -78,7 +78,7 @@ GEM
       byebug (~> 11.0)
       pry (>= 0.13, < 0.15)
     racc (1.8.1)
-    rack (2.2.12)
+    rack (2.2.13)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)

From 306322b9cf28155640bc8fea8e7f18bfaf17d3b6 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 11 Mar 2025 13:33:46 +0000
Subject: [PATCH 241/384] Update ruby/setup-ruby action to v1.224.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index eeff921e23..e6c0209557 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@277ba2a127aba66d45bad0fa2dc56f80dbfedffa # v1.222.0
+      uses: ruby/setup-ruby@bbda85882f33075a3727c01e3c8d0de0be6146ce # v1.224.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index e1088bf2b1..c3f91f5381 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@277ba2a127aba66d45bad0fa2dc56f80dbfedffa # v1.222.0
+      uses: ruby/setup-ruby@bbda85882f33075a3727c01e3c8d0de0be6146ce # v1.224.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 13a4d952eb..0ceacd16de 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@277ba2a127aba66d45bad0fa2dc56f80dbfedffa # v1.222.0
+      uses: ruby/setup-ruby@bbda85882f33075a3727c01e3c8d0de0be6146ce # v1.224.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From eaf31ce6984c0bc3147522aba0af155612d8d2eb Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 12 Mar 2025 22:38:27 +0000
Subject: [PATCH 242/384] Update dependency minitest to v5.25.5

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index be4c1dfc6e..986c19626d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -58,7 +58,7 @@ GEM
     logger (1.6.2)
     method_source (1.0.0)
     mini_portile2 (2.8.8)
-    minitest (5.25.4)
+    minitest (5.25.5)
     multi_json (1.15.0)
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)

From 4a09bcad191f6515efc2eecc6745b12c1f846ae8 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 13 Mar 2025 23:08:22 +0000
Subject: [PATCH 243/384] Update ruby/setup-ruby action to v1.225.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e6c0209557..1a7f67afb1 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bbda85882f33075a3727c01e3c8d0de0be6146ce # v1.224.0
+      uses: ruby/setup-ruby@6c79f721fa26dd64559c2700086ac852c18e0756 # v1.225.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index c3f91f5381..dc24142824 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bbda85882f33075a3727c01e3c8d0de0be6146ce # v1.224.0
+      uses: ruby/setup-ruby@6c79f721fa26dd64559c2700086ac852c18e0756 # v1.225.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 0ceacd16de..2fb9174c6e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bbda85882f33075a3727c01e3c8d0de0be6146ce # v1.224.0
+      uses: ruby/setup-ruby@6c79f721fa26dd64559c2700086ac852c18e0756 # v1.225.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 8a81696c2cc5de8804f29fe1c308ec090e9bbbd4 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 14 Mar 2025 10:28:46 +0000
Subject: [PATCH 244/384] Update docker/login-action digest to 74a5d14

---
 .github/workflows/docker-build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index ef03b89a04..9651a50c99 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -29,7 +29,7 @@ jobs:
           persist-credentials: false
 
       - name: Log in to the Container registry
-        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
+        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
         with:
           registry: ${{ env.REGISTRY }}
           username: ${{ github.actor }}

From 65440bfec4ce2c0ea3da3388a1adf177a806b410 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 14 Mar 2025 18:13:03 +0000
Subject: [PATCH 245/384] Update dependency nokogiri to v1.18.4

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 986c19626d..f195f5b2d1 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -63,7 +63,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.3)
+    nokogiri (1.18.4)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From 9958c5dc36266a72bc89d8624165a25b9a9ed1a9 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 15 Mar 2025 13:21:42 +0000
Subject: [PATCH 246/384] Update ruby/setup-ruby action to v1.226.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1a7f67afb1..f8a678e968 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@6c79f721fa26dd64559c2700086ac852c18e0756 # v1.225.0
+      uses: ruby/setup-ruby@922ebc4c5262cd14e07bb0e1db020984b6c064fe # v1.226.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index dc24142824..3936101ca1 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@6c79f721fa26dd64559c2700086ac852c18e0756 # v1.225.0
+      uses: ruby/setup-ruby@922ebc4c5262cd14e07bb0e1db020984b6c064fe # v1.226.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 2fb9174c6e..835b0ab660 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@6c79f721fa26dd64559c2700086ac852c18e0756 # v1.225.0
+      uses: ruby/setup-ruby@922ebc4c5262cd14e07bb0e1db020984b6c064fe # v1.226.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From e69933c9a144fa15ca79b8985616d5e3ef69d1ff Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 09:32:17 +0100
Subject: [PATCH 247/384] Update Vitest documentation (3.0.8)

---
 lib/docs/filters/vitest/entries.rb |  7 +++----
 lib/docs/scrapers/vitest.rb        | 13 +++++++++++--
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/lib/docs/filters/vitest/entries.rb b/lib/docs/filters/vitest/entries.rb
index daa43bc5ba..1d387e81b9 100644
--- a/lib/docs/filters/vitest/entries.rb
+++ b/lib/docs/filters/vitest/entries.rb
@@ -9,10 +9,9 @@ def get_name
       end
 
       def get_type
-        name = at_css('h1').content
-        name.sub! %r{\s*#\s*}, ''
-        name.sub! %r{\s*\u200B\s*}, ''
-        name
+        return 'browser' if slug.starts_with?('guide/browser')
+        return 'cli' if slug.starts_with?('guide/cli')
+        return slug.split('/').first
       end
 
       def additional_entries
diff --git a/lib/docs/scrapers/vitest.rb b/lib/docs/scrapers/vitest.rb
index bbb82a27c4..ab7a3d1bb3 100644
--- a/lib/docs/scrapers/vitest.rb
+++ b/lib/docs/scrapers/vitest.rb
@@ -10,6 +10,7 @@ class Vitest < UrlScraper
 
     options[:root_title] = 'Vitest'
     options[:download_images] = false
+    options[:skip] = %w(blog)
 
     options[:attribution] = <<-HTML
       &copy; 2021-Present Anthony Fu<br>
@@ -17,10 +18,18 @@ class Vitest < UrlScraper
       Licensed under the MIT License.
     HTML
 
-    self.release = '2.0.3'
-    self.base_url = 'https://vitest.dev/'
     self.initial_paths = %w(guide/)
     html_filters.push 'vitest/entries', 'vite/clean_html'
+    
+    version do
+      self.release = '3.0.8'
+      self.base_url = 'https://vitest.dev/'
+    end
+    
+    version '2' do
+      self.release = '2.1.9'
+      self.base_url = 'https://v2.vitest.dev/'
+    end
 
     def get_latest_version(opts)
       get_npm_version('vitest', opts)

From bad8f3e15e89cdb28f37f971da36fbb35021ca91 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 09:33:09 +0100
Subject: [PATCH 248/384] Update Vite documentation (6.2.2)

---
 lib/docs/scrapers/vite.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vite.rb b/lib/docs/scrapers/vite.rb
index 4ca7b9d38f..4b2fa6132d 100644
--- a/lib/docs/scrapers/vite.rb
+++ b/lib/docs/scrapers/vite.rb
@@ -22,7 +22,7 @@ class Vite < UrlScraper
     html_filters.push 'vite/entries', 'vite/clean_html'
 
     version do
-      self.release = '6.1.0'
+      self.release = '6.2.2'
       self.base_url = 'https://vite.dev/'
     end
 

From 29f6e1c84c7327a9242c1a373f718b4b4244cb10 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 09:37:36 +0100
Subject: [PATCH 249/384] Update Fish documentation (4.0.1)

---
 lib/docs/filters/fish/entries_sphinx.rb |  2 +-
 lib/docs/scrapers/fish.rb               | 12 ++++++++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/docs/filters/fish/entries_sphinx.rb b/lib/docs/filters/fish/entries_sphinx.rb
index 9d33de179f..f60227ee60 100755
--- a/lib/docs/filters/fish/entries_sphinx.rb
+++ b/lib/docs/filters/fish/entries_sphinx.rb
@@ -14,7 +14,7 @@ def get_name
       end
 
       def get_type
-        if root_page? || slug == 'faq' || slug == 'completions' || slug == 'fish_for_bash_users'
+        if root_page? || slug == 'faq' || slug == 'completions' || slug == 'fish_for_bash_users' || slug == 'prompt'
           'Manual'
         elsif slug.starts_with?('cmds') || slug == 'commands'
           'Commands'
diff --git a/lib/docs/scrapers/fish.rb b/lib/docs/scrapers/fish.rb
index 8e9c3326e0..6bf6e0ff63 100644
--- a/lib/docs/scrapers/fish.rb
+++ b/lib/docs/scrapers/fish.rb
@@ -8,14 +8,22 @@ class Fish < UrlScraper
       code: 'https://github.com/fish-shell/fish-shell'
     }
 
-    options[:skip] = %w(design.html license.html)
+    options[:skip] = %w(design.html license.html contributing.html)
 
     # https://fishshell.com/docs/current/license.html
     options[:attribution] = <<-HTML
-      &copy; 2005-2009 Axel Liljencrantz, 2009-2023 fish-shell contributors<br>
+      &copy; 2005-2009 Axel Liljencrantz, 2009-2025 fish-shell contributors<br>
       Licensed under the GNU General Public License, version 2.
     HTML
 
+    version '4.0' do
+      self.release = '4.0.1'
+      self.base_url = "https://fishshell.com/docs/#{version}/"
+
+      options[:skip].concat %w(genindex.html relnotes.html)
+      html_filters.push 'sphinx/clean_html', 'fish/clean_html_sphinx', 'fish/entries_sphinx'
+    end
+
     version '3.7' do
       self.release = '3.7.0'
       self.base_url = "https://fishshell.com/docs/#{version}/"

From 3d5dba281d3e53ae682e84135e60b427489a25cf Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 09:39:35 +0100
Subject: [PATCH 250/384] Update OCaml documentation (5.3)

---
 lib/docs/scrapers/ocaml.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/ocaml.rb b/lib/docs/scrapers/ocaml.rb
index 4718546fbb..97a25a9413 100644
--- a/lib/docs/scrapers/ocaml.rb
+++ b/lib/docs/scrapers/ocaml.rb
@@ -25,7 +25,7 @@ class Ocaml < UrlScraper
     HTML
 
     version '' do
-      self.release = '5.2'
+      self.release = '5.3'
       self.base_url = "https://ocaml.org/manual/#{self.release}/"
     end
 

From 4728005ac721c54928e06da9653e772d7bc2e1e1 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 09:40:53 +0100
Subject: [PATCH 251/384] Update Playwright documentation (1.51.0)

---
 lib/docs/scrapers/playwright.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/playwright.rb b/lib/docs/scrapers/playwright.rb
index c8e2c70e12..b594a78fcb 100644
--- a/lib/docs/scrapers/playwright.rb
+++ b/lib/docs/scrapers/playwright.rb
@@ -2,7 +2,7 @@ module Docs
   class Playwright < UrlScraper
     self.name = 'Playwright'
     self.type = 'simple'
-    self.release = '1.49.0'
+    self.release = '1.51.0'
     self.base_url = 'https://playwright.dev/docs/'
     self.root_path = 'intro'
     self.links = {
@@ -16,7 +16,7 @@ class Playwright < UrlScraper
 
 	# https://github.com/microsoft/playwright/blob/main/LICENSE
     options[:attribution] = <<-HTML
-      &copy; 2024 Microsoft<br>
+      &copy; 2025 Microsoft<br>
 	  Licensed under the Apache License, Version 2.0.
     HTML
 

From 53c8da0a76e1e3678b0475f5b6712bcb1982c1c0 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 09:51:16 +0100
Subject: [PATCH 252/384] Update Prettier documentation (3.5.3)

---
 lib/docs/filters/prettier/clean_html.rb |  8 +++++---
 lib/docs/filters/prettier/entries.rb    | 11 +++++------
 lib/docs/scrapers/prettier.rb           |  7 +++----
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/lib/docs/filters/prettier/clean_html.rb b/lib/docs/filters/prettier/clean_html.rb
index e32b72b767..4ee99fadfc 100644
--- a/lib/docs/filters/prettier/clean_html.rb
+++ b/lib/docs/filters/prettier/clean_html.rb
@@ -2,7 +2,7 @@ module Docs
   class Prettier
     class CleanHtmlFilter < Filter
       def call
-        @doc = at_css('.post')
+        @doc = at_css('article .markdown')
 
         if root_page?
           at_css('h1').content = 'React Native Documentation'
@@ -34,10 +34,12 @@ def call
           node.replace(node.at_css('pre.highlight'))
         end
 
-        css('.prism').each do |node|
+        css('.prism-code').each do |node|
           node.name = 'pre'
           node['data-language'] = node['class'][/(?<=language\-)(\w+)/]
-          node.content = node.content
+          node.content = node.css('.token-line').map(&:content).join("\n")
+          node.remove_attribute('class')
+          node.remove_attribute('style')
         end
 
         css('pre > code.hljs').each do |node|
diff --git a/lib/docs/filters/prettier/entries.rb b/lib/docs/filters/prettier/entries.rb
index c3411a0579..c58b35b5eb 100644
--- a/lib/docs/filters/prettier/entries.rb
+++ b/lib/docs/filters/prettier/entries.rb
@@ -6,9 +6,9 @@ def get_name
       end
 
       def type
-        link = at_css('.navListItemActive')
-        section = link.ancestors('.navGroup').first
-        type = section.at_css('h3').content.strip
+        link = at_css('.menu__link--active')
+        section = link.ancestors('.theme-doc-sidebar-item-category-level-1').first
+        type = section.at_css('.menu__link--sublist').content.strip
         return name if type == 'Configuring Prettier'
         return name if type == 'Usage'
         type
@@ -16,9 +16,8 @@ def type
 
       def additional_entries
         entries = []
-        css('.mainContainer h2').each do |node|
-          id = node.at_css('.anchor')['id']
-          entries << [node.text, id]
+        css('h2').each do |node|
+          entries << [node.text, node['id']]
         end
         entries
       end
diff --git a/lib/docs/scrapers/prettier.rb b/lib/docs/scrapers/prettier.rb
index 98fbafa1c7..5e6e0757a2 100644
--- a/lib/docs/scrapers/prettier.rb
+++ b/lib/docs/scrapers/prettier.rb
@@ -2,8 +2,8 @@ module Docs
   class Prettier < UrlScraper
     self.name = 'Prettier'
     self.type = 'simple'
-    self.release = '3.4.2'
-    self.base_url = 'https://prettier.io/docs/en/'
+    self.release = '3.5.3'
+    self.base_url = 'https://prettier.io/docs/'
     self.links = {
       home: 'https://prettier.io/',
       code: 'https://github.com/prettier/prettier'
@@ -12,11 +12,10 @@ class Prettier < UrlScraper
     # Docusaurus like react_native
     html_filters.push 'prettier/entries', 'prettier/clean_html'
 
-    options[:container] = '.docMainWrapper'
-
     options[:attribution] = <<-HTML
       &copy; James Long and contributors
     HTML
+    options[:skip_patterns] = [ /^next/ ]
 
     def get_latest_version(opts)
       get_npm_version('prettier', opts)

From 13e3a2db72a9a7c219f1207c7b9e4392ae5d9faa Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 09:54:07 +0100
Subject: [PATCH 253/384] Update TypeScript documentation (5.8.2)

---
 lib/docs/scrapers/typescript.rb | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/lib/docs/scrapers/typescript.rb b/lib/docs/scrapers/typescript.rb
index 59398c8717..e3b2ce86cd 100644
--- a/lib/docs/scrapers/typescript.rb
+++ b/lib/docs/scrapers/typescript.rb
@@ -19,16 +19,6 @@ def initial_urls
 
     html_filters.push 'typescript/entries', 'typescript/clean_html', 'title'
 
-    options[:fix_urls_before_parse] = ->(url) do
-      url.sub! '/docs/handbook/esm-node.html', '/docs/handbook/modules/reference.html#node16-nodenext'
-      url.sub! '/docs/handbook/modules.html', '/docs/handbook/modules/introduction.html'
-      url
-    end
-
-    options[:skip] = [
-      'react-&-webpack.html'
-    ]
-
     options[:skip_patterns] = [
       /\Abranding/,
       /\Acommunity/,
@@ -40,12 +30,12 @@ def initial_urls
     ]
 
     options[:attribution] = <<-HTML
-      &copy; 2012-2024 Microsoft<br>
+      &copy; 2012-2025 Microsoft<br>
       Licensed under the Apache License, Version 2.0.
     HTML
 
     version do
-      self.release = '5.7.2'
+      self.release = '5.8.2'
       self.base_urls = [
         'https://www.typescriptlang.org/docs/handbook/',
         'https://www.typescriptlang.org/'

From ab18909a01bcdbccdbd9053aaeea8e4de77e5002 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 13:50:48 +0100
Subject: [PATCH 254/384] Update TypeScript documentation (5.8.2)

Remove MultipleBaseUrls.

Fixes #2455.
---
 lib/docs/scrapers/typescript.rb | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/lib/docs/scrapers/typescript.rb b/lib/docs/scrapers/typescript.rb
index e3b2ce86cd..5f34a31df9 100644
--- a/lib/docs/scrapers/typescript.rb
+++ b/lib/docs/scrapers/typescript.rb
@@ -1,17 +1,10 @@
 module Docs
   class Typescript < UrlScraper
-    include MultipleBaseUrls
-
     self.name = 'TypeScript'
     self.type = 'typescript'
 
     self.root_path = 'docs/'
 
-    def initial_urls
-      [ 'https://www.typescriptlang.org/docs/handbook/',
-        'https://www.typescriptlang.org/tsconfig' ]
-    end
-
     self.links = {
       home: 'https://www.typescriptlang.org',
       code: 'https://github.com/Microsoft/TypeScript'
@@ -19,11 +12,17 @@ def initial_urls
 
     html_filters.push 'typescript/entries', 'typescript/clean_html', 'title'
 
+    options[:only_patterns] = [
+      /\Adocs\Z/,
+      /\Adocs\/handbook/,
+      /\Atsconfig/,
+    ]
     options[:skip_patterns] = [
       /\Abranding/,
       /\Acommunity/,
       /\Adocs\Z/,
       /\Atools/,
+      /react.*webpack/,
       /release-notes/,
       /dt\/search/,
       /play/
@@ -36,10 +35,7 @@ def initial_urls
 
     version do
       self.release = '5.8.2'
-      self.base_urls = [
-        'https://www.typescriptlang.org/docs/handbook/',
-        'https://www.typescriptlang.org/'
-      ]
+      self.base_url = 'https://www.typescriptlang.org/'
     end
 
     version '5.1' do

From 1a03dc7dff6dea52aff7f5a4bfaff6e93d45fed2 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 16 Mar 2025 13:56:39 +0100
Subject: [PATCH 255/384] Update SQLite documentation (3.49.1)

---
 lib/docs/filters/sqlite/clean_html.rb | 2 +-
 lib/docs/scrapers/sqlite.rb           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/filters/sqlite/clean_html.rb b/lib/docs/filters/sqlite/clean_html.rb
index ae74228431..9bf7845332 100644
--- a/lib/docs/filters/sqlite/clean_html.rb
+++ b/lib/docs/filters/sqlite/clean_html.rb
@@ -90,7 +90,7 @@ def call
         css('svg *[style], svg *[fill]').each do |node|
           next if slug == 'geopoly'
           # transform style in SVG diagrams, e.g. on https://sqlite.org/lang_insert.html
-          if node['style'] == 'fill:rgb(0,0,0)' or node['fill'] == 'rgb(0,0,0)'
+          if (node['style'] or '').starts_with?('fill:rgb(0,0,0)') or node['fill'] == 'rgb(0,0,0)'
             node.add_class('fill')
             node.remove_attribute('fill')
           elsif node['style'] == 'fill:none;stroke-width:2.16;stroke:rgb(0,0,0);'
diff --git a/lib/docs/scrapers/sqlite.rb b/lib/docs/scrapers/sqlite.rb
index a9529e9804..7de3e57f12 100644
--- a/lib/docs/scrapers/sqlite.rb
+++ b/lib/docs/scrapers/sqlite.rb
@@ -2,7 +2,7 @@ module Docs
   class Sqlite < UrlScraper
     self.name = 'SQLite'
     self.type = 'sqlite'
-    self.release = '3.47.0'
+    self.release = '3.49.1'
     self.base_url = 'https://sqlite.org/'
     self.root_path = 'docs.html'
     self.initial_paths = %w(keyword_index.html)

From 63d5b9959d48ad17b0405bfad916c9c74e1e076f Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 18 Mar 2025 18:40:36 +0000
Subject: [PATCH 256/384] Update ruby/setup-ruby action to v1.227.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f8a678e968..0426da61c4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@922ebc4c5262cd14e07bb0e1db020984b6c064fe # v1.226.0
+      uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 3936101ca1..0b4c0d9f7b 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@922ebc4c5262cd14e07bb0e1db020984b6c064fe # v1.226.0
+      uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 835b0ab660..6e28c2a37e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@922ebc4c5262cd14e07bb0e1db020984b6c064fe # v1.226.0
+      uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 1bdb9ec751ec59b55181f9d8e9c1ea3ef148dea3 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 19 Mar 2025 18:39:22 +0000
Subject: [PATCH 257/384] Update dependency nokogiri to v1.18.5

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index f195f5b2d1..579554c48c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -63,7 +63,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.4)
+    nokogiri (1.18.5)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From e9a1fee6d3ef5e69f69045cc0aebc4e68a4b2c2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Moritz=20M=C3=BCller?= <moritzm.mueller@posteo.de>
Date: Thu, 20 Mar 2025 11:11:14 +0100
Subject: [PATCH 258/384] Update Qt documentation (6.8)

---
 lib/docs/scrapers/qt.rb | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/docs/scrapers/qt.rb b/lib/docs/scrapers/qt.rb
index 640bbe1467..af27e8c0af 100644
--- a/lib/docs/scrapers/qt.rb
+++ b/lib/docs/scrapers/qt.rb
@@ -103,6 +103,11 @@ class Qt < UrlScraper
       Licensed under the GNU Free Documentation License, Version 1.3.
     HTML
 
+    version '6.8' do
+      self.release = '6.8'
+      self.base_url = "https://doc.qt.io/qt-#{self.release}/"
+    end
+
     version do
       self.release = '6.2'
       self.base_url = "https://doc.qt.io/qt-#{self.release}/"

From 5f7841bf5dbde8f957770d3bec28a9b200480669 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 24 Mar 2025 20:14:50 +0000
Subject: [PATCH 259/384] Update dependency nokogiri to v1.18.6

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 579554c48c..899c53025c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -63,7 +63,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.5)
+    nokogiri (1.18.6)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From 6d8204211ef856c39cde955ec53a4894859c66eb Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 26 Mar 2025 13:04:57 +0000
Subject: [PATCH 260/384] Update ruby/setup-ruby action to v1.228.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0426da61c4..ff8324f884 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
+      uses: ruby/setup-ruby@7886c6653556e1164c58a7603d88286b5f708293 # v1.228.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 0b4c0d9f7b..67ed2af627 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
+      uses: ruby/setup-ruby@7886c6653556e1164c58a7603d88286b5f708293 # v1.228.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6e28c2a37e..36b8678e95 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
+      uses: ruby/setup-ruby@7886c6653556e1164c58a7603d88286b5f708293 # v1.228.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 725fa5104e90a2c711294c978b375fa4582d3573 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 27 Mar 2025 12:37:20 +0000
Subject: [PATCH 261/384] Update ruby/setup-ruby action to v1.229.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ff8324f884..098c3d8efd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7886c6653556e1164c58a7603d88286b5f708293 # v1.228.0
+      uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1.229.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 67ed2af627..700c47bce6 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7886c6653556e1164c58a7603d88286b5f708293 # v1.228.0
+      uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1.229.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 36b8678e95..9372adee05 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@7886c6653556e1164c58a7603d88286b5f708293 # v1.228.0
+      uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1.229.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 09408ea855850eb3c164964d4a560bd638844fd2 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 28 Mar 2025 15:54:47 +0000
Subject: [PATCH 262/384] Update dependency pry-byebug to v3.11.0

---
 Gemfile.lock | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 899c53025c..267bc469b9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -21,7 +21,7 @@ GEM
       rouge (>= 1.0.0)
     bigdecimal (3.1.8)
     browser (5.3.1)
-    byebug (11.1.3)
+    byebug (12.0.0)
     chunky_png (1.4.0)
     coderay (1.1.3)
     concurrent-ruby (1.3.4)
@@ -56,7 +56,7 @@ GEM
     in_threads (1.6.0)
     io-console (0.8.0)
     logger (1.6.2)
-    method_source (1.0.0)
+    method_source (1.1.0)
     mini_portile2 (2.8.8)
     minitest (5.25.5)
     multi_json (1.15.0)
@@ -71,12 +71,12 @@ GEM
     progress_bar (1.3.4)
       highline (>= 1.6)
       options (~> 2.3.0)
-    pry (0.14.2)
+    pry (0.15.2)
       coderay (~> 1.1)
       method_source (~> 1.0)
-    pry-byebug (3.10.1)
-      byebug (~> 11.0)
-      pry (>= 0.13, < 0.15)
+    pry-byebug (3.11.0)
+      byebug (~> 12.0)
+      pry (>= 0.13, < 0.16)
     racc (1.8.1)
     rack (2.2.13)
     rack-protection (3.2.0)

From c9b71bf9772e38f3f213e9192312328f3078f1e7 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 31 Mar 2025 18:28:28 +0000
Subject: [PATCH 263/384] Update dependency nokogiri to v1.18.7

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 267bc469b9..b4568f3aa2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -63,7 +63,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.6)
+    nokogiri (1.18.7)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From 375c2ba96f00656d6bc12a31de6010287104a9fe Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 7 Apr 2025 22:42:08 +0000
Subject: [PATCH 264/384] Update dependency rr to v3.1.2

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index b4568f3aa2..ffeaa732e3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -94,7 +94,7 @@ GEM
       io-console (~> 0.5)
     rexml (3.3.9)
     rouge (1.11.1)
-    rr (3.1.1)
+    rr (3.1.2)
     rss (0.3.1)
       rexml
     ruby2_keywords (0.0.5)

From 3fabf603dc246ec201c124c4df31489716d102c5 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 11 Apr 2025 19:13:04 +0200
Subject: [PATCH 265/384] Update Qt documentation (6.8)

---
 lib/docs/scrapers/qt.rb | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/docs/scrapers/qt.rb b/lib/docs/scrapers/qt.rb
index af27e8c0af..3371120be3 100644
--- a/lib/docs/scrapers/qt.rb
+++ b/lib/docs/scrapers/qt.rb
@@ -11,7 +11,7 @@ class Qt < UrlScraper
 
     html_filters.push 'qt/entries', 'qt/clean_html'
 
-    options[:container] = '.main'
+    options[:container] = 'article, .main'
     options[:max_image_size] = 156_000
     options[:skip_patterns] = [
       # License, copyright attributions
@@ -103,12 +103,12 @@ class Qt < UrlScraper
       Licensed under the GNU Free Documentation License, Version 1.3.
     HTML
 
-    version '6.8' do
+    version do
       self.release = '6.8'
       self.base_url = "https://doc.qt.io/qt-#{self.release}/"
     end
 
-    version do
+    version '6.2' do
       self.release = '6.2'
       self.base_url = "https://doc.qt.io/qt-#{self.release}/"
     end

From 800d7b23c369a061f0f828200c1da5ba5b3aeaa3 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 11 Apr 2025 19:25:48 +0200
Subject: [PATCH 266/384] Update Crystal documentation (1.16.0)

---
 lib/docs/scrapers/crystal.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index 0ca20ab435..002ff5fac2 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -2,7 +2,7 @@ module Docs
   class Crystal < UrlScraper
     include MultipleBaseUrls
     self.type = 'crystal'
-    self.release = '1.15.1'
+    self.release = '1.16.0'
     self.base_urls = [
       "https://crystal-lang.org/api/#{release}/",
       "https://crystal-lang.org/reference/#{release[0..2]}/",

From f52fd64bfdc7116be091807e9f5f2c5aab5ad86b Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 11 Apr 2025 19:25:58 +0200
Subject: [PATCH 267/384] Update Rust documentation (1.86.0)

---
 lib/docs/scrapers/rust.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/rust.rb b/lib/docs/scrapers/rust.rb
index 1b832d8756..21de1602c1 100644
--- a/lib/docs/scrapers/rust.rb
+++ b/lib/docs/scrapers/rust.rb
@@ -3,7 +3,7 @@
 module Docs
   class Rust < UrlScraper
     self.type = 'rust'
-    self.release = '1.85.0'
+    self.release = '1.86.0'
     self.base_url = 'https://doc.rust-lang.org/'
     self.root_path = 'book/index.html'
     self.initial_paths = %w(

From e99df2452fd2dfb13e4990ee6f1ea606c97d4670 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 11 Apr 2025 19:26:07 +0200
Subject: [PATCH 268/384] Update Zig documentation (0.14.0)

---
 lib/docs/scrapers/zig.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/zig.rb b/lib/docs/scrapers/zig.rb
index 9223b8ca7b..dab1a59d6d 100644
--- a/lib/docs/scrapers/zig.rb
+++ b/lib/docs/scrapers/zig.rb
@@ -2,7 +2,7 @@ module Docs
   class Zig < UrlScraper
     self.name = 'Zig'
     self.type = 'simple'
-    self.release = '0.13.0'
+    self.release = '0.14.0'
     self.base_url = "https://ziglang.org/documentation/#{self.release}/"
     self.links = {
       home: 'https://ziglang.org/',
@@ -13,7 +13,7 @@ class Zig < UrlScraper
 
     options[:follow_links] = false
     options[:attribution] = <<-HTML
-      &copy; 2015–2024, Zig contributors<br>
+      &copy; 2015–2025, Zig contributors<br>
       Licensed under the MIT License.
     HTML
 

From acb98cca7306ef01d2d90aa9c2eb9d925ed5916d Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 11 Apr 2025 19:27:29 +0200
Subject: [PATCH 269/384] Update VueUse documentation (13.1.0)

---
 lib/docs/scrapers/vueuse.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vueuse.rb b/lib/docs/scrapers/vueuse.rb
index d9e6748c69..40956fbb8f 100644
--- a/lib/docs/scrapers/vueuse.rb
+++ b/lib/docs/scrapers/vueuse.rb
@@ -22,7 +22,7 @@ class Vueuse < UrlScraper
       Licensed under the MIT License.
     HTML
 
-    self.release = '12.5.0'
+    self.release = '13.1.0'
     self.base_url = 'https://vueuse.org/'
     self.initial_paths = %w(functions.html)
     html_filters.push 'vueuse/entries', 'vite/clean_html', 'vueuse/clean_html'

From 104d7c8ebcf3849159a4d78a02c446a4eecbcc3f Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 14 Apr 2025 02:27:02 +0000
Subject: [PATCH 270/384] Update ruby/setup-ruby action to v1.230.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 098c3d8efd..2aa7fd6438 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1.229.0
+      uses: ruby/setup-ruby@e5ac7b085f6e63d49c8973eb0c6e04d876b881f1 # v1.230.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 700c47bce6..5df1088c6a 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1.229.0
+      uses: ruby/setup-ruby@e5ac7b085f6e63d49c8973eb0c6e04d876b881f1 # v1.230.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9372adee05..a796d6b4c4 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1.229.0
+      uses: ruby/setup-ruby@e5ac7b085f6e63d49c8973eb0c6e04d876b881f1 # v1.230.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 9be79b6a0025b60ccf1587f9f8fa57756e471ead Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 15 Apr 2025 08:22:35 +0200
Subject: [PATCH 271/384] Update JavaScript documentation

---
 lib/docs/scrapers/mdn/javascript.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/mdn/javascript.rb b/lib/docs/scrapers/mdn/javascript.rb
index 5c9f4d0c1d..28268b8112 100644
--- a/lib/docs/scrapers/mdn/javascript.rb
+++ b/lib/docs/scrapers/mdn/javascript.rb
@@ -3,7 +3,7 @@ class Javascript < Mdn
     prepend FixInternalUrlsBehavior
     prepend FixRedirectionsBehavior
 
-    # release = '2025-01-30'
+    # release = '2025-04-15'
     self.name = 'JavaScript'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference'
     self.links = {

From f6e2f00a4ca205b40f26decb422d87f7d8a687a0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 15 Apr 2025 06:44:18 +0000
Subject: [PATCH 272/384] Update ruby/setup-ruby action to v1.231.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2aa7fd6438..04055a4676 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@e5ac7b085f6e63d49c8973eb0c6e04d876b881f1 # v1.230.0
+      uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 5df1088c6a..42594a5a24 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@e5ac7b085f6e63d49c8973eb0c6e04d876b881f1 # v1.230.0
+      uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a796d6b4c4..edf347f959 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@e5ac7b085f6e63d49c8973eb0c6e04d876b881f1 # v1.230.0
+      uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 75456361359777fd468e54804433d00c88b76b70 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 15 Apr 2025 10:41:04 +0000
Subject: [PATCH 273/384] Update dependency ruby to v3.4.3

---
 .ruby-version     | 2 +-
 .tool-versions    | 2 +-
 Dockerfile        | 2 +-
 Dockerfile-alpine | 2 +-
 Gemfile           | 2 +-
 Gemfile.lock      | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.ruby-version b/.ruby-version
index 4d9d11cf50..6cb9d3dd0d 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.4.2
+3.4.3
diff --git a/.tool-versions b/.tool-versions
index ae5ecdb2b3..a72ead61f3 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1 @@
-ruby 3.4.2
+ruby 3.4.3
diff --git a/Dockerfile b/Dockerfile
index 92c5964260..5a85b1e4eb 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:3.4.2
+FROM ruby:3.4.3
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
 
diff --git a/Dockerfile-alpine b/Dockerfile-alpine
index ce605eaab9..7075f4c508 100644
--- a/Dockerfile-alpine
+++ b/Dockerfile-alpine
@@ -1,4 +1,4 @@
-FROM ruby:3.4.2-alpine
+FROM ruby:3.4.3-alpine
 
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
diff --git a/Gemfile b/Gemfile
index be8dcb0b6c..21c75e07a3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,5 @@
 source 'https://rubygems.org'
-ruby '3.4.2'
+ruby '3.4.3'
 
 gem 'activesupport', require: false
 gem 'html-pipeline'
diff --git a/Gemfile.lock b/Gemfile.lock
index ffeaa732e3..bf4189c3c2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -191,7 +191,7 @@ DEPENDENCIES
   yajl-ruby
 
 RUBY VERSION
-   ruby 3.4.2p28
+   ruby 3.4.3p32
 
 BUNDLED WITH
    2.4.6

From eaa0190849bf4c67c0d4453262e2128acc275308 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 16 Apr 2025 21:03:53 +0200
Subject: [PATCH 274/384] Update Ansible documentation ()

---
 lib/docs/scrapers/ansible.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/ansible.rb b/lib/docs/scrapers/ansible.rb
index 1b1ef95e72..dc39634696 100644
--- a/lib/docs/scrapers/ansible.rb
+++ b/lib/docs/scrapers/ansible.rb
@@ -11,7 +11,7 @@ class Ansible < UrlScraper
 
     options[:attribution] = <<-HTML
       &copy; 2012&ndash;2018 Michael DeHaan<br>
-      &copy; 2018&ndash;2024 Red Hat, Inc.<br>
+      &copy; 2018&ndash;2025 Red Hat, Inc.<br>
       Licensed under the GNU General Public License version 3.
     HTML
 

From b2cc5810f363e876fc3785636cc47fa71299119c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Thu, 17 Apr 2025 09:22:10 +0200
Subject: [PATCH 275/384] Crystal 1.16.1

---
 lib/docs/scrapers/crystal.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index 002ff5fac2..e4a34da8e4 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -2,7 +2,7 @@ module Docs
   class Crystal < UrlScraper
     include MultipleBaseUrls
     self.type = 'crystal'
-    self.release = '1.16.0'
+    self.release = '1.16.1'
     self.base_urls = [
       "https://crystal-lang.org/api/#{release}/",
       "https://crystal-lang.org/reference/#{release[0..2]}/",

From 585a1200ae89dd35fcc7af9d0d4c40367e449a51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Thu, 17 Apr 2025 09:24:22 +0200
Subject: [PATCH 276/384] Update Crystal's skip_patterns

---
 lib/docs/scrapers/crystal.rb | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index e4a34da8e4..92bd4bcf29 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -20,8 +20,10 @@ def initial_urls
     html_filters.push 'crystal/entries', 'crystal/clean_html'
 
     options[:skip_patterns] = [
-      %r{\ACrystal/System/},
+      %r{\ALibLLVM\.html\z},
+      %r{\ACrystal/System(/|\.html\z)},
       %r{\ACrystal/PointerPairingHeap/},
+      %r{\AFiber/ExecutionContext/Scheduler.html\z},
       %r{\AIO/Evented.html\z},
       %r{\ARegex/PCRE2.html\z}
     ]

From 0613c53761fce9c50b8cfd3cd967a730ced08a74 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 17 Apr 2025 16:07:25 +0000
Subject: [PATCH 277/384] Update ruby/setup-ruby action to v1.232.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 04055a4676..91a06a5c3e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
+      uses: ruby/setup-ruby@fb404b9557c186e349162b0d8efb06e2bc36edea # v1.232.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 42594a5a24..e734b2b75c 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
+      uses: ruby/setup-ruby@fb404b9557c186e349162b0d8efb06e2bc36edea # v1.232.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index edf347f959..6df87a4625 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
+      uses: ruby/setup-ruby@fb404b9557c186e349162b0d8efb06e2bc36edea # v1.232.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 58f63fd17256385ca210b79e307e754f185752c6 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 18 Apr 2025 09:39:49 +0000
Subject: [PATCH 278/384] Update ruby/setup-ruby action to v1.233.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 91a06a5c3e..a6ebae7afd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@fb404b9557c186e349162b0d8efb06e2bc36edea # v1.232.0
+      uses: ruby/setup-ruby@ca041f971d66735f3e5ff1e21cc13e2d51e7e535 # v1.233.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index e734b2b75c..ae6df74ce4 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@fb404b9557c186e349162b0d8efb06e2bc36edea # v1.232.0
+      uses: ruby/setup-ruby@ca041f971d66735f3e5ff1e21cc13e2d51e7e535 # v1.233.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6df87a4625..45b6d00a9f 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@fb404b9557c186e349162b0d8efb06e2bc36edea # v1.232.0
+      uses: ruby/setup-ruby@ca041f971d66735f3e5ff1e21cc13e2d51e7e535 # v1.233.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 7dbf01e5a311b71e3064e33747ca6c3b93444164 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 20 Apr 2025 09:31:47 +0200
Subject: [PATCH 279/384] Update ESLint documentation (9.25.0)

---
 lib/docs/scrapers/eslint.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/eslint.rb b/lib/docs/scrapers/eslint.rb
index e3243171df..af71cf4a8d 100644
--- a/lib/docs/scrapers/eslint.rb
+++ b/lib/docs/scrapers/eslint.rb
@@ -2,7 +2,7 @@ module Docs
   class Eslint < UrlScraper
     self.name = 'ESLint'
     self.type = 'simple'
-    self.release = '9.15.0'
+    self.release = '9.25.0'
     self.base_url = 'https://eslint.org/docs/latest/'
     self.root_path = '/'
     self.links = {

From 7968e21ccb708b7ea5742cdd9f8d8a5f1563272b Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 20 Apr 2025 09:32:33 +0200
Subject: [PATCH 280/384] Update Vite documentation (6.3.2)

---
 lib/docs/scrapers/vite.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vite.rb b/lib/docs/scrapers/vite.rb
index 4b2fa6132d..ee26d8b9c6 100644
--- a/lib/docs/scrapers/vite.rb
+++ b/lib/docs/scrapers/vite.rb
@@ -22,7 +22,7 @@ class Vite < UrlScraper
     html_filters.push 'vite/entries', 'vite/clean_html'
 
     version do
-      self.release = '6.2.2'
+      self.release = '6.3.2'
       self.base_url = 'https://vite.dev/'
     end
 

From 3425d270f331d050f38ff93ee66ed7a5a391493b Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 20 Apr 2025 09:33:45 +0200
Subject: [PATCH 281/384] Update Playwright documentation (1.52.0)

---
 lib/docs/scrapers/playwright.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/playwright.rb b/lib/docs/scrapers/playwright.rb
index b594a78fcb..57f908a4b2 100644
--- a/lib/docs/scrapers/playwright.rb
+++ b/lib/docs/scrapers/playwright.rb
@@ -2,7 +2,7 @@ module Docs
   class Playwright < UrlScraper
     self.name = 'Playwright'
     self.type = 'simple'
-    self.release = '1.51.0'
+    self.release = '1.52.0'
     self.base_url = 'https://playwright.dev/docs/'
     self.root_path = 'intro'
     self.links = {

From 305fb69614fca5a5ab364f1f9c5bbb1ba9478be9 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 20 Apr 2025 09:54:34 +0200
Subject: [PATCH 282/384] GitHub Actions: use Ubuntu 24.04

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a6ebae7afd..5d00cba3f5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,7 +8,7 @@ on:
 jobs:
   deploy:
     name: Deploy to Heroku
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     if: github.repository == 'freeCodeCamp/devdocs'
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index ae6df74ce4..b1fe097074 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -6,7 +6,7 @@ on:
 
 jobs:
   report:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-24.04
     if: github.repository == 'freeCodeCamp/devdocs'
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0

From ac2c582d3c6c636a8f0e3a3574a2c119e0f2039b Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 20 Apr 2025 10:09:49 +0200
Subject: [PATCH 283/384] GitHub Actions: install Heroku CLI

https://github.com/AkhileshNS/heroku-deploy
---
 .github/workflows/build.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5d00cba3f5..2e9a35ef14 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -18,6 +18,9 @@ jobs:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
       run: bundle exec rake
+    - name: Install Heroku CLI
+      run: |
+        curl https://cli-assets.heroku.com/install.sh | sh
     - name: Deploy to Heroku
       uses: akhileshns/heroku-deploy@e3eb99d45a8e2ec5dca08735e089607befa4bf28 # v3.14.15
       with:

From 16b74845701998a6bfcaa4cdb7a5378c3c706fa8 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 21 Apr 2025 19:43:08 +0000
Subject: [PATCH 284/384] Update dependency nokogiri to v1.18.8

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index bf4189c3c2..49e8c8f4ac 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -63,7 +63,7 @@ GEM
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.7)
+    nokogiri (1.18.8)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From e406f1f3014658c9c962f182762b5cbf15f486d5 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 24 Apr 2025 23:57:43 +0000
Subject: [PATCH 285/384] Update ruby/setup-ruby action to v1.234.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2e9a35ef14..946e2af382 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@ca041f971d66735f3e5ff1e21cc13e2d51e7e535 # v1.233.0
+      uses: ruby/setup-ruby@2e007403fc1ec238429ecaa57af6f22f019cc135 # v1.234.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index b1fe097074..9a652a6e4a 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@ca041f971d66735f3e5ff1e21cc13e2d51e7e535 # v1.233.0
+      uses: ruby/setup-ruby@2e007403fc1ec238429ecaa57af6f22f019cc135 # v1.234.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 45b6d00a9f..31cc7fa097 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@ca041f971d66735f3e5ff1e21cc13e2d51e7e535 # v1.233.0
+      uses: ruby/setup-ruby@2e007403fc1ec238429ecaa57af6f22f019cc135 # v1.234.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 30b83cf55c899bce7dcd54b5373add10c12257aa Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 26 Apr 2025 13:53:59 +0000
Subject: [PATCH 286/384] Update ruby/setup-ruby action to v1.235.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 946e2af382..83ed06da6d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2e007403fc1ec238429ecaa57af6f22f019cc135 # v1.234.0
+      uses: ruby/setup-ruby@dffc446db9ba5a0c4446edb5bca1c5c473a806c5 # v1.235.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 9a652a6e4a..dcaaa8c45f 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2e007403fc1ec238429ecaa57af6f22f019cc135 # v1.234.0
+      uses: ruby/setup-ruby@dffc446db9ba5a0c4446edb5bca1c5c473a806c5 # v1.235.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 31cc7fa097..4de3dd9c90 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@2e007403fc1ec238429ecaa57af6f22f019cc135 # v1.234.0
+      uses: ruby/setup-ruby@dffc446db9ba5a0c4446edb5bca1c5c473a806c5 # v1.235.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 8ae3459aaf59c0f3023d17e83b3d0c7d7b341636 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 23:26:25 +0000
Subject: [PATCH 287/384] Update ruby/setup-ruby action to v1.236.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 83ed06da6d..449bffd5a5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@dffc446db9ba5a0c4446edb5bca1c5c473a806c5 # v1.235.0
+      uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index dcaaa8c45f..567b595b9a 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@dffc446db9ba5a0c4446edb5bca1c5c473a806c5 # v1.235.0
+      uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4de3dd9c90..0a5d1b0885 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@dffc446db9ba5a0c4446edb5bca1c5c473a806c5 # v1.235.0
+      uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 545ccdace6a58b112e1234ae29d9b0d9f1935d22 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 1 May 2025 14:49:26 +0000
Subject: [PATCH 288/384] Update ruby/setup-ruby action to v1.237.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 449bffd5a5..de9243bf62 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0
+      uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 567b595b9a..8bb9246f39 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0
+      uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 0a5d1b0885..c8b1d9e9c0 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0
+      uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 14d8d3cf9b48f411b88bb039ed0fffa533c2bca9 Mon Sep 17 00:00:00 2001
From: Emmanuel Touzery <etouzery@gmail.com>
Date: Fri, 2 May 2025 08:43:26 +0200
Subject: [PATCH 289/384] switch neovim plugin link to a newer maintained
 plugin

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index f4c733d81c..d4f45f2480 100644
--- a/README.md
+++ b/README.md
@@ -188,7 +188,7 @@ Made something cool? Feel free to open a PR to add a new row to this table! You
 | [girishji/devdocs.vim](https://github.com/girishji/devdocs.vim)                               | Vim plugin & TUI (browse inside Vim)                           | ![Latest GitHub commit](https://img.shields.io/github/last-commit/girishji/devdocs.vim?logo=github&label)             | ![GitHub stars](https://img.shields.io/github/stars/girishji/devdocs.vim?logo=github&label)             |
 | [romainl/vim-devdocs](https://github.com/romainl/vim-devdocs)                               | Vim plugin                           | ![Latest GitHub commit](https://img.shields.io/github/last-commit/romainl/vim-devdocs?logo=github&label)             | ![GitHub stars](https://img.shields.io/github/stars/romainl/vim-devdocs?logo=github&label)             |
 | [waiting-for-dev/vim-www](https://github.com/waiting-for-dev/vim-www)                       | Vim plugin                           | ![Latest GitHub commit](https://img.shields.io/github/last-commit/waiting-for-dev/vim-www?logo=github&label)         | ![GitHub stars](https://img.shields.io/github/stars/waiting-for-dev/vim-www?logo=github&label)         |
-| [luckasRanarison/nvim-devdocs](https://github.com/luckasRanarison/nvim-devdocs)             | Neovim plugin                        | ![Latest GitHub commit](https://img.shields.io/github/last-commit/luckasRanarison/nvim-devdocs?logo=github&label)    | ![GitHub stars](https://img.shields.io/github/stars/luckasRanarison/nvim-devdocs?logo=github&label)    |
+| [emmanueltouzery/apidocs.nvim](https://github.com/emmanueltouzery/apidocs.nvim)             | Neovim plugin                        | ![Latest GitHub commit](https://img.shields.io/github/last-commit/emmanueltouzery/apidocs.nvim?logo=github&label)    | ![GitHub stars](https://img.shields.io/github/stars/emmanueltouzery/apidocs.nvim?logo=github&label)    |
 | [toiletbril/dedoc](https://github.com/toiletbril/dedoc)                                     | Terminal based viewer                | ![Latest GitHub commit](https://img.shields.io/github/last-commit/toiletbril/dedoc?logo=github&label)                | ![GitHub stars](https://img.shields.io/github/stars/toiletbril/dedoc?logo=github&label)                |
 | [Raycast Devdocs](https://www.raycast.com/djpowers/devdocs)                                 | Raycast extension                    | Unavailable                 | Unavailable                |
 | [chrisgrieser/alfred-docs-searches](https://github.com/chrisgrieser/alfred-docs-searches)   | Alfred workflow                      | ![Latest GitHub commit](https://img.shields.io/github/last-commit/chrisgrieser/alfred-docs-searches?logo=github&label) | ![GitHub stars](https://img.shields.io/github/stars/chrisgrieser/alfred-docs-searches?logo=github&label) |

From 51967567edc3716f0485cc955471d46a2f3a89d4 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 6 May 2025 22:37:19 +0000
Subject: [PATCH 290/384] Update dependency rack to v2.2.14

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 49e8c8f4ac..a80e6f6103 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -78,7 +78,7 @@ GEM
       byebug (~> 12.0)
       pry (>= 0.13, < 0.16)
     racc (1.8.1)
-    rack (2.2.13)
+    rack (2.2.14)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)

From a8214b3711d4becfa009ee1511be13a9ca984588 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 8 May 2025 15:28:22 +0000
Subject: [PATCH 291/384] Update ruby/setup-ruby action to v1.238.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index de9243bf62..072f224f1f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0
+      uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 8bb9246f39..a59c5ea3af 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0
+      uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c8b1d9e9c0..7701208c06 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0
+      uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 78dc05494d9136a0053c33820d16d49cc550dd7f Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 14 May 2025 22:23:49 +0000
Subject: [PATCH 292/384] Update ruby/setup-ruby action to v1.239.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 072f224f1f..ab3a2ef32a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
+      uses: ruby/setup-ruby@84684c07c1965536eb4802c8daf1a77968df0cb1 # v1.239.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index a59c5ea3af..6146884b35 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
+      uses: ruby/setup-ruby@84684c07c1965536eb4802c8daf1a77968df0cb1 # v1.239.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 7701208c06..e58bce0b96 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
+      uses: ruby/setup-ruby@84684c07c1965536eb4802c8daf1a77968df0cb1 # v1.239.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From c0f79d6826acb825c6e0beca33d0914343a49c37 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 15 May 2025 03:38:44 +0000
Subject: [PATCH 293/384] Update dependency ruby to v3.4.4

---
 .ruby-version  | 2 +-
 .tool-versions | 2 +-
 Gemfile        | 2 +-
 Gemfile.lock   | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.ruby-version b/.ruby-version
index 6cb9d3dd0d..f9892605c7 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.4.3
+3.4.4
diff --git a/.tool-versions b/.tool-versions
index a72ead61f3..ca745c6d6d 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1 @@
-ruby 3.4.3
+ruby 3.4.4
diff --git a/Gemfile b/Gemfile
index 21c75e07a3..cbe55ccf8a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,5 @@
 source 'https://rubygems.org'
-ruby '3.4.3'
+ruby '3.4.4'
 
 gem 'activesupport', require: false
 gem 'html-pipeline'
diff --git a/Gemfile.lock b/Gemfile.lock
index a80e6f6103..d5b5392d7f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -191,7 +191,7 @@ DEPENDENCIES
   yajl-ruby
 
 RUBY VERSION
-   ruby 3.4.3p32
+   ruby 3.4.4p34
 
 BUNDLED WITH
    2.4.6

From eece649f0816bbe91795958de690028f0611ab06 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 16 May 2025 07:19:05 +0000
Subject: [PATCH 294/384] Update ruby Docker tag to v3.4.4

---
 Dockerfile        | 2 +-
 Dockerfile-alpine | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 5a85b1e4eb..2d8a9fee8a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:3.4.3
+FROM ruby:3.4.4
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
 
diff --git a/Dockerfile-alpine b/Dockerfile-alpine
index 7075f4c508..6af65c2eb5 100644
--- a/Dockerfile-alpine
+++ b/Dockerfile-alpine
@@ -1,4 +1,4 @@
-FROM ruby:3.4.3-alpine
+FROM ruby:3.4.4-alpine
 
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true

From b35dc57a65d650800697ca3ffff9a2c1deed0a8e Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 16 May 2025 16:04:12 +0000
Subject: [PATCH 295/384] Update ruby/setup-ruby action to v1.240.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ab3a2ef32a..2577808724 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@84684c07c1965536eb4802c8daf1a77968df0cb1 # v1.239.0
+      uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 6146884b35..08c9c95b31 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@84684c07c1965536eb4802c8daf1a77968df0cb1 # v1.239.0
+      uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e58bce0b96..005081f63d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@84684c07c1965536eb4802c8daf1a77968df0cb1 # v1.239.0
+      uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 0fde144e7a07522a124bf07d00041cb3c4cbc782 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 16 May 2025 23:45:14 +0000
Subject: [PATCH 296/384] Update ruby/setup-ruby action to v1.241.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2577808724..14018c3243 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
+      uses: ruby/setup-ruby@bb0f760b6c925183520ee0bcc9c4a432a7c8c3c6 # v1.241.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 08c9c95b31..e31c90ea70 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
+      uses: ruby/setup-ruby@bb0f760b6c925183520ee0bcc9c4a432a7c8c3c6 # v1.241.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 005081f63d..bf0f564d9a 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
+      uses: ruby/setup-ruby@bb0f760b6c925183520ee0bcc9c4a432a7c8c3c6 # v1.241.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From ade1961b723f012308ce924c404c42fc1ea21fdd Mon Sep 17 00:00:00 2001
From: dorimon <dorsahar4420@gmail.com>
Date: Sat, 17 May 2025 17:32:36 +0300
Subject: [PATCH 297/384] Add vertx docs

---
 lib/docs/filters/vertx/clean_html.rb |  40 +++++++++++++++++++++++++
 lib/docs/filters/vertx/entries.rb    |  43 +++++++++++++++++++++++++++
 lib/docs/scrapers/vertx.rb           |  25 ++++++++++++++++
 public/icons/docs/vertx/16.png       | Bin 0 -> 855 bytes
 public/icons/docs/vertx/16@2x.png    | Bin 0 -> 2081 bytes
 5 files changed, 108 insertions(+)
 create mode 100644 lib/docs/filters/vertx/clean_html.rb
 create mode 100644 lib/docs/filters/vertx/entries.rb
 create mode 100644 lib/docs/scrapers/vertx.rb
 create mode 100644 public/icons/docs/vertx/16.png
 create mode 100644 public/icons/docs/vertx/16@2x.png

diff --git a/lib/docs/filters/vertx/clean_html.rb b/lib/docs/filters/vertx/clean_html.rb
new file mode 100644
index 0000000000..c52dde05bc
--- /dev/null
+++ b/lib/docs/filters/vertx/clean_html.rb
@@ -0,0 +1,40 @@
+module Docs
+  class Vertx
+    class CleanHtmlFilter < Filter
+      def call
+        css('hr', 'header', 'nav', '.navbar', '.topbar').remove
+        xpath('//*[@id="docs-layout"]/div/div[3]').remove
+        xpath('//*[@id="docs-layout"]/div/div[1]').remove
+        xpath('//main/div[last()]').remove
+        xpath('//main/div[1]').remove
+        xpath('//footer').remove
+        css('#changelog').remove if root_page?
+
+        # Set id attributes on <h3> instead of an empty <a>
+        css('h3').each do |node|
+          anchor = node.at_css('a')
+          node['id'] = anchor['id'] if anchor && anchor['id']
+        end
+
+        # Make proper table headers
+        css('td.header').each do |node|
+          node.name = 'th'
+        end
+
+        # Remove code highlighting
+        css('pre').each do |node|
+          node.content = node.content
+        end
+
+        # ❗ Skip <img> tags with data: URIs
+        css('img').each do |img|
+          src = img['src']
+          img.remove if src&.start_with?('data:')
+        end
+
+        doc
+      end
+    end
+  end
+end
+
diff --git a/lib/docs/filters/vertx/entries.rb b/lib/docs/filters/vertx/entries.rb
new file mode 100644
index 0000000000..22478c4f3a
--- /dev/null
+++ b/lib/docs/filters/vertx/entries.rb
@@ -0,0 +1,43 @@
+module Docs
+  class Vertx
+    class EntriesFilter < Docs::EntriesFilter
+      # Determines the default name of the page entry
+      def get_name
+        node = at_css('h1')
+        return nil unless node
+
+        result = node.content.strip
+        result = "v5.0.0 - #{result}" if slug.include?('5.0.0')
+        result << ' event' if type == 'Events'
+        result << '()' if node['class'].to_s.include?('function')
+        result
+      end
+
+      # Determines the type of the default entry (used for sidebar grouping)
+      def get_type
+        return nil if root_page?
+
+        node = at_xpath('/html/body/div/div/div[2]/main/div[1]/div[1]')
+        node ? node.text.strip : 'Miscellaneous'
+      end
+
+      # Returns additional entries from subheadings (usually <h2>)
+      def additional_entries
+        # return [] if root_page?
+        #
+        # css('h2').map do |node|
+        #   name = node.content.strip
+        #   id = node['id']
+        #   [name, id, type]
+        # end
+        []
+      end
+
+      # Determines whether to include the default entry for the page
+      def include_default_entry?
+        !at_css('.obsolete')
+      end
+    end
+  end
+end
+
diff --git a/lib/docs/scrapers/vertx.rb b/lib/docs/scrapers/vertx.rb
new file mode 100644
index 0000000000..be7cd658d8
--- /dev/null
+++ b/lib/docs/scrapers/vertx.rb
@@ -0,0 +1,25 @@
+
+module Docs
+  class Vertx < UrlScraper
+    self.type = 'vertx'
+    self.links = {
+      home: 'http://vertx.io',
+      code: 'https://github.com/eclipse-vertx/vert.x'
+    }
+
+    html_filters.push 'vertx/entries', 'vertx/clean_html'
+
+    self.base_url = 'https://vertx.io/'
+    self.root_path = 'docs'
+    options[:attribution] = <<-HTML
+      by Dor Sahar :)
+    HTML
+
+    options[:skip_patterns] = [
+      /api/,
+      /apidocs/,
+      /blog/,
+    ]
+
+  end
+end
diff --git a/public/icons/docs/vertx/16.png b/public/icons/docs/vertx/16.png
new file mode 100644
index 0000000000000000000000000000000000000000..75de4cd51409bc2fde974ef571233cd1bbecb4d3
GIT binary patch
diff --git a/public/icons/docs/vertx/16@2x.png b/public/icons/docs/vertx/16@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..e7510a59c903861fb2f70a1c150338055e80b8c8
GIT binary patch

From bb8dcec4cf2f28e78405ddcb8465dc24b98f5bfd Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 18 May 2025 05:47:45 +0000
Subject: [PATCH 298/384] Update dependency rack to v2.2.15

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index d5b5392d7f..fd8600d9ef 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -78,7 +78,7 @@ GEM
       byebug (~> 12.0)
       pry (>= 0.13, < 0.16)
     racc (1.8.1)
-    rack (2.2.14)
+    rack (2.2.15)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)

From 42c87bdd177a45be63ec8f8a16e4fbf60f00d6a3 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 18 May 2025 21:38:55 +0200
Subject: [PATCH 299/384] Update Leaflet documentation (2.0.0-alpha)

---
 lib/docs/scrapers/leaflet.rb | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/leaflet.rb b/lib/docs/scrapers/leaflet.rb
index a3e5e50242..dbe0c227b0 100644
--- a/lib/docs/scrapers/leaflet.rb
+++ b/lib/docs/scrapers/leaflet.rb
@@ -14,11 +14,16 @@ class Leaflet < UrlScraper
     options[:skip_links] = true
 
     options[:attribution] = <<-HTML
-      &copy; 2010&ndash;2022 Vladimir Agafonkin<br>
+      &copy; 2010&ndash;2025 Vladimir Agafonkin<br>
       &copy; 2010&ndash;2011, CloudMade<br>
       Maps &copy; OpenStreetMap contributors.
     HTML
 
+    version '2.0' do
+      self.release = '2.0.0-alpha'
+      self.base_url = "https://leafletjs.com/reference-2.0.0.html"
+    end
+
     version '1.9' do
       self.release = '1.9.4'
       self.base_url = "https://leafletjs.com/reference.html"

From 5a091022ac710f4cb546966a5c5da74e400e08ef Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 18 May 2025 22:12:06 +0000
Subject: [PATCH 300/384] Update ruby/setup-ruby action to v1.242.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 14018c3243..c49801ba96 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bb0f760b6c925183520ee0bcc9c4a432a7c8c3c6 # v1.241.0
+      uses: ruby/setup-ruby@cb0fda56a307b8c78d38320cd40d9eb22a3bf04e # v1.242.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index e31c90ea70..1d4ee9febd 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bb0f760b6c925183520ee0bcc9c4a432a7c8c3c6 # v1.241.0
+      uses: ruby/setup-ruby@cb0fda56a307b8c78d38320cd40d9eb22a3bf04e # v1.242.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index bf0f564d9a..738bfb062d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bb0f760b6c925183520ee0bcc9c4a432a7c8c3c6 # v1.241.0
+      uses: ruby/setup-ruby@cb0fda56a307b8c78d38320cd40d9eb22a3bf04e # v1.242.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 19696fb368ef91d25374be44fe55c1dc362446e4 Mon Sep 17 00:00:00 2001
From: dorimon <dorsahar4420@gmail.com>
Date: Mon, 19 May 2025 18:59:45 +0300
Subject: [PATCH 301/384] Add version support

Remove wierd files
---
 lib/docs/filters/vertx/clean_html.rb |  3 +--
 lib/docs/filters/vertx/entries.rb    |  1 -
 lib/docs/scrapers/vertx.rb           | 18 +++++++++++++++---
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/lib/docs/filters/vertx/clean_html.rb b/lib/docs/filters/vertx/clean_html.rb
index c52dde05bc..ba488f0cab 100644
--- a/lib/docs/filters/vertx/clean_html.rb
+++ b/lib/docs/filters/vertx/clean_html.rb
@@ -2,12 +2,11 @@ module Docs
   class Vertx
     class CleanHtmlFilter < Filter
       def call
-        css('hr', 'header', 'nav', '.navbar', '.topbar').remove
+        css('footer', 'hr', 'header', 'nav', '.navbar', '.topbar', '.bg-bg-warning').remove
         xpath('//*[@id="docs-layout"]/div/div[3]').remove
         xpath('//*[@id="docs-layout"]/div/div[1]').remove
         xpath('//main/div[last()]').remove
         xpath('//main/div[1]').remove
-        xpath('//footer').remove
         css('#changelog').remove if root_page?
 
         # Set id attributes on <h3> instead of an empty <a>
diff --git a/lib/docs/filters/vertx/entries.rb b/lib/docs/filters/vertx/entries.rb
index 22478c4f3a..8155c5d888 100644
--- a/lib/docs/filters/vertx/entries.rb
+++ b/lib/docs/filters/vertx/entries.rb
@@ -7,7 +7,6 @@ def get_name
         return nil unless node
 
         result = node.content.strip
-        result = "v5.0.0 - #{result}" if slug.include?('5.0.0')
         result << ' event' if type == 'Events'
         result << '()' if node['class'].to_s.include?('function')
         result
diff --git a/lib/docs/scrapers/vertx.rb b/lib/docs/scrapers/vertx.rb
index be7cd658d8..5a19a7d87a 100644
--- a/lib/docs/scrapers/vertx.rb
+++ b/lib/docs/scrapers/vertx.rb
@@ -1,4 +1,3 @@
-
 module Docs
   class Vertx < UrlScraper
     self.type = 'vertx'
@@ -9,17 +8,30 @@ class Vertx < UrlScraper
 
     html_filters.push 'vertx/entries', 'vertx/clean_html'
 
-    self.base_url = 'https://vertx.io/'
-    self.root_path = 'docs'
     options[:attribution] = <<-HTML
       by Dor Sahar :)
     HTML
 
     options[:skip_patterns] = [
       /api/,
+      /5.0.0/,
       /apidocs/,
       /blog/,
     ]
 
+    version '5.0.0' do
+      self.release = '5.0.0'
+      self.base_url = "https://vertx.io/docs/"
+    end
+
+    version '4.5.15' do
+      self.release = '4.5.15'
+      self.base_url = "https://vertx.io/docs/#{self.version}"
+    end
+
+    version '3.9.16' do
+      self.release = '4.5.15'
+      self.base_url = "https://vertx.io/docs/#{self.version}"
+    end
   end
 end

From 01aca6cccc1963c24dfcb4e644be612ad95120bb Mon Sep 17 00:00:00 2001
From: dorimon <dorsahar4420@gmail.com>
Date: Mon, 19 May 2025 19:09:51 +0300
Subject: [PATCH 302/384] Add SOURCE for icon and credis

---
 lib/docs/scrapers/vertx.rb     | 4 +++-
 public/icons/docs/vertx/SOURCE | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)
 create mode 100644 public/icons/docs/vertx/SOURCE

diff --git a/lib/docs/scrapers/vertx.rb b/lib/docs/scrapers/vertx.rb
index 5a19a7d87a..5986720293 100644
--- a/lib/docs/scrapers/vertx.rb
+++ b/lib/docs/scrapers/vertx.rb
@@ -9,7 +9,9 @@ class Vertx < UrlScraper
     html_filters.push 'vertx/entries', 'vertx/clean_html'
 
     options[:attribution] = <<-HTML
-      by Dor Sahar :)
+      © 2025 Eclipse Vert.x™</br>
+      Eclipse Vert.x™ is open source and dual-licensed under the Eclipse Public License 2.0 and the Apache License 2.0.</br>
+      Website design by Michel Krämer.
     HTML
 
     options[:skip_patterns] = [
diff --git a/public/icons/docs/vertx/SOURCE b/public/icons/docs/vertx/SOURCE
new file mode 100644
index 0000000000..81ae591749
--- /dev/null
+++ b/public/icons/docs/vertx/SOURCE
@@ -0,0 +1 @@
+https://avatars.githubusercontent.com/u/8124623?s=200&v=4

From 03454d6573709f66528f8e0dc3e4c81f6a1e83d8 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 19 May 2025 20:37:22 +0000
Subject: [PATCH 303/384] Update ruby/setup-ruby action to v1.243.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c49801ba96..f22e74bc13 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@cb0fda56a307b8c78d38320cd40d9eb22a3bf04e # v1.242.0
+      uses: ruby/setup-ruby@c95ae3725f6ebdd095f2bd19caed7ebc14435ba5 # v1.243.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 1d4ee9febd..d16b89dce2 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@cb0fda56a307b8c78d38320cd40d9eb22a3bf04e # v1.242.0
+      uses: ruby/setup-ruby@c95ae3725f6ebdd095f2bd19caed7ebc14435ba5 # v1.243.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 738bfb062d..554cfe2982 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@cb0fda56a307b8c78d38320cd40d9eb22a3bf04e # v1.242.0
+      uses: ruby/setup-ruby@c95ae3725f6ebdd095f2bd19caed7ebc14435ba5 # v1.243.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 84ae0b91cc40afed62ed1145c0e950dbc57beaea Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 21 May 2025 11:48:31 +0000
Subject: [PATCH 304/384] Update ruby/setup-ruby action to v1.244.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f22e74bc13..c9d4ed4fba 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@c95ae3725f6ebdd095f2bd19caed7ebc14435ba5 # v1.243.0
+      uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index d16b89dce2..471f54cd9e 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@c95ae3725f6ebdd095f2bd19caed7ebc14435ba5 # v1.243.0
+      uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 554cfe2982..6e7d36baff 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@c95ae3725f6ebdd095f2bd19caed7ebc14435ba5 # v1.243.0
+      uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From ee318ec06135367d72d2d38cfd671fe5c1aa6176 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 22 May 2025 07:01:02 +0000
Subject: [PATCH 305/384] Update dependency rack to v2.2.16

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index fd8600d9ef..fee98e847c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -78,7 +78,7 @@ GEM
       byebug (~> 12.0)
       pry (>= 0.13, < 0.16)
     racc (1.8.1)
-    rack (2.2.15)
+    rack (2.2.16)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)

From e6d8941486c445952da8eb21f753118f501b9c84 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 28 May 2025 20:56:41 +0200
Subject: [PATCH 306/384] Update Vert.x documentation

---
 assets/javascripts/news.json         |  4 ++++
 lib/docs/filters/vertx/clean_html.rb |  1 +
 lib/docs/scrapers/vertx.rb           | 19 +++++++++++++------
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index b6c061b01e..3ddc39a516 100644
--- a/assets/javascripts/news.json
+++ b/assets/javascripts/news.json
@@ -1,4 +1,8 @@
 [
+  [
+    "2025-05-28",
+    "New documentation: <a href=\"/vertx/\">Vert.x</a>"
+  ],
   [
     "2025-02-23",
     "New documentation: <a href=\"/threejs/\">Three.js</a>"
diff --git a/lib/docs/filters/vertx/clean_html.rb b/lib/docs/filters/vertx/clean_html.rb
index ba488f0cab..786383f6a4 100644
--- a/lib/docs/filters/vertx/clean_html.rb
+++ b/lib/docs/filters/vertx/clean_html.rb
@@ -22,6 +22,7 @@ def call
 
         # Remove code highlighting
         css('pre').each do |node|
+          node['data-language'] = node.at_css('code')['data-lang'] if node.at_css('code')
           node.content = node.content
         end
 
diff --git a/lib/docs/scrapers/vertx.rb b/lib/docs/scrapers/vertx.rb
index 5986720293..8163098087 100644
--- a/lib/docs/scrapers/vertx.rb
+++ b/lib/docs/scrapers/vertx.rb
@@ -1,5 +1,7 @@
 module Docs
   class Vertx < UrlScraper
+    self.name = 'Vert.x'
+    self.slug = 'vertx'
     self.type = 'vertx'
     self.links = {
       home: 'http://vertx.io',
@@ -21,19 +23,24 @@ class Vertx < UrlScraper
       /blog/,
     ]
 
-    version '5.0.0' do
+    version '5' do
       self.release = '5.0.0'
       self.base_url = "https://vertx.io/docs/"
     end
 
-    version '4.5.15' do
+    version '4' do
       self.release = '4.5.15'
-      self.base_url = "https://vertx.io/docs/#{self.version}"
+      self.base_url = "https://vertx.io/docs/#{self.release}"
     end
 
-    version '3.9.16' do
-      self.release = '4.5.15'
-      self.base_url = "https://vertx.io/docs/#{self.version}"
+    version '3' do
+      self.release = '3.9.16'
+      self.base_url = "https://vertx.io/docs/#{self.release}"
+    end
+
+    def get_latest_version(opts)
+      doc = fetch_doc('https://repo1.maven.org/maven2/io/vertx/vertx-stack-manager/maven-metadata.xml', opts)
+      doc.css('version')[-1].text
     end
   end
 end

From 739b6242b1b955c7df2419f240bd3592b01244e0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 30 May 2025 11:23:18 +0000
Subject: [PATCH 307/384] Update dependency rake to v13.3.0

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index fee98e847c..65d0c358e9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -85,7 +85,7 @@ GEM
     rack-ssl-enforcer (0.2.9)
     rack-test (2.2.0)
       rack (>= 1.3)
-    rake (13.2.1)
+    rake (13.3.0)
     rb-fsevent (0.11.2)
     rb-inotify (0.10.1)
       ffi (~> 1.0)

From 3794bf6f550cddede068f9f5abf541aa411db2c6 Mon Sep 17 00:00:00 2001
From: spamguy <spamguy@spamguy.org>
Date: Thu, 29 May 2025 11:50:19 -0700
Subject: [PATCH 308/384] Change where GitHub scraper gets its JSON. Fix Koa,
 Q, Sanctuary, and Lua/nginx imports

---
 lib/docs/filters/github/clean_html.rb                |  5 +++++
 lib/docs/filters/nginx_lua_module/entries.rb         |  4 ++--
 lib/docs/filters/sanctuary_def/entries.rb            |  4 +++-
 .../filters/sanctuary_type_classes/clean_html.rb     |  5 -----
 lib/docs/filters/sanctuary_type_classes/entries.rb   |  4 ++--
 lib/docs/scrapers/github.rb                          |  8 +++++++-
 lib/docs/scrapers/koa.rb                             |  4 ++--
 lib/docs/scrapers/nginx_lua_module.rb                | 12 +++++++-----
 lib/docs/scrapers/q.rb                               |  4 ++--
 9 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/lib/docs/filters/github/clean_html.rb b/lib/docs/filters/github/clean_html.rb
index 4d6da24027..a97f2c3a12 100644
--- a/lib/docs/filters/github/clean_html.rb
+++ b/lib/docs/filters/github/clean_html.rb
@@ -2,6 +2,11 @@ module Docs
   class Github
     class CleanHtmlFilter < Filter
       def call
+        # Remove h1 wrapper to render it correctly.
+        css('.markdown-heading h1').each do |node|
+          node.parent.replace(node)
+        end
+
         css('.anchor').each do |node|
           node.parent['id'] = node['href'].remove('#')
           node.remove
diff --git a/lib/docs/filters/nginx_lua_module/entries.rb b/lib/docs/filters/nginx_lua_module/entries.rb
index e4b1285658..70094b9213 100644
--- a/lib/docs/filters/nginx_lua_module/entries.rb
+++ b/lib/docs/filters/nginx_lua_module/entries.rb
@@ -4,11 +4,11 @@ class EntriesFilter < Docs::EntriesFilter
       def additional_entries
         entries = []
 
-        css('#directives + ul > li > a').each do |node|
+        css('h2:contains("Directives") + ul > li > a').each do |node|
           entries << [node.content, node['href'].remove('#'), 'Directives']
         end
 
-        css('#nginx-api-for-lua + ul > li > a').each do |node|
+        css('h2:contains("Nginx API for Lua") + ul > li > a').each do |node|
           next if node.content == 'Introduction'
           entries << [node.content, node['href'].remove('#'), 'Nginx API for Lua']
         end
diff --git a/lib/docs/filters/sanctuary_def/entries.rb b/lib/docs/filters/sanctuary_def/entries.rb
index 5226be07c2..25487e557a 100644
--- a/lib/docs/filters/sanctuary_def/entries.rb
+++ b/lib/docs/filters/sanctuary_def/entries.rb
@@ -39,8 +39,10 @@ def additional_entries
           when "h3"
             type = node.text
           when "h4"
+            # Parent <div>'s ID set in github/clean_html.
+            id = node.parent.attributes["id"].value
             name = node.text.split(' :: ')[0]
-            id = node.attributes["id"].value
+
             entries << [name, id, type]
           end
         end
diff --git a/lib/docs/filters/sanctuary_type_classes/clean_html.rb b/lib/docs/filters/sanctuary_type_classes/clean_html.rb
index 247dbb39a9..491aa351ac 100644
--- a/lib/docs/filters/sanctuary_type_classes/clean_html.rb
+++ b/lib/docs/filters/sanctuary_type_classes/clean_html.rb
@@ -8,11 +8,6 @@ def call
           node.name = 'h3'
         }
 
-        # correct and unify link ids
-        css('h3').each { |node|
-          node.attributes["id"].value = node.text.split(' :: ')[0]
-        }
-
         doc
       end
     end
diff --git a/lib/docs/filters/sanctuary_type_classes/entries.rb b/lib/docs/filters/sanctuary_type_classes/entries.rb
index 8f4e051674..c9ee1aca0d 100644
--- a/lib/docs/filters/sanctuary_type_classes/entries.rb
+++ b/lib/docs/filters/sanctuary_type_classes/entries.rb
@@ -38,9 +38,9 @@ def additional_entries
           case node.name
           when "h2"
             type = node.text
-            if node.attributes["id"].value == "type-class-hierarchy"
+            if node.parent.attributes["id"]&.value == "type-class-hierarchy"
               name = node.text
-              id = node.attributes["id"].value
+              id = node.parent.attributes["id"].value
               entries << [name, id, type]
             end
           when "h4"
diff --git a/lib/docs/scrapers/github.rb b/lib/docs/scrapers/github.rb
index e5b48edbf6..dcadcec865 100644
--- a/lib/docs/scrapers/github.rb
+++ b/lib/docs/scrapers/github.rb
@@ -16,7 +16,13 @@ def process_response?(response)
     end
 
     def parse(response)
-      parsed = JSON.parse(response.response_body)
+      embedded_json = response
+        .response_body
+        .match(/react-app\.embeddedData">(.+?)<\/script>/)
+        &.captures
+        &.first
+      parsed = JSON.parse(embedded_json)
+
       [parsed['payload']['blob']['richText'], parsed['title']]
     end
   end
diff --git a/lib/docs/scrapers/koa.rb b/lib/docs/scrapers/koa.rb
index 94592b8cbb..f16b1061da 100644
--- a/lib/docs/scrapers/koa.rb
+++ b/lib/docs/scrapers/koa.rb
@@ -2,7 +2,7 @@
 
 module Docs
   class Koa < Github
-    self.base_url = 'https://github.com/koajs/koa/tree/master/docs'
+    self.base_url = 'https://github.com/koajs/koa/blob/master/docs'
     self.release = '2.15.0'
 
     self.root_path = 'api/index.md'
@@ -26,7 +26,7 @@ class Koa < Github
 
     html_filters.push 'koa/clean_html', 'koa/entries'
 
-    options[:skip] = %w[middleware.gif]
+    options[:skip_patterns] = [/\.gif/]
     options[:trailing_slash] = false
     options[:container] = '.markdown-body'
 
diff --git a/lib/docs/scrapers/nginx_lua_module.rb b/lib/docs/scrapers/nginx_lua_module.rb
index 9fcbab00ae..d704c38931 100644
--- a/lib/docs/scrapers/nginx_lua_module.rb
+++ b/lib/docs/scrapers/nginx_lua_module.rb
@@ -2,8 +2,9 @@ module Docs
   class NginxLuaModule < Github
     self.name = 'nginx / Lua Module'
     self.slug = 'nginx_lua_module'
-    self.release = '0.10.13'
-    self.base_url = "https://github.com/openresty/lua-nginx-module/tree/v#{self.release}/"
+    self.release = '0.10.28'
+    self.base_url = "https://github.com/openresty/lua-nginx-module/blob/v#{self.release}/"
+    self.root_path = 'README.markdown'
     self.links = {
       code: 'https://github.com/openresty/lua-nginx-module'
     }
@@ -11,13 +12,14 @@ class NginxLuaModule < Github
     html_filters.push 'nginx_lua_module/clean_html', 'nginx_lua_module/entries', 'title'
 
     options[:root_title] = 'ngx_http_lua_module'
-    options[:container] = '#readme > article'
-
+    options[:container] = '.markdown-body'
+    options[:max_image_size] = 256_000
     options[:attribution] = <<-HTML
       &copy; 2009&ndash;2017 Xiaozhe Wang (chaoslawful)<br>
-      &copy; 2009&ndash;2018 Yichun "agentzh" Zhang (章亦春), OpenResty Inc.<br>
+      &copy; 2009&ndash;2019 Yichun "agentzh" Zhang (章亦春), OpenResty Inc.<br>
       Licensed under the BSD License.
     HTML
+    options[:skip_patterns] = [/\.png/]
 
     def get_latest_version(opts)
       tags = get_github_tags('openresty', 'lua-nginx-module', opts)
diff --git a/lib/docs/scrapers/q.rb b/lib/docs/scrapers/q.rb
index a4c449c02d..0ba0cfa937 100644
--- a/lib/docs/scrapers/q.rb
+++ b/lib/docs/scrapers/q.rb
@@ -1,5 +1,5 @@
 module Docs
-  class Q < Github
+  class Q < UrlScraper
     self.name = 'Q'
     self.release = '1.5.1'
     self.base_url = 'https://github.com/kriskowal/q/wiki/'
@@ -16,7 +16,7 @@ class Q < Github
     options[:skip_links] = true
 
     options[:attribution] = <<-HTML
-      &copy; 2009&ndash;2017 Kristopher Michael Kowal<br>
+      &copy; 2009&ndash;2018 Kristopher Michael Kowal<br>
       Licensed under the MIT License.
     HTML
 

From f4e2ebd23b8268ef8433a0d78e858fa767022a66 Mon Sep 17 00:00:00 2001
From: Yikai Zhao <yikai@z1k.dev>
Date: Sat, 31 May 2025 11:15:26 +0800
Subject: [PATCH 309/384] Update pytorch scraper, include various 2.x versions

1. Various 2.x versions are included separately. Pytorch versions are
not backward compatible, it has different compatibilities between CUDA
etc, so people may use specific versions for a extended period of
time.

2. Removed the type replacement table for `get_type`. Instead, get the
type from breadcrumbs directly. IMO this produces better results that
matches the index in the original website (the left side menu in
docs.python.org). Also, the `TYPE_REPLACEMENT` table was opiniated and
hard to maintain across versions.

3. Always include default entry (removed `include_default_entry?`
function). I don't see the downside of this. Previously some pages are
missing because of this (e.g. torchrun https://docs.pytorch.org/docs/1.13/elastic/run.html)
---
 lib/docs/filters/pytorch/entries.rb | 80 +----------------------------
 lib/docs/scrapers/pytorch.rb        | 46 +++++++++++++++--
 2 files changed, 43 insertions(+), 83 deletions(-)

diff --git a/lib/docs/filters/pytorch/entries.rb b/lib/docs/filters/pytorch/entries.rb
index b337edbb9b..37e26e3129 100644
--- a/lib/docs/filters/pytorch/entries.rb
+++ b/lib/docs/filters/pytorch/entries.rb
@@ -1,73 +1,6 @@
 module Docs
   class Pytorch
     class EntriesFilter < Docs::EntriesFilter
-      TYPE_REPLACEMENTS = {
-        "torch.Tensor" => "Tensor",
-        "torch.nn" => "Neuro Network",
-        "Probability distributions - torch.distributions" => "Probability Distributions",
-        "torch" => "Torch",
-        "Quantization" => "Quantization",
-        "torch.optim" => "Optimization",
-        "torch.Storage" => "Storage",
-        "torch.nn.functional" => "NN Functions",
-        "torch.cuda" => "CUDA",
-        "Torch Distributed Elastic" => "Distributed Elastic",
-        "torch.fx" => "FX",
-        "TorchScript" => "Torch Script",
-        "torch.onnx" => "ONNX",
-        "Distributed communication package - torch.distributed" => "Distributed Communication",
-        "Automatic differentiation package - torch.autograd" => "Automatic Differentiation",
-        "torch.linalg" => "Linear Algebra",
-        "Distributed Checkpoint - torch.distributed.checkpoint" => "Distributed Checkpoint",
-        "Distributed RPC Framework" => "Distributed RPC",
-        "torch.special" => "SciPy-like Special",
-        "torch.package" => "Package",
-        "torch.backends" => "Backends",
-        "FullyShardedDataParallel" => "Fully Sharded Data Parallel",
-        "torch.sparse" => "Sparse Tensors",
-        "torch.export" => "Traced Graph Export",
-        "torch.fft" => "Discrete Fourier Transforms",
-        "torch.utils.data" => "Datasets and Data Loaders",
-        "torch.monitor" => "Monitor",
-        "Automatic Mixed Precision package - torch.amp" => "Automatic Mixed Precision",
-        "torch.utils.tensorboard" => "Tensorboard",
-        "torch.profiler" => "Profiler",
-        "torch.mps" => "MPS",
-        "DDP Communication Hooks" => "DDP Communication Hooks",
-        "Benchmark Utils - torch.utils.benchmark" => "Benchmark Utils",
-        "torch.nn.init" => "Parameter Initializations",
-        "Tensor Parallelism - torch.distributed.tensor.parallel" => "Tensor Parallelism",
-        "torch.func" => "JAX-like Function Transforms",
-        "Distributed Optimizers" => "Distributed Optimizers",
-        "torch.signal" => "SciPy-like Signal",
-        "torch.futures" => "Miscellaneous",
-        "torch.utils.cpp_extension" => "Miscellaneous",
-        "torch.overrides" => "Miscellaneous",
-        "Generic Join Context Manager" => "Miscellaneous",
-        "torch.hub" => "Miscellaneous",
-        "torch.cpu" => "Miscellaneous",
-        "torch.random" => "Miscellaneous",
-        "torch.compiler" => "Miscellaneous",
-        "Pipeline Parallelism" => "Miscellaneous",
-        "Named Tensors" => "Miscellaneous",
-        "Multiprocessing package - torch.multiprocessing" => "Miscellaneous",
-        "torch.utils" => "Miscellaneous",
-        "torch.library" => "Miscellaneous",
-        "Tensor Attributes" => "Miscellaneous",
-        "torch.testing" => "Miscellaneous",
-        "torch.nested" => "Miscellaneous",
-        "Understanding CUDA Memory Usage" => "Miscellaneous",
-        "torch.utils.dlpack" => "Miscellaneous",
-        "torch.utils.checkpoint" => "Miscellaneous",
-        "torch.__config__" => "Miscellaneous",
-        "Type Info" => "Miscellaneous",
-        "torch.utils.model_zoo" => "Miscellaneous",
-        "torch.utils.mobile_optimizer" => "Miscellaneous",
-        "torch._logging" => "Miscellaneous",
-        "torch.masked" => "Miscellaneous",
-        "torch.utils.bottleneck" => "Miscellaneous"
-      }
-
       def get_breadcrumbs
         css('.pytorch-breadcrumbs > li').map {
           |node| node.content.delete_suffix(' >').strip
@@ -75,18 +8,11 @@ def get_breadcrumbs
       end
 
       def get_name
-        b = get_breadcrumbs
-        b[(b[1] == 'torch' ? 2 : 1)..].join('.')
+        get_breadcrumbs[-1]
       end
 
       def get_type
-        t = get_breadcrumbs[1]
-        TYPE_REPLACEMENTS.fetch(t, t)
-      end
-
-      def include_default_entry?
-        # Only include API entries to simplify and unify the list
-        return name.start_with?('torch.')
+        get_breadcrumbs[1]
       end
 
       def additional_entries
@@ -108,8 +34,6 @@ def additional_entries
             entries << [id + '()', id]
           when 'py class', 'py attribute', 'py property'
             entries << [id, id]
-          when 'footnote brackets', 'field-list simple'
-            next
           end
         end
 
diff --git a/lib/docs/scrapers/pytorch.rb b/lib/docs/scrapers/pytorch.rb
index ae79ec36ac..cfa1d51010 100644
--- a/lib/docs/scrapers/pytorch.rb
+++ b/lib/docs/scrapers/pytorch.rb
@@ -12,20 +12,56 @@ class Pytorch < UrlScraper
 
     options[:skip] = ['cpp_index.html', 'deploy.html', 'packages.html', 'py-modindex.html', 'genindex.html']
     options[:skip_patterns] = [/\Acommunity/, /\A_modules/, /\Anotes/, /\Aorg\/pytorch\//]
+    options[:max_image_size] = 1_000_000
 
     options[:attribution] = <<-HTML
-    &copy; 2024, PyTorch Contributors<br>
+    &copy; 2025, PyTorch Contributors<br>
     PyTorch has a BSD-style license, as found in the <a href="https://github.com/pytorch/pytorch/blob/main/LICENSE">LICENSE</a> file.
     HTML
 
-    version '2' do
+    version '2.7' do
+      self.release = '2.7'
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
+    end
+
+    version '2.6' do
+      self.release = '2.6'
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
+    end
+
+    version '2.5' do
+      self.release = '2.5'
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
+    end
+
+    version '2.4' do
+      self.release = '2.4'
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
+    end
+
+    version '2.3' do
+      self.release = '2.3'
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
+    end
+
+    version '2.2' do
+      self.release = '2.2'
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
+    end
+
+    version '2.1' do
       self.release = '2.1'
-      self.base_url = "https://pytorch.org/docs/#{release}/"
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
+    end
+
+    version '2.0' do
+      self.release = '2.0'
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
     end
 
-    version '1' do
+    version '1.13' do
       self.release = '1.13'
-      self.base_url = "https://pytorch.org/docs/#{release}/"
+      self.base_url = "https://docs.pytorch.org/docs/#{release}/"
     end
 
     def get_latest_version(opts)

From caf8dda169dfb33faad25865cd6dffe07228ca05 Mon Sep 17 00:00:00 2001
From: Yikai Zhao <yikai@z1k.dev>
Date: Sat, 31 May 2025 14:18:37 +0800
Subject: [PATCH 310/384] numpy: add new version 2.1 and 2.2

---
 lib/docs/scrapers/numpy.rb | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/lib/docs/scrapers/numpy.rb b/lib/docs/scrapers/numpy.rb
index 6ecca0a87e..a679caaae2 100644
--- a/lib/docs/scrapers/numpy.rb
+++ b/lib/docs/scrapers/numpy.rb
@@ -1,4 +1,8 @@
 module Docs
+  # Requires downloading the documents to local disk first.
+  # Go to https://numpy.org/doc/, click "HTML+zip" to download
+  # (example url: https://numpy.org/doc/2.2/numpy-html.zip),
+  # then extract into "docs/numpy~#{version}/"
   class Numpy < FileScraper
     self.name = 'NumPy'
     self.type = 'sphinx'
@@ -26,6 +30,18 @@ class Numpy < FileScraper
       Licensed under the 3-clause BSD License.
     HTML
 
+    version '2.2' do
+      self.release = '2.2'
+      self.base_url = "https://numpy.org/doc/#{self.version}/"
+      options[:container] = nil
+    end
+
+    version '2.1' do
+      self.release = '2.1'
+      self.base_url = "https://numpy.org/doc/#{self.version}/"
+      options[:container] = nil
+    end
+
     version '2.0' do
       self.release = '2.0.1'
       self.base_url = "https://numpy.org/doc/#{self.version}/"

From 754285081d012660223ce97005625d44e7d00e8d Mon Sep 17 00:00:00 2001
From: Yikai Zhao <yikai@z1k.dev>
Date: Sat, 31 May 2025 14:22:15 +0800
Subject: [PATCH 311/384] update logo

---
 public/icons/docs/numpy/16.png    | Bin 834 -> 1121 bytes
 public/icons/docs/numpy/16@2x.png | Bin 2309 -> 2161 bytes
 public/icons/docs/numpy/SOURCE    |   2 +-
 3 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/public/icons/docs/numpy/16.png b/public/icons/docs/numpy/16.png
index ca5252ef09439cf556307a9867f05e67b5791b28..a24fcb151b3c1aa81046730e88a86b703eee22e4 100644
GIT binary patch
diff --git a/public/icons/docs/numpy/16@2x.png b/public/icons/docs/numpy/16@2x.png
index 1fa447c5099f4f40fa0e0c3d23b0809d2feea963..ad2df91191319a0180156e9e72b0cd63c047ed99 100644
GIT binary patch
diff --git a/public/icons/docs/numpy/SOURCE b/public/icons/docs/numpy/SOURCE
index 709633f233..eb744c2c9e 100644
--- a/public/icons/docs/numpy/SOURCE
+++ b/public/icons/docs/numpy/SOURCE
@@ -1 +1 @@
-https://github.com/numpy/numpy/blob/master/doc/source/_static/numpylogo.svg
+https://github.com/numpy/numpy/tree/main/doc/source/_static/favicon

From 040082f6eb48088186097e26eef6257d4c123108 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 09:01:40 +0200
Subject: [PATCH 312/384] Update Koa documentation (3.0.0)

---
 lib/docs/scrapers/koa.rb | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/lib/docs/scrapers/koa.rb b/lib/docs/scrapers/koa.rb
index f16b1061da..d61201ca80 100644
--- a/lib/docs/scrapers/koa.rb
+++ b/lib/docs/scrapers/koa.rb
@@ -2,10 +2,6 @@
 
 module Docs
   class Koa < Github
-    self.base_url = 'https://github.com/koajs/koa/blob/master/docs'
-    self.release = '2.15.0'
-
-    self.root_path = 'api/index.md'
     self.initial_paths = %w[
       error-handling
       faq
@@ -30,16 +26,43 @@ class Koa < Github
     options[:trailing_slash] = false
     options[:container] = '.markdown-body'
 
-    options[:fix_urls] = ->(url) do
-      url.sub! 'https://koajs.com/#error-handling', Koa.base_url + '/error-handling.md'
-      url
-    end
+
 
     options[:attribution] = <<-HTML
       &copy; 2020 Koa contributors<br>
       Licensed under the MIT License.
     HTML
 
+    version do
+      self.base_url = 'https://github.com/koajs/koa/blob/v3.0.0/docs'
+      self.root_path = 'api/index.md'
+      self.release = '3.0.0'
+      options[:fix_urls] = ->(url) do
+        url.sub! 'https://koajs.com/#error-handling', self.base_url + '/error-handling.md'
+        url
+      end
+    end
+    
+    version '2' do
+      self.base_url = 'https://github.com/koajs/koa/blob/v2.16.1/docs'
+      self.root_path = 'api/index.md'
+      self.release = '2.16.1'
+      options[:fix_urls] = ->(url) do
+        url.sub! 'https://koajs.com/#error-handling', self.base_url + '/error-handling.md'
+        url
+      end
+    end
+    
+    version '1' do
+      self.base_url = 'https://github.com/koajs/koa/blob/1.7.1/docs'
+      self.root_path = 'api/index.md'
+      self.release = '1.7.1'
+      options[:fix_urls] = ->(url) do
+        url.sub! 'https://koajs.com/#error-handling', self.base_url + '/error-handling.md'
+        url
+      end
+    end
+    
     def get_latest_version(opts)
       get_npm_version('koa', opts)
     end

From 23ffcc3a83b1a8f610e29511b61cecf7dcf79a7f Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 09:26:01 +0200
Subject: [PATCH 313/384] pytorch: add redirects

---
 lib/app.rb | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/app.rb b/lib/app.rb
index 89fe6cf0a3..675936fbac 100644
--- a/lib/app.rb
+++ b/lib/app.rb
@@ -376,6 +376,8 @@ def modern_browser?(browser)
     'angular~1.3' => 'angularjs~1.3',
     'angular~1.2' => 'angularjs~1.2',
     'codeigniter~3.0' => 'codeigniter~3',
+    'pytorch~1' => 'pytorch~1.13',
+    'pytorch~2' => 'pytorch',
     'webpack~2' => 'webpack'
   }
 

From 0dfc7799ecf611a1441b06cda911e49cca2eb541 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 09:52:48 +0200
Subject: [PATCH 314/384] Update Axios documentation (1.9.0)

---
 lib/docs/scrapers/axios.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/axios.rb b/lib/docs/scrapers/axios.rb
index 6265a9c376..c29b41ba6c 100755
--- a/lib/docs/scrapers/axios.rb
+++ b/lib/docs/scrapers/axios.rb
@@ -5,7 +5,7 @@ class Axios < UrlScraper
       home: 'hthttps://axios-http.com/',
       code: 'https://github.com/axios/axios'
     }
-    self.release = '1.7.7'
+    self.release = '1.9.0'
     self.base_url = "https://axios-http.com/docs/"
     self.initial_paths = %w(index intro)
     options[:skip] = %w(sponsor)

From 3bfddfeb01d62eb4a2b55a99cf3d4d88ffeed84e Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 09:58:59 +0200
Subject: [PATCH 315/384] Update Sass documentation (1.89.1)

---
 lib/docs/scrapers/sass.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/sass.rb b/lib/docs/scrapers/sass.rb
index d0c0a93537..1a1296c04c 100644
--- a/lib/docs/scrapers/sass.rb
+++ b/lib/docs/scrapers/sass.rb
@@ -1,7 +1,7 @@
 module Docs
   class Sass < UrlScraper
     self.type = 'yard'
-    self.release = '1.85.0'
+    self.release = '1.89.1'
     self.base_url = 'https://sass-lang.com/documentation'
     self.root_path = 'index.html'
     self.links = {

From 8771abc223efa42a16ab7e1b07fa1a80b16a755f Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 10:02:00 +0200
Subject: [PATCH 316/384] Update Octave documentation (10.1.0)

---
 lib/docs/scrapers/octave.rb | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/lib/docs/scrapers/octave.rb b/lib/docs/scrapers/octave.rb
index 085d6fd804..ee798d58dc 100644
--- a/lib/docs/scrapers/octave.rb
+++ b/lib/docs/scrapers/octave.rb
@@ -4,8 +4,8 @@ class Octave < UrlScraper
     self.type = 'octave'
     self.root_path = 'index.html'
     self.links = {
-      home: 'http://www.octave.org/',
-      code: 'http://www.octave.org/hg/octave'
+      home: 'https://www.octave.org/',
+      code: 'https://www.octave.org/hg/octave'
     }
 
     html_filters.push 'octave/clean_html', 'octave/entries', 'title'
@@ -23,12 +23,17 @@ class Octave < UrlScraper
     options[:root_title] = 'GNU Octave'
 
     options[:attribution] = <<-HTML
-      &copy; 1996–2023 The Octave Project Developers<br>
+      &copy; 1996–2025 The Octave Project Developers<br>
       Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.<br/>
       Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.</br>
       Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
     HTML
 
+    version '10' do
+      self.release = '10.1.0'
+      self.base_url = "https://docs.octave.org/v#{self.release}/"
+    end
+
     version '9' do
       self.release = '9.2.0'
       self.base_url = "https://docs.octave.org/v#{self.release}/"

From a6e3849c2c556c2b512a37ec8b4ad9d446888e95 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 10:02:15 +0200
Subject: [PATCH 317/384] Update Rust documentation (1.87.0)

---
 lib/docs/scrapers/rust.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/rust.rb b/lib/docs/scrapers/rust.rb
index 21de1602c1..e53c8548a0 100644
--- a/lib/docs/scrapers/rust.rb
+++ b/lib/docs/scrapers/rust.rb
@@ -3,7 +3,7 @@
 module Docs
   class Rust < UrlScraper
     self.type = 'rust'
-    self.release = '1.86.0'
+    self.release = '1.87.0'
     self.base_url = 'https://doc.rust-lang.org/'
     self.root_path = 'book/index.html'
     self.initial_paths = %w(

From c336a0eaec8a0a623f1c543e415211371bacbd97 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 10:07:00 +0200
Subject: [PATCH 318/384] Update Kubectl documentation (1.33.1)

---
 lib/docs/scrapers/kubectl.rb | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/docs/scrapers/kubectl.rb b/lib/docs/scrapers/kubectl.rb
index 732b5211f1..62b556862c 100644
--- a/lib/docs/scrapers/kubectl.rb
+++ b/lib/docs/scrapers/kubectl.rb
@@ -14,13 +14,13 @@ class Kubectl < UrlScraper
     options[:container] = '#page-content-wrapper'
 
     options[:attribution] = <<-HTML
-      &copy; 2024 The Kubernetes Authors | Documentation Distributed under CC BY 4.0 <br>
-      Copyright &copy; 2024 The Linux Foundation ®. All rights reserved.
+      &copy; 2025 The Kubernetes Authors | Documentation Distributed under CC BY 4.0 <br>
+      Copyright &copy; 2025 The Linux Foundation ®. All rights reserved.
     HTML
 
     # latest version has a special URL that does not include the version identifier 
     version do
-      self.release = "1.31.2"
+      self.release = "1.33.1"
       self.base_url = "https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands"
     end
 

From 2560e37df64ac8e2e80085f0df4dad8d9545f63d Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 10:07:29 +0200
Subject: [PATCH 319/384] Update Kubernetes documentation (1.33.1)

---
 lib/docs/scrapers/kubernetes.rb | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/docs/scrapers/kubernetes.rb b/lib/docs/scrapers/kubernetes.rb
index 39cefac7cb..d012c15f2e 100644
--- a/lib/docs/scrapers/kubernetes.rb
+++ b/lib/docs/scrapers/kubernetes.rb
@@ -14,13 +14,13 @@ class Kubernetes < UrlScraper
     options[:container] = '.td-content'
 
     options[:attribution] = <<-HTML
-      &copy; 2024 The Kubernetes Authors | Documentation Distributed under CC BY 4.0 <br>
-      Copyright &copy; 2024 The Linux Foundation ®. All rights reserved.
+      &copy; 2025 The Kubernetes Authors | Documentation Distributed under CC BY 4.0 <br>
+      Copyright &copy; 2025 The Linux Foundation ®. All rights reserved.
     HTML
 
     # latest version has a special URL that does not include the version identifier 
     version do
-      self.release = "1.31.2"
+      self.release = "1.33.1"
       self.base_url = "https://kubernetes.io/docs/reference/kubernetes-api/"
     end
 

From d134b9f64589af55137b3aaaabc0d07d1e53ef1d Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 10:08:25 +0200
Subject: [PATCH 320/384] Update PointCloudLibrary documentation (1.15.0)

---
 lib/docs/scrapers/point_cloud_library.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/point_cloud_library.rb b/lib/docs/scrapers/point_cloud_library.rb
index 2fdc609de5..7c49965497 100644
--- a/lib/docs/scrapers/point_cloud_library.rb
+++ b/lib/docs/scrapers/point_cloud_library.rb
@@ -9,7 +9,7 @@ class PointCloudLibrary < UrlScraper
     self.initial_paths = [
       "https://pointclouds.org/documentation/hierarchy.html"
     ]
-    self.release = '1.13.0'
+    self.release = '1.15.0'
 
     self.links = {
       home: 'https://pointclouds.org/',

From c71b811e8e53e0e628f9fa00c2bf9f78b71b24ff Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 10:13:04 +0200
Subject: [PATCH 321/384] Update Node.js documentation (24.1.0)

---
 lib/docs/scrapers/node.rb | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/node.rb b/lib/docs/scrapers/node.rb
index d8dc6cb484..ea9af21225 100644
--- a/lib/docs/scrapers/node.rb
+++ b/lib/docs/scrapers/node.rb
@@ -24,10 +24,15 @@ class Node < UrlScraper
     HTML
 
     version do
-      self.release = '22.3.0'
+      self.release = '24.1.0'
       self.base_url = 'https://nodejs.org/api/'
     end
 
+    version '22 LTS' do
+      self.release = '22.16.0'
+      self.base_url = 'https://nodejs.org/dist/latest-v22.x/docs/api/'
+    end
+
     version '20 LTS' do
       self.release = '20.15.01'
       self.base_url = 'https://nodejs.org/dist/latest-v20.x/docs/api/'

From 0b5689ac6f899715c85d58ee5ec9a71e1ea812a6 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 11:15:01 +0200
Subject: [PATCH 322/384] Update Web APIs documentation

---
 assets/stylesheets/global/_classes.scss |  5 +++++
 assets/stylesheets/pages/_mdn.scss      | 10 ++++++++--
 lib/docs/scrapers/mdn/dom.rb            |  2 +-
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/assets/stylesheets/global/_classes.scss b/assets/stylesheets/global/_classes.scss
index 9e6b933279..3321ff8fba 100644
--- a/assets/stylesheets/global/_classes.scss
+++ b/assets/stylesheets/global/_classes.scss
@@ -133,6 +133,11 @@
   border-color: var(--noteRedBorder);
 }
 
+%note-gray, %label-gray {
+  background: var(--boxBackground);
+  border: 1px solid var(--boxBorder);
+}
+
 //
 // External links
 //
diff --git a/assets/stylesheets/pages/_mdn.scss b/assets/stylesheets/pages/_mdn.scss
index 9155df4534..1bc6b8d831 100644
--- a/assets/stylesheets/pages/_mdn.scss
+++ b/assets/stylesheets/pages/_mdn.scss
@@ -28,12 +28,18 @@
 
   p > code, li > code { @extend %label; }
 
-  details { @extend %box; }
+  details { @extend %note; @extend %box; }
+  details.baseline-indicator.not { @extend %note; @extend %note-gray; }
+  details.baseline-indicator.low { @extend %note; @extend %note-blue; }
+  details.baseline-indicator.high { @extend %note; @extend %note-green; }
   summary > div { display: inline; }
+  summary .status-title { font-weight: bold; }
 
   > .note,
   .notecard, // MDN 2021
-  .notice,
+  .notice {
+    @extend %note; @extend %note-blue;
+  }
   .warning,
   .overheadIndicator,
   .blockIndicator,
diff --git a/lib/docs/scrapers/mdn/dom.rb b/lib/docs/scrapers/mdn/dom.rb
index 322d65d03f..88facbeda9 100644
--- a/lib/docs/scrapers/mdn/dom.rb
+++ b/lib/docs/scrapers/mdn/dom.rb
@@ -1,6 +1,6 @@
 module Docs
   class Dom < Mdn
-    # release = '2025-01-30'
+    # release = '2025-06-01'
     self.name = 'Web APIs'
     self.slug = 'dom'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/API'

From 778474845a65fb4bf3aff30d1fac3ad23711d91d Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 11:21:13 +0200
Subject: [PATCH 323/384] Update JavaScript documentation

---
 lib/docs/scrapers/mdn/javascript.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/mdn/javascript.rb b/lib/docs/scrapers/mdn/javascript.rb
index 28268b8112..28c0808cee 100644
--- a/lib/docs/scrapers/mdn/javascript.rb
+++ b/lib/docs/scrapers/mdn/javascript.rb
@@ -3,7 +3,7 @@ class Javascript < Mdn
     prepend FixInternalUrlsBehavior
     prepend FixRedirectionsBehavior
 
-    # release = '2025-04-15'
+    # release = '2025-06-01'
     self.name = 'JavaScript'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference'
     self.links = {

From b864fb10df5ea913c710a7d05f8cfbb87317c483 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 11:29:12 +0200
Subject: [PATCH 324/384] Update CSS documentation

---
 lib/docs/scrapers/mdn/css.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/mdn/css.rb b/lib/docs/scrapers/mdn/css.rb
index 42ace85097..5247481579 100644
--- a/lib/docs/scrapers/mdn/css.rb
+++ b/lib/docs/scrapers/mdn/css.rb
@@ -1,6 +1,6 @@
 module Docs
   class Css < Mdn
-    # release = '2024-11-17'
+    # release = '2025-06-01'
     self.name = 'CSS'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/CSS'
     self.root_path = '/Reference'

From 6797b57aedc398b12e1820afa4a1505bcd65f7b0 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 11:50:33 +0200
Subject: [PATCH 325/384] Update HTML documentation ()

---
 lib/docs/filters/html/entries.rb | 19 ++++++++++---------
 lib/docs/scrapers/mdn/html.rb    |  8 +-------
 lib/docs/scrapers/mdn/mdn.rb     |  2 +-
 3 files changed, 12 insertions(+), 17 deletions(-)

diff --git a/lib/docs/filters/html/entries.rb b/lib/docs/filters/html/entries.rb
index b018d9087d..1dcf397a06 100644
--- a/lib/docs/filters/html/entries.rb
+++ b/lib/docs/filters/html/entries.rb
@@ -5,21 +5,22 @@ class EntriesFilter < Docs::EntriesFilter
 
       def get_name
         name = super
-        name.sub!('Element.', '').try(:downcase!)
-        name.sub!('Global attributes.', '').try(:concat, ' (attribute)')
+        name.sub!('Guides.', '')
+        name.sub!('How to.', '')
+        name.sub!('Reference.Elements.', '').try(:downcase!)
+        name.sub!('Reference.Attributes.', '').try(:concat, ' (attribute)')
+        name.sub!('Reference.Global attributes.', '').try(:concat, ' (attribute)')
         name.sub!(/input\.([-\w]+)/, 'input type="\1"')
         name
       end
 
       def get_type
-        return 'Miscellaneous' if slug.include?('CORS') || slug.include?('Using')
-
         if at_css('.deprecated', '.non-standard', '.obsolete')
-        'Obsolete'
-        elsif slug.start_with?('Global_attr')
-          'Attributes'
-        elsif slug.start_with?('Element/')
-          'Elements'
+          'Obsolete'
+        elsif slug.start_with?('Guides/')
+          'Guides'
+        elsif slug.start_with?('Reference/')
+          slug.split('/').drop(1).first.sub(/_/, ' ')
         else
           'Miscellaneous'
         end
diff --git a/lib/docs/scrapers/mdn/html.rb b/lib/docs/scrapers/mdn/html.rb
index 70b75917ac..fcec226ed5 100644
--- a/lib/docs/scrapers/mdn/html.rb
+++ b/lib/docs/scrapers/mdn/html.rb
@@ -2,7 +2,7 @@ module Docs
   class Html < Mdn
     prepend FixInternalUrlsBehavior
 
-    # release = '2024-08-20'
+    # release = '2025-06-01'
     self.name = 'HTML'
     self.base_url = 'https://developer.mozilla.org/en-US/docs/Web/HTML'
     self.links = {
@@ -22,11 +22,5 @@ class Html < Mdn
       '/Element/h5' => '/Element/Heading_Elements',
       '/Element/h6' => '/Element/Heading_Elements',
       '/Global_attributes/data-%2A' => '/Global_attributes/data-*' }
-
-    options[:fix_urls] = ->(url) do
-      url.sub! 'https://developer.mozilla.org/en-US/docs/HTML/', "#{Html.base_url}/" unless url.include?('Content_categories')
-      url
-    end
-
   end
 end
diff --git a/lib/docs/scrapers/mdn/mdn.rb b/lib/docs/scrapers/mdn/mdn.rb
index ebc482e7cc..c574345992 100644
--- a/lib/docs/scrapers/mdn/mdn.rb
+++ b/lib/docs/scrapers/mdn/mdn.rb
@@ -18,7 +18,7 @@ class Mdn < UrlScraper
     }
 
     options[:attribution] = <<-HTML
-      &copy; 2005&ndash;2024 MDN contributors.<br>
+      &copy; 2005&ndash;2025 MDN contributors.<br>
       Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
     HTML
 

From de218ca78209255993240ec69f6ea4d110a4acb6 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 11:54:01 +0200
Subject: [PATCH 326/384] Update Perl documentation (5.40.2)

---
 lib/docs/scrapers/perl.rb | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/perl.rb b/lib/docs/scrapers/perl.rb
index 6c9febb338..e28f4076ae 100644
--- a/lib/docs/scrapers/perl.rb
+++ b/lib/docs/scrapers/perl.rb
@@ -19,11 +19,16 @@ class Perl < UrlScraper
     options[:skip_patterns] = [/\Afunctions/, /\Avariables/, /\.pdf/, /delta/]
 
     options[:attribution] = <<-HTML
-      &copy; 1993&ndash;2023 Larry Wall and others<br>
+      &copy; 1993&ndash;2025 Larry Wall and others<br>
       Licensed under the GNU General Public License version 1 or later, or the Artistic License.<br>
       The Perl logo is a trademark of the Perl Foundation.
     HTML
 
+    version '5.40' do
+      self.release = '5.40.2'
+      self.base_url = "https://perldoc.perl.org/#{release}/"
+    end
+
     version '5.38' do
       self.release = '5.38.0'
       self.base_url = "https://perldoc.perl.org/#{release}/"

From 24a9cbbc324cddabfee452b4d566af5e6e9fcc3c Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 11:56:35 +0200
Subject: [PATCH 327/384] Update SQLite documentation (3.50.0)

---
 lib/docs/scrapers/sqlite.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/sqlite.rb b/lib/docs/scrapers/sqlite.rb
index 7de3e57f12..c7a4cd36df 100644
--- a/lib/docs/scrapers/sqlite.rb
+++ b/lib/docs/scrapers/sqlite.rb
@@ -2,7 +2,7 @@ module Docs
   class Sqlite < UrlScraper
     self.name = 'SQLite'
     self.type = 'sqlite'
-    self.release = '3.49.1'
+    self.release = '3.50.0'
     self.base_url = 'https://sqlite.org/'
     self.root_path = 'docs.html'
     self.initial_paths = %w(keyword_index.html)

From db68e27b900da5fac64390cfef028e9546ad4125 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 11:59:54 +0200
Subject: [PATCH 328/384] Update Jekyll documentation (4.4.1)

---
 lib/docs/scrapers/jekyll.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/jekyll.rb b/lib/docs/scrapers/jekyll.rb
index 1c0534ebe8..d105e3523f 100644
--- a/lib/docs/scrapers/jekyll.rb
+++ b/lib/docs/scrapers/jekyll.rb
@@ -23,12 +23,12 @@ class Jekyll < UrlScraper
     }
 
     options[:attribution] = <<-HTML
-      &copy; 2020 Jekyll Core Team and contributors<br>
+      &copy; 2025 Jekyll Core Team and contributors<br>
       Licensed under the MIT license.
     HTML
 
     version '4' do
-      self.release = '4.2.0'
+      self.release = '4.4.1'
     end
 
     version '3' do

From 896f8e0a023f6481e51d1845291ae86aa3a10296 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 12:25:54 +0200
Subject: [PATCH 329/384] Update PostgreSQL documentation (17.5)

---
 lib/docs/scrapers/postgresql.rb | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/postgresql.rb b/lib/docs/scrapers/postgresql.rb
index e54cc8a513..6ce5bbf8aa 100644
--- a/lib/docs/scrapers/postgresql.rb
+++ b/lib/docs/scrapers/postgresql.rb
@@ -17,6 +17,7 @@ class Postgresql < UrlScraper
     options[:title] = false
     options[:root_title] = 'PostgreSQL'
     options[:follow_links] = ->(filter) { filter.initial_page? }
+    options[:rate_limit] = 200
 
     options[:skip] = %w(
       index.html
@@ -51,12 +52,12 @@ class Postgresql < UrlScraper
       /\Aunsupported-features/ ]
 
     options[:attribution] = <<-HTML
-      &copy; 1996&ndash;2024 The PostgreSQL Global Development Group<br>
+      &copy; 1996&ndash;2025 The PostgreSQL Global Development Group<br>
       Licensed under the PostgreSQL License.
     HTML
 
     version '17' do
-      self.release = '17.1'
+      self.release = '17.5'
       self.base_url = "https://www.postgresql.org/docs/#{version}/"
     end
 

From 1dc15574d4bbe7676ffb06176dd3bc484916d856 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 18:51:18 +0200
Subject: [PATCH 330/384] Update Svelte documentation (5.33.11)

---
 lib/docs/scrapers/svelte.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/svelte.rb b/lib/docs/scrapers/svelte.rb
index aac8738920..537c2cc063 100644
--- a/lib/docs/scrapers/svelte.rb
+++ b/lib/docs/scrapers/svelte.rb
@@ -13,7 +13,7 @@ class Svelte < UrlScraper
 
     # https://github.com/sveltejs/svelte/blob/master/LICENSE.md
     options[:attribution] = <<-HTML
-      &copy; 2016–2024 Rich Harris and contributors<br>
+      &copy; 2016–2025 Rich Harris and contributors<br>
       Licensed under the MIT License.
     HTML
 
@@ -21,7 +21,7 @@ class Svelte < UrlScraper
     html_filters.push 'svelte/entries', 'svelte/clean_html'
 
     version do
-      self.release = '5.2.3'
+      self.release = '5.33.11'
     end
 
     version '4' do

From 786a238d5e238d1fdb0226f88bf5d29c8f788695 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 20:40:32 +0200
Subject: [PATCH 331/384] Update QUnit documentation (2.24.1)

---
 lib/docs/filters/qunit/entries.rb | 3 ++-
 lib/docs/scrapers/qunit.rb        | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/docs/filters/qunit/entries.rb b/lib/docs/filters/qunit/entries.rb
index 43de1c5af8..fa4541c45b 100644
--- a/lib/docs/filters/qunit/entries.rb
+++ b/lib/docs/filters/qunit/entries.rb
@@ -8,7 +8,8 @@ class EntriesFilter < Docs::EntriesFilter
         'assert' => '2. Assertions',
         'callbacks' => '3. Callback events',
         'config' => '4. Configuration',
-        'extension' => '5. Extension interface'
+        'extension' => '5. Extension interface',
+        'reporters' => '6. Reporters',
       }
       def get_name
         at_css('h1').content
diff --git a/lib/docs/scrapers/qunit.rb b/lib/docs/scrapers/qunit.rb
index ff13fbdb7b..125605e373 100644
--- a/lib/docs/scrapers/qunit.rb
+++ b/lib/docs/scrapers/qunit.rb
@@ -4,7 +4,7 @@ module Docs
   class Qunit < UrlScraper
     self.name = 'QUnit'
     self.type = 'qunit'
-    self.release = '2.21.0'
+    self.release = '2.24.1'
     self.base_url = 'https://qunitjs.com/api/'
     self.root_path = '/'
     self.links = {

From afc9e535c1012b2299fe46b4c12666537f052a0b Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Sun, 1 Jun 2025 20:57:09 +0200
Subject: [PATCH 332/384] Update Express documentation (5.1.0)

---
 lib/docs/filters/express/clean_html.rb |  6 +++---
 lib/docs/scrapers/express.rb           | 12 ++++++++++--
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/lib/docs/filters/express/clean_html.rb b/lib/docs/filters/express/clean_html.rb
index 01a6390972..eeb98f1d50 100644
--- a/lib/docs/filters/express/clean_html.rb
+++ b/lib/docs/filters/express/clean_html.rb
@@ -7,14 +7,14 @@ def call
         i += 1 while n && n = n.previous_element
         at_css('h1')['data-level'] = i
 
-        @doc = at_css('#api-doc, .content')
+        @doc = at_css('#api-doc, main, .content')
+
+        css('nav').remove # aria-labelledby="sidebar-heading"
 
         css('section', 'div.highlighter-rouge').each do |node|
           node.before(node.children).remove
         end
 
-        @doc = at_css('#page-doc') unless root_page?
-
         if root_page?
           at_css('h1').remove
           css('> header', '#menu').remove
diff --git a/lib/docs/scrapers/express.rb b/lib/docs/scrapers/express.rb
index 724b771ff8..ff6514b5fb 100644
--- a/lib/docs/scrapers/express.rb
+++ b/lib/docs/scrapers/express.rb
@@ -2,9 +2,7 @@ module Docs
   class Express < UrlScraper
     self.name = 'Express'
     self.type = 'express'
-    self.release = '4.21.2'
     self.base_url = 'https://expressjs.com/en/'
-    self.root_path = '4x/api.html'
     self.initial_paths = %w(
       starter/installing.html
       guide/routing.html
@@ -29,6 +27,16 @@ class Express < UrlScraper
       Licensed under the Creative Commons Attribution-ShareAlike License v3.0.
     HTML
 
+    version do
+      self.release = '5.1.0'
+      self.root_path = '5x/api.html'
+    end
+
+    version '4' do
+      self.release = '4.21.2'
+      self.root_path = '4x/api.html'
+    end
+
     def get_latest_version(opts)
       get_npm_version('express', opts)
     end

From 93c3c572a4ddfd535bfaa202326771e8d430d92a Mon Sep 17 00:00:00 2001
From: Adam Doppelt <amd@gurge.com>
Date: Mon, 2 Jun 2025 15:51:15 -0700
Subject: [PATCH 333/384] es-toolkit scraper

---
 docs/file-scrapers.md                  |   6 ++
 lib/docs/scrapers/es_toolkit.rb        |  87 +++++++++++++++++++++++++
 public/icons/docs/es_toolkit/16.png    | Bin 0 -> 450 bytes
 public/icons/docs/es_toolkit/16@2x.png | Bin 0 -> 752 bytes
 public/icons/docs/es_toolkit/SOURCE    |   1 +
 5 files changed, 94 insertions(+)
 create mode 100644 lib/docs/scrapers/es_toolkit.rb
 create mode 100644 public/icons/docs/es_toolkit/16.png
 create mode 100644 public/icons/docs/es_toolkit/16@2x.png
 create mode 100644 public/icons/docs/es_toolkit/SOURCE

diff --git a/docs/file-scrapers.md b/docs/file-scrapers.md
index 7a6e0a5f5f..133b621b9b 100644
--- a/docs/file-scrapers.md
+++ b/docs/file-scrapers.md
@@ -59,6 +59,12 @@ curl -L https://github.com/erlang/otp/releases/download/OTP-$RELEASE/otp_doc_htm
 bsdtar --extract --file - --directory=docs/erlang\~$VERSION/
 ```
 
+## es-toolkit
+
+```sh
+git clone https://github.com/toss/es-toolkit docs/es_toolkit
+```
+
 ## Gnu
 
 ### Bash
diff --git a/lib/docs/scrapers/es_toolkit.rb b/lib/docs/scrapers/es_toolkit.rb
new file mode 100644
index 0000000000..943faef0a4
--- /dev/null
+++ b/lib/docs/scrapers/es_toolkit.rb
@@ -0,0 +1,87 @@
+module Docs
+  class EsToolkit < FileScraper
+    self.name = "es-toolkit"
+    self.slug = "es_toolkit"
+    self.type = "simple"
+    self.links = {
+      code: "https://github.com/toss/es-toolkit",
+      home: "https://es-toolkit.slash.page",
+    }
+
+    options[:attribution] = <<-HTML
+      &copy; 2024-2025, Viva Republica<br>
+      Licensed under the MIT License.
+    HTML
+
+    def get_latest_version(opts)
+      get_github_tags("toss", "es-toolkit", opts).first["name"]
+    end
+
+    def build_pages(&block)
+      internal("docs/intro.md", path: "index", &block)
+      Dir.chdir(source_directory) do
+        Dir["docs/reference/**/*.md"]
+      end.each { internal(_1, &block) }
+    end
+
+    protected
+
+    def internal(filename, path: nil, &block)
+      path ||= filename[%r{docs/reference/(.*/.*).md$}, 1]
+
+      # calculate name/type
+      if path != "index"
+        name = filename[%r{([^/]+).md$}, 1]
+        type = path.split("/")[0..-2]
+        type = type.map(&:capitalize).join(" ")
+        # really bad way to sort
+        type = type.gsub(/^(Compat|Error)\b/, "~ \\1")
+      else
+        name = type = nil
+      end
+
+      # now yield
+      entries = [Entry.new(name, path, type)]
+      output = render(filename)
+      store_path = "#{path}.html"
+      yield({entries:, output:, path:, store_path:})
+    end
+
+    # render/style HTML
+    def render(filename)
+      s = md.render(request_one(filename).body)
+
+      # kill all links, they don't work
+      s.gsub!(%r{<a href="[^"]+">(.*?)</a>}, "<span>\\1</span>")
+
+      # syntax highlighting
+      s.gsub!(%r{<pre><code class="typescript">}, "<pre data-language='typescript'><code class='typescript'>")
+
+      # h3 => h4
+      s.gsub!(%r{(</?h)3>}, "\\14>")
+
+      # manually add attribution
+      s += <<~HTML
+        <div class="_attribution">
+          <p class="_attribution-p">
+            #{options[:attribution]}
+            <br>
+            <a href="#{self.class.links[:home]}" class="_attribution-link">
+              #{self.class.links[:home]}
+            </a>
+          </p>
+        </div>
+      HTML
+      s
+    end
+
+    def md
+      @md ||= Redcarpet::Markdown.new(
+        Redcarpet::Render::HTML,
+        autolink: true,
+        fenced_code_blocks: true,
+        tables: true
+      )
+    end
+  end
+end
diff --git a/public/icons/docs/es_toolkit/16.png b/public/icons/docs/es_toolkit/16.png
new file mode 100644
index 0000000000000000000000000000000000000000..d63aff1c359d25b91120b893c23e5a8843e9989d
GIT binary patch
diff --git a/public/icons/docs/es_toolkit/16@2x.png b/public/icons/docs/es_toolkit/16@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..40dff7a352707bf6d9cb8ec4036015ccabd8a76f
GIT binary patch
diff --git a/public/icons/docs/es_toolkit/SOURCE b/public/icons/docs/es_toolkit/SOURCE
new file mode 100644
index 0000000000..90444ebb34
--- /dev/null
+++ b/public/icons/docs/es_toolkit/SOURCE
@@ -0,0 +1 @@
+https://es-toolkit.slash.page/favicon-100x100.png

From 45833e2a9bef973753e6af3e0f6ce130b0f71025 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 3 Jun 2025 04:58:05 +0000
Subject: [PATCH 334/384] Update dependency rack to v2.2.17

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 65d0c358e9..8f6c1c7dca 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -78,7 +78,7 @@ GEM
       byebug (~> 12.0)
       pry (>= 0.13, < 0.16)
     racc (1.8.1)
-    rack (2.2.16)
+    rack (2.2.17)
     rack-protection (3.2.0)
       base64 (>= 0.1.0)
       rack (~> 2.2, >= 2.2.4)

From 90fed11831d019314ff40d5ac5006ded1215817c Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 4 Jun 2025 20:03:48 +0200
Subject: [PATCH 335/384] es-toolkit: use U+2063 INVISIBLE SEPARATOR

---
 lib/docs/scrapers/es_toolkit.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/es_toolkit.rb b/lib/docs/scrapers/es_toolkit.rb
index 943faef0a4..4b84aa51a9 100644
--- a/lib/docs/scrapers/es_toolkit.rb
+++ b/lib/docs/scrapers/es_toolkit.rb
@@ -35,7 +35,7 @@ def internal(filename, path: nil, &block)
         type = path.split("/")[0..-2]
         type = type.map(&:capitalize).join(" ")
         # really bad way to sort
-        type = type.gsub(/^(Compat|Error)\b/, "~ \\1")
+        type = type.gsub(/^(Compat|Error)\b/, "\u2063\\1") #  U+2063 INVISIBLE SEPARATOR
       else
         name = type = nil
       end

From 52a9a3da3a1582cb5522a8f3ee8023db7ff1eae5 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 4 Jun 2025 20:03:59 +0200
Subject: [PATCH 336/384] es-toolkit: attribution link

---
 lib/docs/scrapers/es_toolkit.rb | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/es_toolkit.rb b/lib/docs/scrapers/es_toolkit.rb
index 4b84aa51a9..85079723a0 100644
--- a/lib/docs/scrapers/es_toolkit.rb
+++ b/lib/docs/scrapers/es_toolkit.rb
@@ -61,13 +61,14 @@ def render(filename)
       s.gsub!(%r{(</?h)3>}, "\\14>")
 
       # manually add attribution
+      link = "#{self.class.links[:home]}#{filename.gsub(/^docs/,'').gsub(/md$/,'html')}"
       s += <<~HTML
         <div class="_attribution">
           <p class="_attribution-p">
             #{options[:attribution]}
             <br>
-            <a href="#{self.class.links[:home]}" class="_attribution-link">
-              #{self.class.links[:home]}
+            <a href="#{link}" class="_attribution-link">
+              #{link}
             </a>
           </p>
         </div>

From 58c4ef986418bdfb5153c38738d0ed0469d88439 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Wed, 4 Jun 2025 20:04:22 +0200
Subject: [PATCH 337/384] es-toolkit: add news

---
 assets/javascripts/news.json | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index 3ddc39a516..6679b04f5c 100644
--- a/assets/javascripts/news.json
+++ b/assets/javascripts/news.json
@@ -1,4 +1,8 @@
 [
+  [
+    "2025-06-04",
+    "New documentation: <a href=\"/es_toolkit/\">es-toolkit</a>"
+  ],
   [
     "2025-05-28",
     "New documentation: <a href=\"/vertx/\">Vert.x</a>"

From fe827b3da367b500f42413faab603babb37107ee Mon Sep 17 00:00:00 2001
From: spamguy <spamguy@spamguy.org>
Date: Tue, 3 Jun 2025 15:29:03 -0700
Subject: [PATCH 338/384] Implement Zsh scraper

---
 lib/docs/filters/zsh/clean_html.rb |  20 ++++++++++++++
 lib/docs/filters/zsh/entries.rb    |  41 +++++++++++++++++++++++++++++
 lib/docs/scrapers/zsh.rb           |  33 +++++++++++++++++++++++
 public/icons/docs/zsh/16.png       | Bin 0 -> 687 bytes
 public/icons/docs/zsh/16@2x.png    | Bin 0 -> 1206 bytes
 public/icons/docs/zsh/SOURCE       |   2 ++
 6 files changed, 96 insertions(+)
 create mode 100644 lib/docs/filters/zsh/clean_html.rb
 create mode 100644 lib/docs/filters/zsh/entries.rb
 create mode 100644 lib/docs/scrapers/zsh.rb
 create mode 100644 public/icons/docs/zsh/16.png
 create mode 100644 public/icons/docs/zsh/16@2x.png
 create mode 100644 public/icons/docs/zsh/SOURCE

diff --git a/lib/docs/filters/zsh/clean_html.rb b/lib/docs/filters/zsh/clean_html.rb
new file mode 100644
index 0000000000..43d65e045c
--- /dev/null
+++ b/lib/docs/filters/zsh/clean_html.rb
@@ -0,0 +1,20 @@
+module Docs
+  class Zsh
+    class CleanHtmlFilter < Filter
+      def call
+        css('table.header', 'table.menu', 'hr').remove
+
+        # Remove indices from headers.
+        css('h1', 'h2', 'h3').each do |node|
+          node.content = node.content.match(/^[\d\.]* (.*)$/)&.captures&.first
+        end
+
+        css('h2.section ~ a').each do |node|
+          node.next_element['id'] = node['name']
+        end
+
+        doc
+      end
+    end
+  end
+end
diff --git a/lib/docs/filters/zsh/entries.rb b/lib/docs/filters/zsh/entries.rb
new file mode 100644
index 0000000000..e6bc07305e
--- /dev/null
+++ b/lib/docs/filters/zsh/entries.rb
@@ -0,0 +1,41 @@
+module Docs
+  class Zsh
+    class EntriesFilter < Docs::EntriesFilter
+      def get_name
+        extract_header_text(at_css('h1.chapter').content)
+      end
+
+      def additional_entries
+        entries = []
+
+        css('h2.section').each do |node|
+          type = get_type
+
+          # Linkable anchor sits above <h2>.
+          a = node.xpath('preceding-sibling::a').last
+          header_text = extract_header_text(node.content)
+
+          if type == 'Zsh Modules'
+            module_name = header_text.match(/The (zsh\/.*) Module/)&.captures&.first
+            header_text = module_name if module_name.present?
+          end
+
+          entries << [header_text, a['name'], type] if header_text != 'Description'
+        end
+
+        entries
+      end
+
+      def get_type
+        extract_header_text(at_css('h1.chapter').content)
+      end
+
+      private
+
+      # Extracts text from a string, dropping indices preceding it.
+      def extract_header_text(str)
+        str.match(/^[\d\.]* (.*)$/)&.captures&.first
+      end
+    end
+  end
+end
diff --git a/lib/docs/scrapers/zsh.rb b/lib/docs/scrapers/zsh.rb
new file mode 100644
index 0000000000..82423d34f2
--- /dev/null
+++ b/lib/docs/scrapers/zsh.rb
@@ -0,0 +1,33 @@
+module Docs
+  class Zsh < UrlScraper
+    self.type = 'zsh'
+    self.release = '5.9.0'
+    self.base_url = 'https://zsh.sourceforge.io/Doc/Release/'
+    self.root_path = 'index.html'
+    self.links = {
+      home: 'https://zsh.sourceforge.io/',
+      code: 'https://sourceforge.net/p/zsh/web/ci/master/tree/',
+    }
+
+    options[:skip] = %w(
+      zsh_toc.html
+      zsh_abt.html
+      The-Z-Shell-Manual.html
+      Introduction.html
+    )
+    options[:skip_patterns] = [/-Index.html/]
+
+    html_filters.push 'zsh/entries', 'zsh/clean_html'
+
+    options[:attribution] = <<-HTML
+      The Z Shell is copyright &copy; 1992&ndash;2017 Paul Falstad, Richard Coleman,
+ Zoltán Hidvégi, Andrew Main, Peter Stephenson, Sven Wischnowsky, and others.<br />
+      Licensed under the MIT License.
+    HTML
+
+    def get_latest_version(opts)
+      body = fetch('https://zsh.sourceforge.io/Doc/Release', opts)
+      body.scan(/, Zsh version ([0-9.]+)/)[0][0][0...-1]
+    end
+  end
+end
diff --git a/public/icons/docs/zsh/16.png b/public/icons/docs/zsh/16.png
new file mode 100644
index 0000000000000000000000000000000000000000..05dc56e07e77cd0c22fff897d23390b270292ef1
GIT binary patch
diff --git a/public/icons/docs/zsh/16@2x.png b/public/icons/docs/zsh/16@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..014d7ab78a835b47ea610fada2e2a929fbfb06b4
GIT binary patch
diff --git a/public/icons/docs/zsh/SOURCE b/public/icons/docs/zsh/SOURCE
new file mode 100644
index 0000000000..70cc4aeed8
--- /dev/null
+++ b/public/icons/docs/zsh/SOURCE
@@ -0,0 +1,2 @@
+https://sourceforge.net/p/zsh/web/ci/master/tree/favicon.png
+

From 5d59c2f63d8207070ed43836cad1d310d3b09d6e Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 11 Jun 2025 23:14:24 +0000
Subject: [PATCH 339/384] Update ruby/setup-ruby action to v1.245.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c9d4ed4fba..0955358272 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
+      uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 471f54cd9e..6bce275a66 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
+      uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6e7d36baff..89a56c13e9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
+      uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From ba2f450bdec60822309732d6b4ccae3ec95ec2e9 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 19 Jun 2025 16:47:34 +0000
Subject: [PATCH 340/384] Update dependency terser to v1.2.6

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 8f6c1c7dca..cd22f745b6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -130,7 +130,7 @@ GEM
     strings-ansi (0.2.0)
     terminal-table (3.0.2)
       unicode-display_width (>= 1.1.1, < 3)
-    terser (1.2.5)
+    terser (1.2.6)
       execjs (>= 0.3.0, < 3)
     thin (1.8.2)
       daemons (~> 1.0, >= 1.0.9)

From 2b035804da5a215af86da454e38a49e2e1fdcc1b Mon Sep 17 00:00:00 2001
From: Alex Bepple <alex@bepple.de>
Date: Fri, 20 Jun 2025 19:00:59 +0200
Subject: [PATCH 341/384] (ramda) $! make docs generatable again

---
 lib/docs/filters/ramda/entries.rb | 4 +++-
 lib/docs/scrapers/ramda.rb        | 4 ++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/lib/docs/filters/ramda/entries.rb b/lib/docs/filters/ramda/entries.rb
index dcab3c0137..ab85371f8a 100644
--- a/lib/docs/filters/ramda/entries.rb
+++ b/lib/docs/filters/ramda/entries.rb
@@ -3,7 +3,9 @@ class Ramda
     class EntriesFilter < Docs::EntriesFilter
       def additional_entries
         css('ul.toc li').map do |node|
-          ["R.#{node['data-name']}", node['data-name'], node['data-category'].sub('Relaction', 'Relation')]
+          # As of 2025-06-20, `data-category` attribute is missing on https://ramdajs.com/ for Ramda versions < 0.29.0.
+          # This results in missing type for entries – and docs cannot be generated.
+          ["R.#{node['data-name']}", node['data-name'], node['data-category']]
         end
       end
     end
diff --git a/lib/docs/scrapers/ramda.rb b/lib/docs/scrapers/ramda.rb
index 897b227f21..abf7dde9ba 100644
--- a/lib/docs/scrapers/ramda.rb
+++ b/lib/docs/scrapers/ramda.rb
@@ -1,7 +1,7 @@
 module Docs
   class Ramda < UrlScraper
     self.type = 'ramda'
-    self.release = '0.27.0'
+    self.release = '0.29.0'
     self.base_url = "https://ramdajs.com/#{release}/docs/"
     self.links = {
       home: 'http://ramdajs.com/',
@@ -12,7 +12,7 @@ class Ramda < UrlScraper
 
     options[:title] = 'Ramda'
     options[:attribution] = <<-HTML
-      &copy; 2013&ndash;2020 Scott Sauyet and Michael Hurley<br>
+      &copy; 2013&ndash;2024 Scott Sauyet and Michael Hurley<br>
       Licensed under the MIT License.
     HTML
 

From 3111ac2e1016a5b79e89af9e8e4b6cf23d86a84b Mon Sep 17 00:00:00 2001
From: Alex Bepple <alex@bepple.de>
Date: Fri, 20 Jun 2025 19:08:44 +0200
Subject: [PATCH 342/384] (ramda) $! correctly determine latest version

---
 lib/docs/scrapers/ramda.rb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/ramda.rb b/lib/docs/scrapers/ramda.rb
index abf7dde9ba..d69cc0e964 100644
--- a/lib/docs/scrapers/ramda.rb
+++ b/lib/docs/scrapers/ramda.rb
@@ -17,8 +17,7 @@ class Ramda < UrlScraper
     HTML
 
     def get_latest_version(opts)
-      doc = fetch_doc('https://ramdajs.com/docs/', opts)
-      doc.at_css('.navbar-brand > .version').content[1..-1]
+      get_npm_version('ramda', opts)
     end
   end
 end

From d413aab015d5cdc2936fbf9c85043ab866f338e7 Mon Sep 17 00:00:00 2001
From: Alex Bepple <alex@bepple.de>
Date: Fri, 20 Jun 2025 19:55:36 +0200
Subject: [PATCH 343/384] (ramda) $ specify the only 2 versions that make sense

---
 lib/docs/scrapers/ramda.rb | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/ramda.rb b/lib/docs/scrapers/ramda.rb
index d69cc0e964..03494eb77d 100644
--- a/lib/docs/scrapers/ramda.rb
+++ b/lib/docs/scrapers/ramda.rb
@@ -1,8 +1,6 @@
 module Docs
   class Ramda < UrlScraper
     self.type = 'ramda'
-    self.release = '0.29.0'
-    self.base_url = "https://ramdajs.com/#{release}/docs/"
     self.links = {
       home: 'http://ramdajs.com/',
       code: 'https://github.com/ramda/ramda/'
@@ -16,6 +14,16 @@ class Ramda < UrlScraper
       Licensed under the MIT License.
     HTML
 
+    version '0.30' do
+      self.release = '0.30.1'
+      self.base_url = "https://ramdajs.com/#{release}/docs/"
+    end
+
+    version '0.29' do
+      self.release = '0.29.1'
+      self.base_url = "https://ramdajs.com/#{release}/docs/"
+    end
+
     def get_latest_version(opts)
       get_npm_version('ramda', opts)
     end

From 54d3b88bb18528a912d3a6b403401cc188c83049 Mon Sep 17 00:00:00 2001
From: spamguy <spamguy@spamguy.org>
Date: Fri, 13 Jun 2025 12:46:28 -0700
Subject: [PATCH 344/384] Add entries for function calls and operators

---
 lib/docs/filters/zsh/entries.rb | 43 +++++++++++++++++++++++++++++----
 lib/docs/scrapers/zsh.rb        |  2 +-
 2 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/lib/docs/filters/zsh/entries.rb b/lib/docs/filters/zsh/entries.rb
index e6bc07305e..02e7dc9602 100644
--- a/lib/docs/filters/zsh/entries.rb
+++ b/lib/docs/filters/zsh/entries.rb
@@ -7,20 +7,53 @@ def get_name
 
       def additional_entries
         entries = []
-
+        used_fns = []
+        
         css('h2.section').each do |node|
           type = get_type
-
           # Linkable anchor sits above <h2>.
           a = node.xpath('preceding-sibling::a').last
           header_text = extract_header_text(node.content)
 
-          if type == 'Zsh Modules'
-            module_name = header_text.match(/The (zsh\/.*) Module/)&.captures&.first
+          case type
+          when 'Zsh Modules'
+            module_name = header_text.match(/The (zsh\/.* Module)/)&.captures&.first
             header_text = module_name if module_name.present?
+          when 'Calendar Function System'
+            header_text << ' (Calendar)'
           end
 
-          entries << [header_text, a['name'], type] if header_text != 'Description'
+          entries << [header_text, a['name'], type] unless header_text.start_with?('Description')
+        end
+
+        # Functions are documented within <dl> elements.
+        # Names are wrapped in <dt>, details within <dd>.
+        # <dd> can also contain anchors for the next function.
+        doc.css('> dl').each do |node|
+          type = get_type
+          fn_names = node.css('> dt')
+          node.css('dd a[name]').each_with_index do |anchor, i|
+            if fn_names[i].present? && anchor['name'].present?
+              fn_names[i]['id'] = anchor['name']
+
+              # Groups of functions are sometimes comma-delimited.
+              # Strip arguments, flags, etc. from function name.
+              # Skip flag-only headers.
+              fn_names[i].inner_html.split(', ').each do |fn|
+                fn.gsub!(/<(?:tt|var)>(.+?)<\/(?:tt|var)>/, '\1')
+                fn = fn.split(' ').first
+                fn.gsub!(/(?:[\[\(]).*(?:[\]\)]).*$/, '')
+
+                # Add context for operators.
+                fn << " (#{type})" if fn.length == 1
+
+                if fn.present? && !fn.match?(/^[\-\[]/) && !used_fns.include?(fn)
+                  used_fns << fn
+                  entries << [fn, anchor['name'], type]
+                end
+              end
+            end
+          end
         end
 
         entries
diff --git a/lib/docs/scrapers/zsh.rb b/lib/docs/scrapers/zsh.rb
index 82423d34f2..b4705960b3 100644
--- a/lib/docs/scrapers/zsh.rb
+++ b/lib/docs/scrapers/zsh.rb
@@ -27,7 +27,7 @@ class Zsh < UrlScraper
 
     def get_latest_version(opts)
       body = fetch('https://zsh.sourceforge.io/Doc/Release', opts)
-      body.scan(/, Zsh version ([0-9.]+)/)[0][0][0...-1]
+      body.scan(/Zsh version ([0-9.]+)/)[0][0]
     end
   end
 end

From b29a3c8c28500bd8bccd5fd36ac27d279aa6fde0 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 27 Jun 2025 21:27:39 +0200
Subject: [PATCH 345/384] zsh: add news entry

---
 assets/javascripts/news.json | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index 3ddc39a516..2c5c71680c 100644
--- a/assets/javascripts/news.json
+++ b/assets/javascripts/news.json
@@ -1,4 +1,8 @@
 [
+  [
+    "2025-06-27",
+    "New documentation: <a href=\"/zsh/\">Zsh</a>"
+  ],
   [
     "2025-05-28",
     "New documentation: <a href=\"/vertx/\">Vert.x</a>"

From 57a9f0ccbb0099985725e67556353e5772357792 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 27 Jun 2025 21:33:50 +0200
Subject: [PATCH 346/384] Update Ramda documentation (0.31.3)

---
 lib/docs/scrapers/ramda.rb | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/lib/docs/scrapers/ramda.rb b/lib/docs/scrapers/ramda.rb
index 03494eb77d..09a367f6df 100644
--- a/lib/docs/scrapers/ramda.rb
+++ b/lib/docs/scrapers/ramda.rb
@@ -10,17 +10,12 @@ class Ramda < UrlScraper
 
     options[:title] = 'Ramda'
     options[:attribution] = <<-HTML
-      &copy; 2013&ndash;2024 Scott Sauyet and Michael Hurley<br>
+      &copy; 2013&ndash;2025 Scott Sauyet and Michael Hurley<br>
       Licensed under the MIT License.
     HTML
 
-    version '0.30' do
-      self.release = '0.30.1'
-      self.base_url = "https://ramdajs.com/#{release}/docs/"
-    end
-
-    version '0.29' do
-      self.release = '0.29.1'
+    version do
+      self.release = '0.31.3'
       self.base_url = "https://ramdajs.com/#{release}/docs/"
     end
 

From 2a2c11bd108287c1c055a538c1f2579839ba0c91 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 27 Jun 2025 21:50:05 +0200
Subject: [PATCH 347/384] Update Rust documentation (1.88.0)

Fixes #2510.
---
 lib/docs/filters/rust/entries.rb | 6 ++++--
 lib/docs/scrapers/rust.rb        | 2 +-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/lib/docs/filters/rust/entries.rb b/lib/docs/filters/rust/entries.rb
index db795cb75b..31fa47ba9a 100644
--- a/lib/docs/filters/rust/entries.rb
+++ b/lib/docs/filters/rust/entries.rb
@@ -4,8 +4,10 @@ class EntriesFilter < Docs::EntriesFilter
 
       def get_name
         if slug.start_with?('book') || slug.start_with?('reference')
-          name = at_css("#sidebar a[href='#{File.basename(slug)}']")
-          name ? name.content : 'Introduction'
+          name = at_css("h2", "h1")
+          ch1 = slug[/ch(\d+)-(\d+)/, 1]
+          ch2 = slug[/ch(\d+)-(\d+)/, 2]
+          name ? "#{ch1}.#{ch2}. #{name.content}" : 'Introduction'
         elsif slug == 'error-index'
           'Compiler Errors'
         else
diff --git a/lib/docs/scrapers/rust.rb b/lib/docs/scrapers/rust.rb
index e53c8548a0..8ccdaea376 100644
--- a/lib/docs/scrapers/rust.rb
+++ b/lib/docs/scrapers/rust.rb
@@ -3,7 +3,7 @@
 module Docs
   class Rust < UrlScraper
     self.type = 'rust'
-    self.release = '1.87.0'
+    self.release = '1.88.0'
     self.base_url = 'https://doc.rust-lang.org/'
     self.root_path = 'book/index.html'
     self.initial_paths = %w(

From 0fbfafc865f22ebacbd49cc8293a050056a81817 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 1 Jul 2025 18:38:24 +0200
Subject: [PATCH 348/384] Update nginx documentation (1.29.0)

---
 lib/docs/scrapers/nginx.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/nginx.rb b/lib/docs/scrapers/nginx.rb
index 3e401c6362..e7af592414 100644
--- a/lib/docs/scrapers/nginx.rb
+++ b/lib/docs/scrapers/nginx.rb
@@ -2,7 +2,7 @@ module Docs
   class Nginx < UrlScraper
     self.name = 'nginx'
     self.type = 'nginx'
-    self.release = '1.27.1'
+    self.release = '1.29.0'
     self.base_url = 'https://nginx.org/en/docs/'
     self.links = {
       home: 'https://nginx.org/',
@@ -23,7 +23,7 @@ class Nginx < UrlScraper
     # http://nginx.org/LICENSE
     options[:attribution] = <<-HTML
       &copy; 2002-2021 Igor Sysoev<br>
-      &copy; 2011-2024 Nginx, Inc.<br>
+      &copy; 2011-2025 Nginx, Inc.<br>
       Licensed under the BSD License.
     HTML
 

From 25ac4ef5b6ce41749bc7c3fedce614cac6a124d5 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 1 Jul 2025 18:40:08 +0200
Subject: [PATCH 349/384] Update Vite documentation (7.0.0)

---
 lib/docs/scrapers/vite.rb | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vite.rb b/lib/docs/scrapers/vite.rb
index ee26d8b9c6..c02b85d894 100644
--- a/lib/docs/scrapers/vite.rb
+++ b/lib/docs/scrapers/vite.rb
@@ -22,10 +22,15 @@ class Vite < UrlScraper
     html_filters.push 'vite/entries', 'vite/clean_html'
 
     version do
-      self.release = '6.3.2'
+      self.release = '7.0.0'
       self.base_url = 'https://vite.dev/'
     end
 
+    version '6' do
+      self.release = '6.3.5'
+      self.base_url = 'https://v6.vite.dev/'
+    end
+
     version '5' do
       self.release = '5.4.11'
       self.base_url = 'https://v5.vite.dev/'

From 21927ee529bf5aa2ae46d71c753254a333dc8b9c Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 1 Jul 2025 18:41:21 +0200
Subject: [PATCH 350/384] Update Playwright documentation (1.53.2)

---
 lib/docs/scrapers/playwright.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/playwright.rb b/lib/docs/scrapers/playwright.rb
index 57f908a4b2..8726f2f0b6 100644
--- a/lib/docs/scrapers/playwright.rb
+++ b/lib/docs/scrapers/playwright.rb
@@ -2,7 +2,7 @@ module Docs
   class Playwright < UrlScraper
     self.name = 'Playwright'
     self.type = 'simple'
-    self.release = '1.52.0'
+    self.release = '1.53.2'
     self.base_url = 'https://playwright.dev/docs/'
     self.root_path = 'intro'
     self.links = {

From 63e0ed3b141b5dad40483ba6743e7bbb7523e614 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 1 Jul 2025 18:44:19 +0200
Subject: [PATCH 351/384] Update Astro documentation (5.10.2)

---
 lib/docs/scrapers/astro.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/astro.rb b/lib/docs/scrapers/astro.rb
index ef2e3e6a7b..40c496e15e 100644
--- a/lib/docs/scrapers/astro.rb
+++ b/lib/docs/scrapers/astro.rb
@@ -16,7 +16,7 @@ class Astro < UrlScraper
 
     options[:skip_patterns] = [/tutorial/, /getting-started/]
 
-    self.release = '4.14.2'
+    self.release = '5.10.2'
     self.base_url = 'https://docs.astro.build/en/'
     self.initial_paths = %w(install-and-setup/)
 

From 9117c2d2d3521d23c10b6840a44552c70164d810 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 1 Jul 2025 18:51:03 +0200
Subject: [PATCH 352/384] Update Git documentation (2.50.0)

---
 lib/docs/scrapers/git.rb | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/lib/docs/scrapers/git.rb b/lib/docs/scrapers/git.rb
index a3a0fff89b..ae04f9bc2b 100644
--- a/lib/docs/scrapers/git.rb
+++ b/lib/docs/scrapers/git.rb
@@ -1,9 +1,37 @@
 module Docs
   class Git < UrlScraper
     self.type = 'git'
-    self.release = '2.48.1'
+    self.release = '2.50.0'
     self.base_url = 'https://git-scm.com/docs'
-    self.initial_paths = %w(/git.html)
+    self.initial_paths = %w(
+      /git.html
+      /git-archimport.html
+      /git-cherry.html
+      /git-citool.html
+      /git-column.html
+      /git-cvsexportcommit.html
+      /git-for-each-repo.html
+      /git-get-tar-commit-id.html
+      /git-http-fetch.html
+      /git-http-push.html
+      /git-merge-file.html
+      /git-merge-index.html
+      /git-merge-one-file.html
+      /git-merge-tree.html
+      /git-mktree.html
+      /git-p4.html
+      /git-pack-redundant.html
+      /git-quiltimport.html
+      /git-replay.html
+      /git-sh-i18n.html
+      /git-sh-i18n--envsubst.html
+      /git-sh-setup.html
+      /git-show-index.html
+      /git-unpack-file.html
+      /git-verify-commit.html
+      /gitformat-index.html
+      /scalar.html
+    )
     self.links = {
       home: 'https://git-scm.com/',
       code: 'https://github.com/git/git'
@@ -16,9 +44,9 @@ class Git < UrlScraper
     options[:skip] = %w(/howto-index.html)
 
     # https://github.com/git/git?tab=License-1-ov-file#readme
-    # NOT https://github.com/git/git-scm.com/blob/main/MIT-LICENSE.txt
+    # NOT https://github.com/git/git-scm.com/blob/gh-pages/MIT-LICENSE.txt
     options[:attribution] = <<-HTML
-      &copy; 2005&ndash;2024 Linus Torvalds and others<br>
+      &copy; 2005&ndash;2025 Linus Torvalds and others<br>
       Licensed under the GNU General Public License version 2.
     HTML
 

From 03bd6a05bd5cc0572b4baa81d6789ed58f597c4f Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 1 Jul 2025 18:52:09 +0200
Subject: [PATCH 353/384] Update Prettier documentation (3.6.2)

---
 lib/docs/scrapers/prettier.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/prettier.rb b/lib/docs/scrapers/prettier.rb
index 5e6e0757a2..888a042582 100644
--- a/lib/docs/scrapers/prettier.rb
+++ b/lib/docs/scrapers/prettier.rb
@@ -2,7 +2,7 @@ module Docs
   class Prettier < UrlScraper
     self.name = 'Prettier'
     self.type = 'simple'
-    self.release = '3.5.3'
+    self.release = '3.6.2'
     self.base_url = 'https://prettier.io/docs/'
     self.links = {
       home: 'https://prettier.io/',

From 0848782f676081bd24f2563f66aa7aa913e281cf Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 1 Jul 2025 19:14:18 +0200
Subject: [PATCH 354/384] Update Python documentation (3.13.5)

---
 lib/docs/scrapers/python.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/python.rb b/lib/docs/scrapers/python.rb
index 781b0df9a2..fa4ca6dbe8 100644
--- a/lib/docs/scrapers/python.rb
+++ b/lib/docs/scrapers/python.rb
@@ -28,7 +28,7 @@ class Python < UrlScraper
     HTML
 
     version '3.13' do
-      self.release = '3.13.2'
+      self.release = '3.13.5'
       self.base_url = "https://docs.python.org/#{self.version}/"
 
       html_filters.push 'python/entries_v3', 'sphinx/clean_html', 'python/clean_html'

From c05928e89f303a34ce22897119532551226a2815 Mon Sep 17 00:00:00 2001
From: spamguy <spamguy@spamguy.org>
Date: Fri, 27 Jun 2025 12:01:51 -0700
Subject: [PATCH 355/384] Add Tailwind CSS v4 and revise v3

---
 lib/docs/filters/tailwindcss/clean_html.rb | 73 +++++++++++++++-------
 lib/docs/filters/tailwindcss/entries.rb    | 25 ++++++--
 lib/docs/scrapers/tailwindcss.rb           | 67 +++++++++++++-------
 3 files changed, 114 insertions(+), 51 deletions(-)

diff --git a/lib/docs/filters/tailwindcss/clean_html.rb b/lib/docs/filters/tailwindcss/clean_html.rb
index 9815cf090a..bdab80b912 100644
--- a/lib/docs/filters/tailwindcss/clean_html.rb
+++ b/lib/docs/filters/tailwindcss/clean_html.rb
@@ -2,26 +2,38 @@ module Docs
   class Tailwindcss
     class CleanHtmlFilter < Filter
       def call
+        # Move h1 out of wrapper.
+        css('h1').each do |node|
+          doc.prepend_child(node)
+        end
+
         # Remove main page headers (top level sticky)
-        css('#__next > .sticky').remove
+        css('#__next > .sticky', 'div.fixed.inset-x-0.top-0').remove
         # And anything absolutely positioned (fancy floating navigation elements we don't care about)
-        css('#__next .absolute').remove
+        css('#__next .absolute', '.fixed').remove
         # Remove the left-navigation we scraped
         css('nav').remove
 
         css('svg').remove if root_page?
 
-        # Remove the duplicate category name at the top of the page - redundant
-        at_css('header#header > div:first-child > p:first-child').remove
-
         # Remove the right navigation sidebar
-        at_css('header#header').parent.css('> div:has(h5:contains("On this page"))').remove
+        css('header#header', 'p[data-section]').each do |node|
+          node.parent.css('> div:has(h5:contains("On this page"))').remove # v3
+
+          node.parent.parent.css('div.max-xl\\:hidden').remove # v4
+        end
+
+        # Remove the duplicate category name at the top of the page - redundant
+        css(
+          'header#header > div:first-child > p:first-child', # v3
+          'p[data-section]' # v4
+        ).remove
 
         # Remove footer + prev/next navigation
-        at_css('footer').remove
+        css('footer', '.row-start-5').remove
 
         # Handle long lists of class reference that otherwise span several scrolled pages
-        if class_reference = at_css('#class-reference')
+        if class_reference = at_css('#class-reference', '#quick-reference')
           reference_container = class_reference.parent
           classes_container = reference_container.children.reject{ |child| child == class_reference }.first
 
@@ -33,7 +45,7 @@ def call
         end
 
         # Remove border color preview column as it isn't displayed anyway
-        if result[:path] == "border-color" and class_reference = at_css('#class-reference')
+        if result[:path] == "border-color" and class_reference = at_css('#class-reference', '#quick-reference')
           class_reference.parent.css("thead th:nth-child(3)").remove
           class_reference.parent.css("tbody td:nth-child(3)").remove
         end
@@ -59,29 +71,48 @@ def call
         end
 
         # Remove buttons to expand lists - those are already expanded and the button is useless
-        css('div > button:contains("Show all classes")').each do |node|
+        css(
+          'div > button:contains("Show all classes")',
+          'div > button:contains("Show more")'
+        ).each do |node|
           node.parent.remove
         end
 
         # Remove class examples - not part of devdocs styleguide? (similar to bootstrap)
         # Refer to https://github.com/freeCodeCamp/devdocs/pull/1534#pullrequestreview-649818936
-        css('.not-prose').each do |node|
-          if node.parent.children.length == 1
-            node.parent.remove
-          else
-            node.remove
-          end
-        end
+        css('.mt-4.-mb-3', 'figure', 'svg', '.flex.space-x-2').remove
 
-        # Properly format code examples
+        # Properly format code examples.
         css('pre > code:first-child').each do |node|
-          node.parent['data-language'] = node['class'][/language-(\w+)/, 1] if node['class'] and node['class'][/language-(\w+)/]
-          node.parent.content = node.parent.content
+          # v4 doesn't provide language context, so it must be inferred imperfectly.
+          node.parent['data-language'] =
+            if node.content.include?('function')
+              'jsx'
+            elsif node.content.include?("</")
+              'html'
+            else
+              'css'
+            end
+
+          node.parent.content =
+            if version == '3'
+              node.parent.content
+            else
+              node.css('.line').map(&:content).join("\n")
+            end
+        end
+
+        # Remove headers some code examples have.
+        css('.flex.text-slate-400.text-xs.leading-6', '.px-3.pt-0\\.5.pb-1\\.5').remove
+
+        # Strip anchor from headers
+        css('h2', 'h3').each do |node|
+          node.content = node.inner_text
         end
 
         @doc.traverse { |node| cleanup_tailwind_classes(node) }
 
-        #remove weird <hr> (https://github.com/damms005/devdocs/commit/8c9fbd859b71a2525b94a35ea994393ce2b6fedb#commitcomment-50091018)
+        # Remove weird <hr> (https://github.com/damms005/devdocs/commit/8c9fbd859b71a2525b94a35ea994393ce2b6fedb#commitcomment-50091018)
         css('hr').remove
 
         doc
diff --git a/lib/docs/filters/tailwindcss/entries.rb b/lib/docs/filters/tailwindcss/entries.rb
index ad0bf7b441..5e95d5a3fb 100644
--- a/lib/docs/filters/tailwindcss/entries.rb
+++ b/lib/docs/filters/tailwindcss/entries.rb
@@ -3,22 +3,35 @@ class Tailwindcss
     class EntriesFilter < Docs::EntriesFilter
       def get_type
         # We are only interested in children list items
-        selector = "nav li li a[href='#{result[:path]}']"
+        
 
-        anchor = at_css(selector)
-        category_list = anchor.ancestors('li')[1]
-        title = category_list.css('h5')
+        anchor = at_css(get_selector)
+        title =
+          if version == '3'
+            anchor.ancestors('li')[1].css('h5')
+          else
+            anchor.ancestors('ul').last.previous_element
+          end
 
         return title.inner_text
       end
 
       def get_name
         # We are only interested in children list items
-        selector = "nav li li a[href='#{result[:path]}']"
-        item = at_css(selector)
+        item = at_css(get_selector)
 
         return item.inner_text
       end
+
+      private
+
+      def get_selector
+        if version == '3'
+          "nav li li a[href='#{result[:path]}']"
+        else
+          "nav li a[href*='#{result[:path]}']"
+        end
+      end
     end
   end
 end
diff --git a/lib/docs/scrapers/tailwindcss.rb b/lib/docs/scrapers/tailwindcss.rb
index 71b84d5f3b..fdf045994c 100644
--- a/lib/docs/scrapers/tailwindcss.rb
+++ b/lib/docs/scrapers/tailwindcss.rb
@@ -3,9 +3,7 @@ class Tailwindcss < UrlScraper
     self.name = 'Tailwind CSS'
     self.type = 'tailwindcss'
     self.slug = 'tailwindcss'
-    self.base_url = 'https://tailwindcss.com/docs'
     self.root_path = '/'
-    self.release = '3.3.2'
     self.links = {
       home: 'https://tailwindcss.com/',
       code: 'https://github.com/tailwindlabs/tailwindcss'
@@ -16,27 +14,6 @@ class Tailwindcss < UrlScraper
     # Disable the clean text filter which removes empty nodes - we'll do it ourselves more selectively
     text_filters.replace("clean_text", "tailwindcss/noop")
 
-    # Fix redirects from older tailwind 2 docs
-    options[:fix_urls] = lambda do |url|
-      if url.include? "installation/"
-        break "/docs/installation"
-      end
-
-      if url.end_with? "/breakpoints"
-        break "/docs/screens#{/#.*$/.match(url)}"
-      end
-      if url.end_with? "/adding-base-styles"
-        break "/docs/adding-custom-styles#adding-base-styles"
-      end
-      if url.end_with? "/ring-opacity"
-        break "/docs/ring-color#changing-the-opacity"
-      end
-
-      if url.match(/\/colors#?/)
-        break "/docs/customizing-colors#{/#.*$/.match(url)}"
-      end
-    end
-
     options[:skip_patterns] = [
       # Skip setup instructions
       /\/browser-support$/,
@@ -49,9 +26,51 @@ class Tailwindcss < UrlScraper
 
     #Obtainable from https://github.com/tailwindlabs/tailwindcss/blob/master/LICENSE
     options[:attribution] = <<-HTML
-      &copy; 2022 Tailwind Labs Inc.
+      &copy; Tailwind Labs Inc.
     HTML
 
+    version do
+      self.release = '4.1.11'
+      self.base_url = 'https://tailwindcss.com/docs'
+
+      # Fix redirects
+      options[:fix_urls] = lambda do |url|
+        if url.include? "installation/"
+          break "/docs/installation"
+        end
+
+        if url.end_with? "text-color"
+          break "/docs/color"
+        end
+      end
+    end
+
+    version '3' do
+      self.release = '3.4.17'
+      self.base_url = 'https://v3.tailwindcss.com/docs'
+
+      # Fix redirects from older tailwind 2 docs
+      options[:fix_urls] = lambda do |url|
+        if url.include? "installation/"
+          break "/docs/installation"
+        end
+
+        if url.end_with? "/breakpoints"
+          break "/docs/screens#{/#.*$/.match(url)}"
+        end
+        if url.end_with? "/adding-base-styles"
+          break "/docs/adding-custom-styles#adding-base-styles"
+        end
+        if url.end_with? "/ring-opacity"
+          break "/docs/ring-color#changing-the-opacity"
+        end
+
+        if url.match(/\/colors#?/)
+          break "/docs/customizing-colors#{/#.*$/.match(url)}"
+        end
+      end
+    end
+
     def get_latest_version(opts)
       get_latest_github_release('tailwindlabs', 'tailwindcss', opts)
     end

From fc86e6eee9266103567315da197ec9adaba19846 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 4 Jul 2025 10:26:39 +0200
Subject: [PATCH 356/384] Update Perl documentation (5.42.0)

---
 lib/docs/scrapers/perl.rb | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/docs/scrapers/perl.rb b/lib/docs/scrapers/perl.rb
index e28f4076ae..2792132b39 100644
--- a/lib/docs/scrapers/perl.rb
+++ b/lib/docs/scrapers/perl.rb
@@ -24,6 +24,11 @@ class Perl < UrlScraper
       The Perl logo is a trademark of the Perl Foundation.
     HTML
 
+    version '5.42' do
+      self.release = '5.42.0'
+      self.base_url = "https://perldoc.perl.org/#{release}/"
+    end
+
     version '5.40' do
       self.release = '5.40.2'
       self.base_url = "https://perldoc.perl.org/#{release}/"

From 06ce9ee6793faeef3746e2e40a7856b7ba866b94 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Fri, 4 Jul 2025 10:35:40 +0200
Subject: [PATCH 357/384] Update pandas documentation (2.3.0)

---
 lib/docs/scrapers/pandas.rb | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/docs/scrapers/pandas.rb b/lib/docs/scrapers/pandas.rb
index c95f75618a..872930d31c 100644
--- a/lib/docs/scrapers/pandas.rb
+++ b/lib/docs/scrapers/pandas.rb
@@ -11,13 +11,15 @@ class Pandas < FileScraper
     options[:skip] = %w(internals.html release.html contributing.html whatsnew.html)
     options[:skip_patterns] = [/whatsnew\//]
 
+    # https://github.com/pandas-dev/pandas/blob/main/LICENSE
     options[:attribution] = <<-HTML
-      &copy; 2008&ndash;2022, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team<br>
+      &copy; 2008&ndash;2011, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team<br>
+      &copy; 2011&ndash;2025, Open source contributors<br>
       Licensed under the 3-clause BSD License.
     HTML
 
     version '2' do
-      self.release = '2.2.2'
+      self.release = '2.3.0'
       self.base_url = "https://pandas.pydata.org/pandas-docs/version/#{self.release}/"
 
       html_filters.push 'pandas/clean_html', 'pandas/entries'

From 18ca208b1d90115350f3b32400fc7e52a02ee9ce Mon Sep 17 00:00:00 2001
From: Chris Roberts <chris.roberts@flightaware.com>
Date: Thu, 10 Jul 2025 03:22:28 +0000
Subject: [PATCH 358/384] Update URLs for tcl_tk and fix version check

---
 lib/docs/scrapers/tcl_tk.rb | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/docs/scrapers/tcl_tk.rb b/lib/docs/scrapers/tcl_tk.rb
index ec9d5ed427..f4dd3f867c 100644
--- a/lib/docs/scrapers/tcl_tk.rb
+++ b/lib/docs/scrapers/tcl_tk.rb
@@ -4,10 +4,10 @@ class TclTk < UrlScraper
     self.type = 'tcl_tk'
     self.slug = 'tcl_tk'
     self.release = '8.6.6'
-    self.base_url = 'https://www.tcl.tk/man/tcl/'
+    self.base_url = 'https://www.tcl-lang.org/man/tcl/'
     self.root_path = 'contents.htm'
     self.links = {
-      home: 'https://www.tcl.tk/',
+      home: 'https://www.tcl-lang.org/',
       code: 'https://sourceforge.net/projects/tcl/files/Tcl/'
     }
 
@@ -27,11 +27,11 @@ class TclTk < UrlScraper
     ]
 
     options[:attribution] = <<-HTML
-      Licensed under <a href="http://tcl.tk/software/tcltk/license.html">Tcl/Tk terms</a>
+      Licensed under <a href="http://www.tcl-lang.org/software/tcltk/license.html">Tcl/Tk terms</a>
     HTML
 
     def get_latest_version(opts)
-      doc = fetch_doc('https://www.tcl.tk/man/tcl/contents.htm', opts)
+      doc = fetch_doc('https://www.tcl-lang.org/man/tcl/', opts)
       doc.at_css('h2').content.scan(/Tk([0-9.]+)/)[0][0]
     end
   end

From 63a1e666e845fddd13641a8e59949aac5aaa4958 Mon Sep 17 00:00:00 2001
From: Chris Roberts <chris.roberts@flightaware.com>
Date: Thu, 10 Jul 2025 04:54:37 +0000
Subject: [PATCH 359/384] Add tcl9.0

---
 lib/docs/scrapers/tcl_tk.rb | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/docs/scrapers/tcl_tk.rb b/lib/docs/scrapers/tcl_tk.rb
index f4dd3f867c..c47e2f1178 100644
--- a/lib/docs/scrapers/tcl_tk.rb
+++ b/lib/docs/scrapers/tcl_tk.rb
@@ -3,9 +3,6 @@ class TclTk < UrlScraper
     self.name = 'Tcl/Tk'
     self.type = 'tcl_tk'
     self.slug = 'tcl_tk'
-    self.release = '8.6.6'
-    self.base_url = 'https://www.tcl-lang.org/man/tcl/'
-    self.root_path = 'contents.htm'
     self.links = {
       home: 'https://www.tcl-lang.org/',
       code: 'https://sourceforge.net/projects/tcl/files/Tcl/'
@@ -30,6 +27,17 @@ class TclTk < UrlScraper
       Licensed under <a href="http://www.tcl-lang.org/software/tcltk/license.html">Tcl/Tk terms</a>
     HTML
 
+    version '8.6' do
+      self.base_url = "https://www.tcl-lang.org/man/tcl#{self.version}/"
+      self.root_path = 'contents.htm'
+      self.release = '8.6.6'
+    end
+
+    version '9.0' do
+      self.base_url = "https://www.tcl-lang.org/man/tcl#{self.version}/"
+      self.release = '9.0.2'
+    end
+
     def get_latest_version(opts)
       doc = fetch_doc('https://www.tcl-lang.org/man/tcl/', opts)
       doc.at_css('h2').content.scan(/Tk([0-9.]+)/)[0][0]

From ceca91ba8d4c044afdf419c4ea5e346251b1dd8f Mon Sep 17 00:00:00 2001
From: Chris Roberts <chris.roberts@flightaware.com>
Date: Thu, 10 Jul 2025 04:55:39 +0000
Subject: [PATCH 360/384] Bump tcl8.6 release

---
 lib/docs/scrapers/tcl_tk.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/tcl_tk.rb b/lib/docs/scrapers/tcl_tk.rb
index c47e2f1178..8aa933c835 100644
--- a/lib/docs/scrapers/tcl_tk.rb
+++ b/lib/docs/scrapers/tcl_tk.rb
@@ -30,7 +30,7 @@ class TclTk < UrlScraper
     version '8.6' do
       self.base_url = "https://www.tcl-lang.org/man/tcl#{self.version}/"
       self.root_path = 'contents.htm'
-      self.release = '8.6.6'
+      self.release = '8.6.16'
     end
 
     version '9.0' do

From e0a0a262569fa385aec19c7b3dc9a7a7952399e3 Mon Sep 17 00:00:00 2001
From: Chris Roberts <chris.roberts@flightaware.com>
Date: Thu, 10 Jul 2025 05:02:13 +0000
Subject: [PATCH 361/384] Fix name of Tcl icon file

---
 public/icons/docs/tcl_tk/{16@2.png => 16@2x.png} | Bin
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename public/icons/docs/tcl_tk/{16@2.png => 16@2x.png} (100%)

diff --git a/public/icons/docs/tcl_tk/16@2.png b/public/icons/docs/tcl_tk/16@2x.png
similarity index 100%
rename from public/icons/docs/tcl_tk/16@2.png
rename to public/icons/docs/tcl_tk/16@2x.png

From 87eb6bfb460403a4732b2b5ef74257c158d19878 Mon Sep 17 00:00:00 2001
From: Chris Roberts <chris.roberts@flightaware.com>
Date: Thu, 10 Jul 2025 05:12:08 +0000
Subject: [PATCH 362/384] Add new tcl logo

---
 public/icons/docs/tcl_tk/16.png    | Bin 387 -> 8925 bytes
 public/icons/docs/tcl_tk/16@2x.png | Bin 853 -> 9520 bytes
 public/icons/docs/tcl_tk/SOURCE    |   2 +-
 3 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/public/icons/docs/tcl_tk/16.png b/public/icons/docs/tcl_tk/16.png
index eb88a3bb08114994a637b09b768157e601e64c83..4485795098485929c7a7085b5dd18baf70c184e1 100644
GIT binary patch
diff --git a/public/icons/docs/tcl_tk/16@2x.png b/public/icons/docs/tcl_tk/16@2x.png
index 3e00d1f6534309b0340bfdf8f9ca0b57516ac1ab..969c355c956ad611dab045191e1170976439f338 100644
GIT binary patch
diff --git a/public/icons/docs/tcl_tk/SOURCE b/public/icons/docs/tcl_tk/SOURCE
index 91f3566f9c..c6aea9ed9a 100644
--- a/public/icons/docs/tcl_tk/SOURCE
+++ b/public/icons/docs/tcl_tk/SOURCE
@@ -1 +1 @@
-https://commons.wikimedia.org/wiki/File:Tcl.svg
+https://www.tcl-lang.org/images/plume.png

From 31cf4af04c3addcb06e12c433a58fb447e41d011 Mon Sep 17 00:00:00 2001
From: Chris Roberts <chris.roberts@flightaware.com>
Date: Wed, 9 Jul 2025 11:50:12 -0500
Subject: [PATCH 363/384] Add tcllib scraper

Tcllib is effectively Tcl's extended stdlib and so is worth including
alongside it. The only issue with this docset is that the `html` module
page is broken because they embed unencoded html tags in bad places,
causing the page to parse incorrectly.
---
 lib/docs/filters/tcllib/clean_html.rb |  36 ++++++++++++++++++++++++
 lib/docs/filters/tcllib/entries.rb    |  22 +++++++++++++++
 lib/docs/filters/tcllib/nop.rb        |   9 ++++++
 lib/docs/scrapers/tcllib.rb           |  39 ++++++++++++++++++++++++++
 public/icons/docs/tcllib/16.png       | Bin 0 -> 387 bytes
 public/icons/docs/tcllib/16@2x.png    | Bin 0 -> 853 bytes
 public/icons/docs/tcllib/SOURCE       |   1 +
 7 files changed, 107 insertions(+)
 create mode 100644 lib/docs/filters/tcllib/clean_html.rb
 create mode 100644 lib/docs/filters/tcllib/entries.rb
 create mode 100644 lib/docs/filters/tcllib/nop.rb
 create mode 100644 lib/docs/scrapers/tcllib.rb
 create mode 100644 public/icons/docs/tcllib/16.png
 create mode 100644 public/icons/docs/tcllib/16@2x.png
 create mode 100644 public/icons/docs/tcllib/SOURCE

diff --git a/lib/docs/filters/tcllib/clean_html.rb b/lib/docs/filters/tcllib/clean_html.rb
new file mode 100644
index 0000000000..b61649b62e
--- /dev/null
+++ b/lib/docs/filters/tcllib/clean_html.rb
@@ -0,0 +1,36 @@
+module Docs
+  class Tcllib
+    class CleanHtmlFilter < Filter
+      def call
+        css("hr").remove()
+        xpath("./div/text()").remove() # Navigation text content e.g. [ | | | ]
+        css("div.markdown > a").remove() # Navigation links
+
+
+        # Fix up ToC links
+        css('a[name]').each do |node|
+          node.parent['id'] = node['name']
+          node.before(node.children).remove unless node['href']
+        end
+
+        # Relies on the above ToC fixup
+        keywords = at_css('#keywords')
+        if !keywords.nil?
+          keywords.next_sibling.remove()
+          keywords.remove()
+          css('a[href="#keywords"]').remove()
+        end
+
+        # Downrank headings for styling
+        css('h2').each do |node|
+          node.name = 'h3'
+        end
+        css('h1').each do |node|
+          node.name = 'h2'
+        end
+
+        doc
+      end
+    end
+  end
+end
diff --git a/lib/docs/filters/tcllib/entries.rb b/lib/docs/filters/tcllib/entries.rb
new file mode 100644
index 0000000000..bcf8c02a58
--- /dev/null
+++ b/lib/docs/filters/tcllib/entries.rb
@@ -0,0 +1,22 @@
+module Docs
+  class Tcllib
+    class EntriesFilter < Docs::EntriesFilter
+      def get_name
+        # The first word after the `NAME` heading
+        name = at_css('h1 + p')
+        return name.content.strip.split[0]
+      end
+
+      def get_type
+        # The types are the categories as indicated on each page (and on the
+        # root page, toc0.md)
+        category = at_css('a[name="category"]')
+        if !category.nil?
+          return category.parent.next.next.content
+        end
+        return 'Unfiled'
+      end
+    end
+  end
+end
+
diff --git a/lib/docs/filters/tcllib/nop.rb b/lib/docs/filters/tcllib/nop.rb
new file mode 100644
index 0000000000..88bd225bd5
--- /dev/null
+++ b/lib/docs/filters/tcllib/nop.rb
@@ -0,0 +1,9 @@
+module Docs
+  class Tcllib
+    class NopFilter < Filter
+      def call
+        doc
+      end
+    end
+  end
+end
diff --git a/lib/docs/scrapers/tcllib.rb b/lib/docs/scrapers/tcllib.rb
new file mode 100644
index 0000000000..02c9a99026
--- /dev/null
+++ b/lib/docs/scrapers/tcllib.rb
@@ -0,0 +1,39 @@
+module Docs
+  class Tcllib < UrlScraper
+    self.name = 'Tcllib'
+    self.type = 'simple'
+    self.slug = 'tcllib'
+    self.release = '2.0'
+    self.base_url = 'https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/'
+    self.root_path = 'toc0.md'
+    self.links = {
+      home: 'https://core.tcl-lang.org/tcllib/doc/trunk/embedded/index.md',
+      code: 'https://sourceforge.net/projects/tcllib/files/tcllib/'
+    }
+
+    html_filters.push 'tcllib/entries', 'tcllib/clean_html', 'title'
+    # The docs have incorrect <base> elements, so we should just skip that
+    html_filters.replace('apply_base_url', 'tcllib/nop')
+
+    options[:root_title] = 'Tcllib Documentation'
+    options[:container] = '.content'
+    options[:skip] = [
+      # Full of broken links, path improperly duplicates "tcllib" segment
+      'tcllib/toc.md',
+      # The other ones aren't terribly useful
+      'toc.md', 'toc1.md', 'toc2.md',
+      # Keyword index
+      'index.md'
+    ]
+
+    options[:attribution] = <<-HTML
+      Licensed under the <a href="https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/devdoc/tcllib_license.md">BSD license</a>
+    HTML
+
+
+    def get_latest_version(opts)
+      doc = fetch_doc('https://core.tcl-lang.org/tcllib/doc/trunk/embedded/index.md', opts)
+      doc.at_css('strong').content.scan(/([0-9.]+)/)[0][0]
+    end
+  end
+end
diff --git a/public/icons/docs/tcllib/16.png b/public/icons/docs/tcllib/16.png
new file mode 100644
index 0000000000000000000000000000000000000000..eb88a3bb08114994a637b09b768157e601e64c83
GIT binary patch
diff --git a/public/icons/docs/tcllib/16@2x.png b/public/icons/docs/tcllib/16@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..3e00d1f6534309b0340bfdf8f9ca0b57516ac1ab
GIT binary patch
diff --git a/public/icons/docs/tcllib/SOURCE b/public/icons/docs/tcllib/SOURCE
new file mode 100644
index 0000000000..91f3566f9c
--- /dev/null
+++ b/public/icons/docs/tcllib/SOURCE
@@ -0,0 +1 @@
+https://commons.wikimedia.org/wiki/File:Tcl.svg

From 52b026e4e074e24487e27f669de07f5b6e456a40 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Thu, 10 Jul 2025 19:59:38 +0200
Subject: [PATCH 364/384] Update Apache HTTP Server documentation (2.4.64)

---
 lib/docs/scrapers/apache.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/apache.rb b/lib/docs/scrapers/apache.rb
index 1fb31640a1..adfc7f56d5 100644
--- a/lib/docs/scrapers/apache.rb
+++ b/lib/docs/scrapers/apache.rb
@@ -3,7 +3,7 @@ class Apache < UrlScraper
     self.name = 'Apache HTTP Server'
     self.slug = 'apache_http_server'
     self.type = 'apache'
-    self.release = '2.4.52'
+    self.release = '2.4.64'
     self.base_url = 'https://httpd.apache.org/docs/2.4/en/'
     self.links = {
       home: 'https://httpd.apache.org/'

From e7d010f8fa8a8f9f86ce3026f5cc83fd3f037f69 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Mon, 14 Jul 2025 07:37:29 +0200
Subject: [PATCH 365/384] tcllib: add news entry

---
 assets/javascripts/news.json | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json
index 1d049a723d..5b79ed9adc 100644
--- a/assets/javascripts/news.json
+++ b/assets/javascripts/news.json
@@ -1,4 +1,8 @@
 [
+  [
+    "2025-07-14",
+    "New documentation: <a href=\"/tcllib/\">Tcllib</a>"
+  ],
   [
     "2025-06-27",
     "New documentation: <a href=\"/zsh/\">Zsh</a>"

From c1495237cb41b4ba7fdaa69b8dfeae1ddcc062dc Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Mon, 14 Jul 2025 07:40:50 +0200
Subject: [PATCH 366/384] tcllib: enable syntax highlighting

---
 assets/javascripts/vendor/prism.js    | 11152 ++++++++++++------------
 lib/docs/filters/tcllib/clean_html.rb |     4 +
 2 files changed, 5377 insertions(+), 5779 deletions(-)

diff --git a/assets/javascripts/vendor/prism.js b/assets/javascripts/vendor/prism.js
index 8eda8d2106..1f4a1b70bf 100644
--- a/assets/javascripts/vendor/prism.js
+++ b/assets/javascripts/vendor/prism.js
@@ -1,14 +1,14 @@
-/* PrismJS 1.29.0
-https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+cmake+coffeescript+crystal+d+dart+diff+django+elixir+erlang+go+groovy+java+json+julia+kotlin+latex+lua+markdown+markup-templating+matlab+nginx+nim+nix+ocaml+perl+php+python+qml+r+jsx+ruby+rust+scss+scala+shell-session+sql+typescript+yaml+zig */
+/* PrismJS 1.30.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+cmake+coffeescript+crystal+d+dart+diff+django+elixir+erlang+go+groovy+java+json+julia+kotlin+latex+lua+markdown+markup-templating+matlab+nginx+nim+nix+ocaml+perl+php+python+qml+r+jsx+ruby+rust+scss+scala+shell-session+sql+tcl+typescript+yaml+zig */
 /// <reference lib="WebWorker"/>
 
-var _self =
-  typeof window !== "undefined"
-    ? window // if in browser
-    : typeof WorkerGlobalScope !== "undefined" &&
-        self instanceof WorkerGlobalScope
-      ? self // if in worker
-      : {}; // if in node js
+var _self = (typeof window !== 'undefined')
+	? window   // if in browser
+	: (
+		(typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
+			? self // if in worker
+			: {}   // if in node js
+	);
 
 /**
  * Prism: Lightweight, robust, elegant syntax highlighting
@@ -19,1260 +19,1200 @@ var _self =
  * @public
  */
 var Prism = (function (_self) {
-  // Private helper vars
-  var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i;
-  var uniqueId = 0;
-
-  // The grammar object for plaintext
-  var plainTextGrammar = {};
-
-  var _ = {
-    /**
-     * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
-     * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
-     * additional languages or plugins yourself.
-     *
-     * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
-     *
-     * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
-     * empty Prism object into the global scope before loading the Prism script like this:
-     *
-     * ```js
-     * window.Prism = window.Prism || {};
-     * Prism.manual = true;
-     * // add a new <script> to load Prism's script
-     * ```
-     *
-     * @default false
-     * @type {boolean}
-     * @memberof Prism
-     * @public
-     */
-    manual: _self.Prism && _self.Prism.manual,
-    /**
-     * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses
-     * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your
-     * own worker, you don't want it to do this.
-     *
-     * By setting this value to `true`, Prism will not add its own listeners to the worker.
-     *
-     * You obviously have to change this value before Prism executes. To do this, you can add an
-     * empty Prism object into the global scope before loading the Prism script like this:
-     *
-     * ```js
-     * window.Prism = window.Prism || {};
-     * Prism.disableWorkerMessageHandler = true;
-     * // Load Prism's script
-     * ```
-     *
-     * @default false
-     * @type {boolean}
-     * @memberof Prism
-     * @public
-     */
-    disableWorkerMessageHandler:
-      _self.Prism && _self.Prism.disableWorkerMessageHandler,
-
-    /**
-     * A namespace for utility methods.
-     *
-     * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
-     * change or disappear at any time.
-     *
-     * @namespace
-     * @memberof Prism
-     */
-    util: {
-      encode: function encode(tokens) {
-        if (tokens instanceof Token) {
-          return new Token(tokens.type, encode(tokens.content), tokens.alias);
-        } else if (Array.isArray(tokens)) {
-          return tokens.map(encode);
-        } else {
-          return tokens
-            .replace(/&/g, "&amp;")
-            .replace(/</g, "&lt;")
-            .replace(/\u00a0/g, " ");
-        }
-      },
-
-      /**
-       * Returns the name of the type of the given value.
-       *
-       * @param {any} o
-       * @returns {string}
-       * @example
-       * type(null)      === 'Null'
-       * type(undefined) === 'Undefined'
-       * type(123)       === 'Number'
-       * type('foo')     === 'String'
-       * type(true)      === 'Boolean'
-       * type([1, 2])    === 'Array'
-       * type({})        === 'Object'
-       * type(String)    === 'Function'
-       * type(/abc+/)    === 'RegExp'
-       */
-      type: function (o) {
-        return Object.prototype.toString.call(o).slice(8, -1);
-      },
-
-      /**
-       * Returns a unique number for the given object. Later calls will still return the same number.
-       *
-       * @param {Object} obj
-       * @returns {number}
-       */
-      objId: function (obj) {
-        if (!obj["__id"]) {
-          Object.defineProperty(obj, "__id", { value: ++uniqueId });
-        }
-        return obj["__id"];
-      },
-
-      /**
-       * Creates a deep clone of the given object.
-       *
-       * The main intended use of this function is to clone language definitions.
-       *
-       * @param {T} o
-       * @param {Record<number, any>} [visited]
-       * @returns {T}
-       * @template T
-       */
-      clone: function deepClone(o, visited) {
-        visited = visited || {};
-
-        var clone;
-        var id;
-        switch (_.util.type(o)) {
-          case "Object":
-            id = _.util.objId(o);
-            if (visited[id]) {
-              return visited[id];
-            }
-            clone = /** @type {Record<string, any>} */ ({});
-            visited[id] = clone;
-
-            for (var key in o) {
-              if (o.hasOwnProperty(key)) {
-                clone[key] = deepClone(o[key], visited);
-              }
-            }
-
-            return /** @type {any} */ (clone);
-
-          case "Array":
-            id = _.util.objId(o);
-            if (visited[id]) {
-              return visited[id];
-            }
-            clone = [];
-            visited[id] = clone;
-
-            /** @type {Array} */ (/** @type {any} */ (o)).forEach(
-              function (v, i) {
-                clone[i] = deepClone(v, visited);
-              },
-            );
-
-            return /** @type {any} */ (clone);
-
-          default:
-            return o;
-        }
-      },
-
-      /**
-       * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
-       *
-       * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
-       *
-       * @param {Element} element
-       * @returns {string}
-       */
-      getLanguage: function (element) {
-        while (element) {
-          var m = lang.exec(element.className);
-          if (m) {
-            return m[1].toLowerCase();
-          }
-          element = element.parentElement;
-        }
-        return "none";
-      },
-
-      /**
-       * Sets the Prism `language-xxxx` class of the given element.
-       *
-       * @param {Element} element
-       * @param {string} language
-       * @returns {void}
-       */
-      setLanguage: function (element, language) {
-        // remove all `language-xxxx` classes
-        // (this might leave behind a leading space)
-        element.className = element.className.replace(RegExp(lang, "gi"), "");
-
-        // add the new `language-xxxx` class
-        // (using `classList` will automatically clean up spaces for us)
-        element.classList.add("language-" + language);
-      },
-
-      /**
-       * Returns the script element that is currently executing.
-       *
-       * This does __not__ work for line script element.
-       *
-       * @returns {HTMLScriptElement | null}
-       */
-      currentScript: function () {
-        if (typeof document === "undefined") {
-          return null;
-        }
-        if (
-          "currentScript" in document &&
-          1 < 2 /* hack to trip TS' flow analysis */
-        ) {
-          return /** @type {any} */ (document.currentScript);
-        }
-
-        // IE11 workaround
-        // we'll get the src of the current script by parsing IE11's error stack trace
-        // this will not work for inline scripts
-
-        try {
-          throw new Error();
-        } catch (err) {
-          // Get file src url from stack. Specifically works with the format of stack traces in IE.
-          // A stack will look like this:
-          //
-          // Error
-          //    at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
-          //    at Global code (http://localhost/components/prism-core.js:606:1)
-
-          var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) ||
-            [])[1];
-          if (src) {
-            var scripts = document.getElementsByTagName("script");
-            for (var i in scripts) {
-              if (scripts[i].src == src) {
-                return scripts[i];
-              }
-            }
-          }
-          return null;
-        }
-      },
-
-      /**
-       * Returns whether a given class is active for `element`.
-       *
-       * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
-       * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
-       * given class is just the given class with a `no-` prefix.
-       *
-       * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
-       * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
-       * ancestors have the given class or the negated version of it, then the default activation will be returned.
-       *
-       * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
-       * version of it, the class is considered active.
-       *
-       * @param {Element} element
-       * @param {string} className
-       * @param {boolean} [defaultActivation=false]
-       * @returns {boolean}
-       */
-      isActive: function (element, className, defaultActivation) {
-        var no = "no-" + className;
-
-        while (element) {
-          var classList = element.classList;
-          if (classList.contains(className)) {
-            return true;
-          }
-          if (classList.contains(no)) {
-            return false;
-          }
-          element = element.parentElement;
-        }
-        return !!defaultActivation;
-      },
-    },
-
-    /**
-     * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
-     *
-     * @namespace
-     * @memberof Prism
-     * @public
-     */
-    languages: {
-      /**
-       * The grammar for plain, unformatted text.
-       */
-      plain: plainTextGrammar,
-      plaintext: plainTextGrammar,
-      text: plainTextGrammar,
-      txt: plainTextGrammar,
-
-      /**
-       * Creates a deep copy of the language with the given id and appends the given tokens.
-       *
-       * If a token in `redef` also appears in the copied language, then the existing token in the copied language
-       * will be overwritten at its original position.
-       *
-       * ## Best practices
-       *
-       * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
-       * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
-       * understand the language definition because, normally, the order of tokens matters in Prism grammars.
-       *
-       * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
-       * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
-       *
-       * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
-       * @param {Grammar} redef The new tokens to append.
-       * @returns {Grammar} The new language created.
-       * @public
-       * @example
-       * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
-       *     // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
-       *     // at its original position
-       *     'comment': { ... },
-       *     // CSS doesn't have a 'color' token, so this token will be appended
-       *     'color': /\b(?:red|green|blue)\b/
-       * });
-       */
-      extend: function (id, redef) {
-        var lang = _.util.clone(_.languages[id]);
-
-        for (var key in redef) {
-          lang[key] = redef[key];
-        }
-
-        return lang;
-      },
-
-      /**
-       * Inserts tokens _before_ another token in a language definition or any other grammar.
-       *
-       * ## Usage
-       *
-       * This helper method makes it easy to modify existing languages. For example, the CSS language definition
-       * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
-       * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
-       * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
-       * this:
-       *
-       * ```js
-       * Prism.languages.markup.style = {
-       *     // token
-       * };
-       * ```
-       *
-       * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
-       * before existing tokens. For the CSS example above, you would use it like this:
-       *
-       * ```js
-       * Prism.languages.insertBefore('markup', 'cdata', {
-       *     'style': {
-       *         // token
-       *     }
-       * });
-       * ```
-       *
-       * ## Special cases
-       *
-       * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
-       * will be ignored.
-       *
-       * This behavior can be used to insert tokens after `before`:
-       *
-       * ```js
-       * Prism.languages.insertBefore('markup', 'comment', {
-       *     'comment': Prism.languages.markup.comment,
-       *     // tokens after 'comment'
-       * });
-       * ```
-       *
-       * ## Limitations
-       *
-       * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
-       * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
-       * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
-       * deleting properties which is necessary to insert at arbitrary positions.
-       *
-       * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
-       * Instead, it will create a new object and replace all references to the target object with the new one. This
-       * can be done without temporarily deleting properties, so the iteration order is well-defined.
-       *
-       * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
-       * you hold the target object in a variable, then the value of the variable will not change.
-       *
-       * ```js
-       * var oldMarkup = Prism.languages.markup;
-       * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
-       *
-       * assert(oldMarkup !== Prism.languages.markup);
-       * assert(newMarkup === Prism.languages.markup);
-       * ```
-       *
-       * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
-       * object to be modified.
-       * @param {string} before The key to insert before.
-       * @param {Grammar} insert An object containing the key-value pairs to be inserted.
-       * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
-       * object to be modified.
-       *
-       * Defaults to `Prism.languages`.
-       * @returns {Grammar} The new grammar object.
-       * @public
-       */
-      insertBefore: function (inside, before, insert, root) {
-        root = root || /** @type {any} */ (_.languages);
-        var grammar = root[inside];
-        /** @type {Grammar} */
-        var ret = {};
-
-        for (var token in grammar) {
-          if (grammar.hasOwnProperty(token)) {
-            if (token == before) {
-              for (var newToken in insert) {
-                if (insert.hasOwnProperty(newToken)) {
-                  ret[newToken] = insert[newToken];
-                }
-              }
-            }
-
-            // Do not insert token which also occur in insert. See #1525
-            if (!insert.hasOwnProperty(token)) {
-              ret[token] = grammar[token];
-            }
-          }
-        }
-
-        var old = root[inside];
-        root[inside] = ret;
-
-        // Update references in other language definitions
-        _.languages.DFS(_.languages, function (key, value) {
-          if (value === old && key != inside) {
-            this[key] = ret;
-          }
-        });
-
-        return ret;
-      },
-
-      // Traverse a language definition with Depth First Search
-      DFS: function DFS(o, callback, type, visited) {
-        visited = visited || {};
-
-        var objId = _.util.objId;
-
-        for (var i in o) {
-          if (o.hasOwnProperty(i)) {
-            callback.call(o, i, o[i], type || i);
-
-            var property = o[i];
-            var propertyType = _.util.type(property);
-
-            if (propertyType === "Object" && !visited[objId(property)]) {
-              visited[objId(property)] = true;
-              DFS(property, callback, null, visited);
-            } else if (propertyType === "Array" && !visited[objId(property)]) {
-              visited[objId(property)] = true;
-              DFS(property, callback, i, visited);
-            }
-          }
-        }
-      },
-    },
-
-    plugins: {},
-
-    /**
-     * This is the most high-level function in Prism’s API.
-     * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
-     * each one of them.
-     *
-     * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
-     *
-     * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
-     * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
-     * @memberof Prism
-     * @public
-     */
-    highlightAll: function (async, callback) {
-      _.highlightAllUnder(document, async, callback);
-    },
-
-    /**
-     * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
-     * {@link Prism.highlightElement} on each one of them.
-     *
-     * The following hooks will be run:
-     * 1. `before-highlightall`
-     * 2. `before-all-elements-highlight`
-     * 3. All hooks of {@link Prism.highlightElement} for each element.
-     *
-     * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
-     * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
-     * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
-     * @memberof Prism
-     * @public
-     */
-    highlightAllUnder: function (container, async, callback) {
-      var env = {
-        callback: callback,
-        container: container,
-        selector:
-          'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code',
-      };
-
-      _.hooks.run("before-highlightall", env);
-
-      env.elements = Array.prototype.slice.apply(
-        env.container.querySelectorAll(env.selector),
-      );
-
-      _.hooks.run("before-all-elements-highlight", env);
-
-      for (var i = 0, element; (element = env.elements[i++]); ) {
-        _.highlightElement(element, async === true, env.callback);
-      }
-    },
-
-    /**
-     * Highlights the code inside a single element.
-     *
-     * The following hooks will be run:
-     * 1. `before-sanity-check`
-     * 2. `before-highlight`
-     * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
-     * 4. `before-insert`
-     * 5. `after-highlight`
-     * 6. `complete`
-     *
-     * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
-     * the element's language.
-     *
-     * @param {Element} element The element containing the code.
-     * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
-     * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
-     * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
-     * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
-     *
-     * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
-     * asynchronous highlighting to work. You can build your own bundle on the
-     * [Download page](https://prismjs.com/download.html).
-     * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
-     * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
-     * @memberof Prism
-     * @public
-     */
-    highlightElement: function (element, async, callback) {
-      // Find language
-      var language = _.util.getLanguage(element);
-      var grammar = _.languages[language];
-
-      // Set language on the element, if not present
-      _.util.setLanguage(element, language);
-
-      // Set language on the parent, for styling
-      var parent = element.parentElement;
-      if (parent && parent.nodeName.toLowerCase() === "pre") {
-        _.util.setLanguage(parent, language);
-      }
-
-      var code = element.textContent;
-
-      var env = {
-        element: element,
-        language: language,
-        grammar: grammar,
-        code: code,
-      };
-
-      function insertHighlightedCode(highlightedCode) {
-        env.highlightedCode = highlightedCode;
-
-        _.hooks.run("before-insert", env);
-
-        env.element.innerHTML = env.highlightedCode;
-
-        _.hooks.run("after-highlight", env);
-        _.hooks.run("complete", env);
-        callback && callback.call(env.element);
-      }
-
-      _.hooks.run("before-sanity-check", env);
-
-      // plugins may change/add the parent/element
-      parent = env.element.parentElement;
-      if (
-        parent &&
-        parent.nodeName.toLowerCase() === "pre" &&
-        !parent.hasAttribute("tabindex")
-      ) {
-        parent.setAttribute("tabindex", "0");
-      }
-
-      if (!env.code) {
-        _.hooks.run("complete", env);
-        callback && callback.call(env.element);
-        return;
-      }
-
-      _.hooks.run("before-highlight", env);
-
-      if (!env.grammar) {
-        insertHighlightedCode(_.util.encode(env.code));
-        return;
-      }
-
-      if (async && _self.Worker) {
-        var worker = new Worker(_.filename);
-
-        worker.onmessage = function (evt) {
-          insertHighlightedCode(evt.data);
-        };
-
-        worker.postMessage(
-          JSON.stringify({
-            language: env.language,
-            code: env.code,
-            immediateClose: true,
-          }),
-        );
-      } else {
-        insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
-      }
-    },
-
-    /**
-     * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
-     * and the language definitions to use, and returns a string with the HTML produced.
-     *
-     * The following hooks will be run:
-     * 1. `before-tokenize`
-     * 2. `after-tokenize`
-     * 3. `wrap`: On each {@link Token}.
-     *
-     * @param {string} text A string with the code to be highlighted.
-     * @param {Grammar} grammar An object containing the tokens to use.
-     *
-     * Usually a language definition like `Prism.languages.markup`.
-     * @param {string} language The name of the language definition passed to `grammar`.
-     * @returns {string} The highlighted HTML.
-     * @memberof Prism
-     * @public
-     * @example
-     * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
-     */
-    highlight: function (text, grammar, language) {
-      var env = {
-        code: text,
-        grammar: grammar,
-        language: language,
-      };
-      _.hooks.run("before-tokenize", env);
-      if (!env.grammar) {
-        throw new Error('The language "' + env.language + '" has no grammar.');
-      }
-      env.tokens = _.tokenize(env.code, env.grammar);
-      _.hooks.run("after-tokenize", env);
-      return Token.stringify(_.util.encode(env.tokens), env.language);
-    },
-
-    /**
-     * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
-     * and the language definitions to use, and returns an array with the tokenized code.
-     *
-     * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
-     *
-     * This method could be useful in other contexts as well, as a very crude parser.
-     *
-     * @param {string} text A string with the code to be highlighted.
-     * @param {Grammar} grammar An object containing the tokens to use.
-     *
-     * Usually a language definition like `Prism.languages.markup`.
-     * @returns {TokenStream} An array of strings and tokens, a token stream.
-     * @memberof Prism
-     * @public
-     * @example
-     * let code = `var foo = 0;`;
-     * let tokens = Prism.tokenize(code, Prism.languages.javascript);
-     * tokens.forEach(token => {
-     *     if (token instanceof Prism.Token && token.type === 'number') {
-     *         console.log(`Found numeric literal: ${token.content}`);
-     *     }
-     * });
-     */
-    tokenize: function (text, grammar) {
-      var rest = grammar.rest;
-      if (rest) {
-        for (var token in rest) {
-          grammar[token] = rest[token];
-        }
-
-        delete grammar.rest;
-      }
-
-      var tokenList = new LinkedList();
-      addAfter(tokenList, tokenList.head, text);
-
-      matchGrammar(text, tokenList, grammar, tokenList.head, 0);
-
-      return toArray(tokenList);
-    },
-
-    /**
-     * @namespace
-     * @memberof Prism
-     * @public
-     */
-    hooks: {
-      all: {},
-
-      /**
-       * Adds the given callback to the list of callbacks for the given hook.
-       *
-       * The callback will be invoked when the hook it is registered for is run.
-       * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
-       *
-       * One callback function can be registered to multiple hooks and the same hook multiple times.
-       *
-       * @param {string} name The name of the hook.
-       * @param {HookCallback} callback The callback function which is given environment variables.
-       * @public
-       */
-      add: function (name, callback) {
-        var hooks = _.hooks.all;
-
-        hooks[name] = hooks[name] || [];
-
-        hooks[name].push(callback);
-      },
-
-      /**
-       * Runs a hook invoking all registered callbacks with the given environment variables.
-       *
-       * Callbacks will be invoked synchronously and in the order in which they were registered.
-       *
-       * @param {string} name The name of the hook.
-       * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
-       * @public
-       */
-      run: function (name, env) {
-        var callbacks = _.hooks.all[name];
-
-        if (!callbacks || !callbacks.length) {
-          return;
-        }
-
-        for (var i = 0, callback; (callback = callbacks[i++]); ) {
-          callback(env);
-        }
-      },
-    },
-
-    Token: Token,
-  };
-  _self.Prism = _;
-
-  // Typescript note:
-  // The following can be used to import the Token type in JSDoc:
-  //
-  //   @typedef {InstanceType<import("./prism-core")["Token"]>} Token
-
-  /**
-   * Creates a new token.
-   *
-   * @param {string} type See {@link Token#type type}
-   * @param {string | TokenStream} content See {@link Token#content content}
-   * @param {string|string[]} [alias] The alias(es) of the token.
-   * @param {string} [matchedStr=""] A copy of the full string this token was created from.
-   * @class
-   * @global
-   * @public
-   */
-  function Token(type, content, alias, matchedStr) {
-    /**
-     * The type of the token.
-     *
-     * This is usually the key of a pattern in a {@link Grammar}.
-     *
-     * @type {string}
-     * @see GrammarToken
-     * @public
-     */
-    this.type = type;
-    /**
-     * The strings or tokens contained by this token.
-     *
-     * This will be a token stream if the pattern matched also defined an `inside` grammar.
-     *
-     * @type {string | TokenStream}
-     * @public
-     */
-    this.content = content;
-    /**
-     * The alias(es) of the token.
-     *
-     * @type {string|string[]}
-     * @see GrammarToken
-     * @public
-     */
-    this.alias = alias;
-    // Copy of the full string this token was created from
-    this.length = (matchedStr || "").length | 0;
-  }
-
-  /**
-   * A token stream is an array of strings and {@link Token Token} objects.
-   *
-   * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
-   * them.
-   *
-   * 1. No adjacent strings.
-   * 2. No empty strings.
-   *
-   *    The only exception here is the token stream that only contains the empty string and nothing else.
-   *
-   * @typedef {Array<string | Token>} TokenStream
-   * @global
-   * @public
-   */
-
-  /**
-   * Converts the given token or token stream to an HTML representation.
-   *
-   * The following hooks will be run:
-   * 1. `wrap`: On each {@link Token}.
-   *
-   * @param {string | Token | TokenStream} o The token or token stream to be converted.
-   * @param {string} language The name of current language.
-   * @returns {string} The HTML representation of the token or token stream.
-   * @memberof Token
-   * @static
-   */
-  Token.stringify = function stringify(o, language) {
-    if (typeof o == "string") {
-      return o;
-    }
-    if (Array.isArray(o)) {
-      var s = "";
-      o.forEach(function (e) {
-        s += stringify(e, language);
-      });
-      return s;
-    }
-
-    var env = {
-      type: o.type,
-      content: stringify(o.content, language),
-      tag: "span",
-      classes: ["token", o.type],
-      attributes: {},
-      language: language,
-    };
-
-    var aliases = o.alias;
-    if (aliases) {
-      if (Array.isArray(aliases)) {
-        Array.prototype.push.apply(env.classes, aliases);
-      } else {
-        env.classes.push(aliases);
-      }
-    }
-
-    _.hooks.run("wrap", env);
-
-    var attributes = "";
-    for (var name in env.attributes) {
-      attributes +=
-        " " +
-        name +
-        '="' +
-        (env.attributes[name] || "").replace(/"/g, "&quot;") +
-        '"';
-    }
-
-    return (
-      "<" +
-      env.tag +
-      ' class="' +
-      env.classes.join(" ") +
-      '"' +
-      attributes +
-      ">" +
-      env.content +
-      "</" +
-      env.tag +
-      ">"
-    );
-  };
-
-  /**
-   * @param {RegExp} pattern
-   * @param {number} pos
-   * @param {string} text
-   * @param {boolean} lookbehind
-   * @returns {RegExpExecArray | null}
-   */
-  function matchPattern(pattern, pos, text, lookbehind) {
-    pattern.lastIndex = pos;
-    var match = pattern.exec(text);
-    if (match && lookbehind && match[1]) {
-      // change the match to remove the text matched by the Prism lookbehind group
-      var lookbehindLength = match[1].length;
-      match.index += lookbehindLength;
-      match[0] = match[0].slice(lookbehindLength);
-    }
-    return match;
-  }
-
-  /**
-   * @param {string} text
-   * @param {LinkedList<string | Token>} tokenList
-   * @param {any} grammar
-   * @param {LinkedListNode<string | Token>} startNode
-   * @param {number} startPos
-   * @param {RematchOptions} [rematch]
-   * @returns {void}
-   * @private
-   *
-   * @typedef RematchOptions
-   * @property {string} cause
-   * @property {number} reach
-   */
-  function matchGrammar(
-    text,
-    tokenList,
-    grammar,
-    startNode,
-    startPos,
-    rematch,
-  ) {
-    for (var token in grammar) {
-      if (!grammar.hasOwnProperty(token) || !grammar[token]) {
-        continue;
-      }
-
-      var patterns = grammar[token];
-      patterns = Array.isArray(patterns) ? patterns : [patterns];
-
-      for (var j = 0; j < patterns.length; ++j) {
-        if (rematch && rematch.cause == token + "," + j) {
-          return;
-        }
-
-        var patternObj = patterns[j];
-        var inside = patternObj.inside;
-        var lookbehind = !!patternObj.lookbehind;
-        var greedy = !!patternObj.greedy;
-        var alias = patternObj.alias;
-
-        if (greedy && !patternObj.pattern.global) {
-          // Without the global flag, lastIndex won't work
-          var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
-          patternObj.pattern = RegExp(patternObj.pattern.source, flags + "g");
-        }
-
-        /** @type {RegExp} */
-        var pattern = patternObj.pattern || patternObj;
-
-        for (
-          // iterate the token list and keep track of the current token/string position
-          var currentNode = startNode.next, pos = startPos;
-          currentNode !== tokenList.tail;
-          pos += currentNode.value.length, currentNode = currentNode.next
-        ) {
-          if (rematch && pos >= rematch.reach) {
-            break;
-          }
-
-          var str = currentNode.value;
-
-          if (tokenList.length > text.length) {
-            // Something went terribly wrong, ABORT, ABORT!
-            return;
-          }
-
-          if (str instanceof Token) {
-            continue;
-          }
-
-          var removeCount = 1; // this is the to parameter of removeBetween
-          var match;
-
-          if (greedy) {
-            match = matchPattern(pattern, pos, text, lookbehind);
-            if (!match || match.index >= text.length) {
-              break;
-            }
-
-            var from = match.index;
-            var to = match.index + match[0].length;
-            var p = pos;
-
-            // find the node that contains the match
-            p += currentNode.value.length;
-            while (from >= p) {
-              currentNode = currentNode.next;
-              p += currentNode.value.length;
-            }
-            // adjust pos (and p)
-            p -= currentNode.value.length;
-            pos = p;
-
-            // the current node is a Token, then the match starts inside another Token, which is invalid
-            if (currentNode.value instanceof Token) {
-              continue;
-            }
-
-            // find the last node which is affected by this match
-            for (
-              var k = currentNode;
-              k !== tokenList.tail && (p < to || typeof k.value === "string");
-              k = k.next
-            ) {
-              removeCount++;
-              p += k.value.length;
-            }
-            removeCount--;
-
-            // replace with the new match
-            str = text.slice(pos, p);
-            match.index -= pos;
-          } else {
-            match = matchPattern(pattern, 0, str, lookbehind);
-            if (!match) {
-              continue;
-            }
-          }
-
-          // eslint-disable-next-line no-redeclare
-          var from = match.index;
-          var matchStr = match[0];
-          var before = str.slice(0, from);
-          var after = str.slice(from + matchStr.length);
-
-          var reach = pos + str.length;
-          if (rematch && reach > rematch.reach) {
-            rematch.reach = reach;
-          }
-
-          var removeFrom = currentNode.prev;
-
-          if (before) {
-            removeFrom = addAfter(tokenList, removeFrom, before);
-            pos += before.length;
-          }
-
-          removeRange(tokenList, removeFrom, removeCount);
-
-          var wrapped = new Token(
-            token,
-            inside ? _.tokenize(matchStr, inside) : matchStr,
-            alias,
-            matchStr,
-          );
-          currentNode = addAfter(tokenList, removeFrom, wrapped);
-
-          if (after) {
-            addAfter(tokenList, currentNode, after);
-          }
-
-          if (removeCount > 1) {
-            // at least one Token object was removed, so we have to do some rematching
-            // this can only happen if the current pattern is greedy
-
-            /** @type {RematchOptions} */
-            var nestedRematch = {
-              cause: token + "," + j,
-              reach: reach,
-            };
-            matchGrammar(
-              text,
-              tokenList,
-              grammar,
-              currentNode.prev,
-              pos,
-              nestedRematch,
-            );
-
-            // the reach might have been extended because of the rematching
-            if (rematch && nestedRematch.reach > rematch.reach) {
-              rematch.reach = nestedRematch.reach;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  /**
-   * @typedef LinkedListNode
-   * @property {T} value
-   * @property {LinkedListNode<T> | null} prev The previous node.
-   * @property {LinkedListNode<T> | null} next The next node.
-   * @template T
-   * @private
-   */
-
-  /**
-   * @template T
-   * @private
-   */
-  function LinkedList() {
-    /** @type {LinkedListNode<T>} */
-    var head = { value: null, prev: null, next: null };
-    /** @type {LinkedListNode<T>} */
-    var tail = { value: null, prev: head, next: null };
-    head.next = tail;
-
-    /** @type {LinkedListNode<T>} */
-    this.head = head;
-    /** @type {LinkedListNode<T>} */
-    this.tail = tail;
-    this.length = 0;
-  }
-
-  /**
-   * Adds a new node with the given value to the list.
-   *
-   * @param {LinkedList<T>} list
-   * @param {LinkedListNode<T>} node
-   * @param {T} value
-   * @returns {LinkedListNode<T>} The added node.
-   * @template T
-   */
-  function addAfter(list, node, value) {
-    // assumes that node != list.tail && values.length >= 0
-    var next = node.next;
-
-    var newNode = { value: value, prev: node, next: next };
-    node.next = newNode;
-    next.prev = newNode;
-    list.length++;
-
-    return newNode;
-  }
-  /**
-   * Removes `count` nodes after the given node. The given node will not be removed.
-   *
-   * @param {LinkedList<T>} list
-   * @param {LinkedListNode<T>} node
-   * @param {number} count
-   * @template T
-   */
-  function removeRange(list, node, count) {
-    var next = node.next;
-    for (var i = 0; i < count && next !== list.tail; i++) {
-      next = next.next;
-    }
-    node.next = next;
-    next.prev = node;
-    list.length -= i;
-  }
-  /**
-   * @param {LinkedList<T>} list
-   * @returns {T[]}
-   * @template T
-   */
-  function toArray(list) {
-    var array = [];
-    var node = list.head.next;
-    while (node !== list.tail) {
-      array.push(node.value);
-      node = node.next;
-    }
-    return array;
-  }
-
-  if (!_self.document) {
-    if (!_self.addEventListener) {
-      // in Node.js
-      return _;
-    }
-
-    if (!_.disableWorkerMessageHandler) {
-      // In worker
-      _self.addEventListener(
-        "message",
-        function (evt) {
-          var message = JSON.parse(evt.data);
-          var lang = message.language;
-          var code = message.code;
-          var immediateClose = message.immediateClose;
-
-          _self.postMessage(_.highlight(code, _.languages[lang], lang));
-          if (immediateClose) {
-            _self.close();
-          }
-        },
-        false,
-      );
-    }
-
-    return _;
-  }
-
-  // Get current script and highlight
-  var script = _.util.currentScript();
-
-  if (script) {
-    _.filename = script.src;
-
-    if (script.hasAttribute("data-manual")) {
-      _.manual = true;
-    }
-  }
-
-  function highlightAutomaticallyCallback() {
-    if (!_.manual) {
-      _.highlightAll();
-    }
-  }
-
-  if (!_.manual) {
-    // If the document state is "loading", then we'll use DOMContentLoaded.
-    // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
-    // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
-    // might take longer one animation frame to execute which can create a race condition where only some plugins have
-    // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
-    // See https://github.com/PrismJS/prism/issues/2102
-    var readyState = document.readyState;
-    if (
-      readyState === "loading" ||
-      (readyState === "interactive" && script && script.defer)
-    ) {
-      document.addEventListener(
-        "DOMContentLoaded",
-        highlightAutomaticallyCallback,
-      );
-    } else {
-      if (requestAnimationFrame) {
-        requestAnimationFrame(highlightAutomaticallyCallback);
-      } else {
-        window.setTimeout(highlightAutomaticallyCallback, 16);
-      }
-    }
-  }
-
-  return _;
-})(_self);
-
-if (typeof module !== "undefined" && module.exports) {
-  module.exports = Prism;
+
+	// Private helper vars
+	var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i;
+	var uniqueId = 0;
+
+	// The grammar object for plaintext
+	var plainTextGrammar = {};
+
+
+	var _ = {
+		/**
+		 * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
+		 * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
+		 * additional languages or plugins yourself.
+		 *
+		 * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
+		 *
+		 * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
+		 * empty Prism object into the global scope before loading the Prism script like this:
+		 *
+		 * ```js
+		 * window.Prism = window.Prism || {};
+		 * Prism.manual = true;
+		 * // add a new <script> to load Prism's script
+		 * ```
+		 *
+		 * @default false
+		 * @type {boolean}
+		 * @memberof Prism
+		 * @public
+		 */
+		manual: _self.Prism && _self.Prism.manual,
+		/**
+		 * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses
+		 * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your
+		 * own worker, you don't want it to do this.
+		 *
+		 * By setting this value to `true`, Prism will not add its own listeners to the worker.
+		 *
+		 * You obviously have to change this value before Prism executes. To do this, you can add an
+		 * empty Prism object into the global scope before loading the Prism script like this:
+		 *
+		 * ```js
+		 * window.Prism = window.Prism || {};
+		 * Prism.disableWorkerMessageHandler = true;
+		 * // Load Prism's script
+		 * ```
+		 *
+		 * @default false
+		 * @type {boolean}
+		 * @memberof Prism
+		 * @public
+		 */
+		disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
+
+		/**
+		 * A namespace for utility methods.
+		 *
+		 * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
+		 * change or disappear at any time.
+		 *
+		 * @namespace
+		 * @memberof Prism
+		 */
+		util: {
+			encode: function encode(tokens) {
+				if (tokens instanceof Token) {
+					return new Token(tokens.type, encode(tokens.content), tokens.alias);
+				} else if (Array.isArray(tokens)) {
+					return tokens.map(encode);
+				} else {
+					return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
+				}
+			},
+
+			/**
+			 * Returns the name of the type of the given value.
+			 *
+			 * @param {any} o
+			 * @returns {string}
+			 * @example
+			 * type(null)      === 'Null'
+			 * type(undefined) === 'Undefined'
+			 * type(123)       === 'Number'
+			 * type('foo')     === 'String'
+			 * type(true)      === 'Boolean'
+			 * type([1, 2])    === 'Array'
+			 * type({})        === 'Object'
+			 * type(String)    === 'Function'
+			 * type(/abc+/)    === 'RegExp'
+			 */
+			type: function (o) {
+				return Object.prototype.toString.call(o).slice(8, -1);
+			},
+
+			/**
+			 * Returns a unique number for the given object. Later calls will still return the same number.
+			 *
+			 * @param {Object} obj
+			 * @returns {number}
+			 */
+			objId: function (obj) {
+				if (!obj['__id']) {
+					Object.defineProperty(obj, '__id', { value: ++uniqueId });
+				}
+				return obj['__id'];
+			},
+
+			/**
+			 * Creates a deep clone of the given object.
+			 *
+			 * The main intended use of this function is to clone language definitions.
+			 *
+			 * @param {T} o
+			 * @param {Record<number, any>} [visited]
+			 * @returns {T}
+			 * @template T
+			 */
+			clone: function deepClone(o, visited) {
+				visited = visited || {};
+
+				var clone; var id;
+				switch (_.util.type(o)) {
+					case 'Object':
+						id = _.util.objId(o);
+						if (visited[id]) {
+							return visited[id];
+						}
+						clone = /** @type {Record<string, any>} */ ({});
+						visited[id] = clone;
+
+						for (var key in o) {
+							if (o.hasOwnProperty(key)) {
+								clone[key] = deepClone(o[key], visited);
+							}
+						}
+
+						return /** @type {any} */ (clone);
+
+					case 'Array':
+						id = _.util.objId(o);
+						if (visited[id]) {
+							return visited[id];
+						}
+						clone = [];
+						visited[id] = clone;
+
+						(/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
+							clone[i] = deepClone(v, visited);
+						});
+
+						return /** @type {any} */ (clone);
+
+					default:
+						return o;
+				}
+			},
+
+			/**
+			 * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
+			 *
+			 * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
+			 *
+			 * @param {Element} element
+			 * @returns {string}
+			 */
+			getLanguage: function (element) {
+				while (element) {
+					var m = lang.exec(element.className);
+					if (m) {
+						return m[1].toLowerCase();
+					}
+					element = element.parentElement;
+				}
+				return 'none';
+			},
+
+			/**
+			 * Sets the Prism `language-xxxx` class of the given element.
+			 *
+			 * @param {Element} element
+			 * @param {string} language
+			 * @returns {void}
+			 */
+			setLanguage: function (element, language) {
+				// remove all `language-xxxx` classes
+				// (this might leave behind a leading space)
+				element.className = element.className.replace(RegExp(lang, 'gi'), '');
+
+				// add the new `language-xxxx` class
+				// (using `classList` will automatically clean up spaces for us)
+				element.classList.add('language-' + language);
+			},
+
+			/**
+			 * Returns the script element that is currently executing.
+			 *
+			 * This does __not__ work for line script element.
+			 *
+			 * @returns {HTMLScriptElement | null}
+			 */
+			currentScript: function () {
+				if (typeof document === 'undefined') {
+					return null;
+				}
+				if (document.currentScript && document.currentScript.tagName === 'SCRIPT' && 1 < 2 /* hack to trip TS' flow analysis */) {
+					return /** @type {any} */ (document.currentScript);
+				}
+
+				// IE11 workaround
+				// we'll get the src of the current script by parsing IE11's error stack trace
+				// this will not work for inline scripts
+
+				try {
+					throw new Error();
+				} catch (err) {
+					// Get file src url from stack. Specifically works with the format of stack traces in IE.
+					// A stack will look like this:
+					//
+					// Error
+					//    at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
+					//    at Global code (http://localhost/components/prism-core.js:606:1)
+
+					var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || [])[1];
+					if (src) {
+						var scripts = document.getElementsByTagName('script');
+						for (var i in scripts) {
+							if (scripts[i].src == src) {
+								return scripts[i];
+							}
+						}
+					}
+					return null;
+				}
+			},
+
+			/**
+			 * Returns whether a given class is active for `element`.
+			 *
+			 * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
+			 * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
+			 * given class is just the given class with a `no-` prefix.
+			 *
+			 * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
+			 * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
+			 * ancestors have the given class or the negated version of it, then the default activation will be returned.
+			 *
+			 * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
+			 * version of it, the class is considered active.
+			 *
+			 * @param {Element} element
+			 * @param {string} className
+			 * @param {boolean} [defaultActivation=false]
+			 * @returns {boolean}
+			 */
+			isActive: function (element, className, defaultActivation) {
+				var no = 'no-' + className;
+
+				while (element) {
+					var classList = element.classList;
+					if (classList.contains(className)) {
+						return true;
+					}
+					if (classList.contains(no)) {
+						return false;
+					}
+					element = element.parentElement;
+				}
+				return !!defaultActivation;
+			}
+		},
+
+		/**
+		 * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
+		 *
+		 * @namespace
+		 * @memberof Prism
+		 * @public
+		 */
+		languages: {
+			/**
+			 * The grammar for plain, unformatted text.
+			 */
+			plain: plainTextGrammar,
+			plaintext: plainTextGrammar,
+			text: plainTextGrammar,
+			txt: plainTextGrammar,
+
+			/**
+			 * Creates a deep copy of the language with the given id and appends the given tokens.
+			 *
+			 * If a token in `redef` also appears in the copied language, then the existing token in the copied language
+			 * will be overwritten at its original position.
+			 *
+			 * ## Best practices
+			 *
+			 * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
+			 * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
+			 * understand the language definition because, normally, the order of tokens matters in Prism grammars.
+			 *
+			 * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
+			 * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
+			 *
+			 * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
+			 * @param {Grammar} redef The new tokens to append.
+			 * @returns {Grammar} The new language created.
+			 * @public
+			 * @example
+			 * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
+			 *     // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
+			 *     // at its original position
+			 *     'comment': { ... },
+			 *     // CSS doesn't have a 'color' token, so this token will be appended
+			 *     'color': /\b(?:red|green|blue)\b/
+			 * });
+			 */
+			extend: function (id, redef) {
+				var lang = _.util.clone(_.languages[id]);
+
+				for (var key in redef) {
+					lang[key] = redef[key];
+				}
+
+				return lang;
+			},
+
+			/**
+			 * Inserts tokens _before_ another token in a language definition or any other grammar.
+			 *
+			 * ## Usage
+			 *
+			 * This helper method makes it easy to modify existing languages. For example, the CSS language definition
+			 * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
+			 * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
+			 * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
+			 * this:
+			 *
+			 * ```js
+			 * Prism.languages.markup.style = {
+			 *     // token
+			 * };
+			 * ```
+			 *
+			 * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
+			 * before existing tokens. For the CSS example above, you would use it like this:
+			 *
+			 * ```js
+			 * Prism.languages.insertBefore('markup', 'cdata', {
+			 *     'style': {
+			 *         // token
+			 *     }
+			 * });
+			 * ```
+			 *
+			 * ## Special cases
+			 *
+			 * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
+			 * will be ignored.
+			 *
+			 * This behavior can be used to insert tokens after `before`:
+			 *
+			 * ```js
+			 * Prism.languages.insertBefore('markup', 'comment', {
+			 *     'comment': Prism.languages.markup.comment,
+			 *     // tokens after 'comment'
+			 * });
+			 * ```
+			 *
+			 * ## Limitations
+			 *
+			 * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
+			 * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
+			 * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
+			 * deleting properties which is necessary to insert at arbitrary positions.
+			 *
+			 * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
+			 * Instead, it will create a new object and replace all references to the target object with the new one. This
+			 * can be done without temporarily deleting properties, so the iteration order is well-defined.
+			 *
+			 * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
+			 * you hold the target object in a variable, then the value of the variable will not change.
+			 *
+			 * ```js
+			 * var oldMarkup = Prism.languages.markup;
+			 * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
+			 *
+			 * assert(oldMarkup !== Prism.languages.markup);
+			 * assert(newMarkup === Prism.languages.markup);
+			 * ```
+			 *
+			 * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
+			 * object to be modified.
+			 * @param {string} before The key to insert before.
+			 * @param {Grammar} insert An object containing the key-value pairs to be inserted.
+			 * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
+			 * object to be modified.
+			 *
+			 * Defaults to `Prism.languages`.
+			 * @returns {Grammar} The new grammar object.
+			 * @public
+			 */
+			insertBefore: function (inside, before, insert, root) {
+				root = root || /** @type {any} */ (_.languages);
+				var grammar = root[inside];
+				/** @type {Grammar} */
+				var ret = {};
+
+				for (var token in grammar) {
+					if (grammar.hasOwnProperty(token)) {
+
+						if (token == before) {
+							for (var newToken in insert) {
+								if (insert.hasOwnProperty(newToken)) {
+									ret[newToken] = insert[newToken];
+								}
+							}
+						}
+
+						// Do not insert token which also occur in insert. See #1525
+						if (!insert.hasOwnProperty(token)) {
+							ret[token] = grammar[token];
+						}
+					}
+				}
+
+				var old = root[inside];
+				root[inside] = ret;
+
+				// Update references in other language definitions
+				_.languages.DFS(_.languages, function (key, value) {
+					if (value === old && key != inside) {
+						this[key] = ret;
+					}
+				});
+
+				return ret;
+			},
+
+			// Traverse a language definition with Depth First Search
+			DFS: function DFS(o, callback, type, visited) {
+				visited = visited || {};
+
+				var objId = _.util.objId;
+
+				for (var i in o) {
+					if (o.hasOwnProperty(i)) {
+						callback.call(o, i, o[i], type || i);
+
+						var property = o[i];
+						var propertyType = _.util.type(property);
+
+						if (propertyType === 'Object' && !visited[objId(property)]) {
+							visited[objId(property)] = true;
+							DFS(property, callback, null, visited);
+						} else if (propertyType === 'Array' && !visited[objId(property)]) {
+							visited[objId(property)] = true;
+							DFS(property, callback, i, visited);
+						}
+					}
+				}
+			}
+		},
+
+		plugins: {},
+
+		/**
+		 * This is the most high-level function in Prism’s API.
+		 * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
+		 * each one of them.
+		 *
+		 * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
+		 *
+		 * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
+		 * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
+		 * @memberof Prism
+		 * @public
+		 */
+		highlightAll: function (async, callback) {
+			_.highlightAllUnder(document, async, callback);
+		},
+
+		/**
+		 * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
+		 * {@link Prism.highlightElement} on each one of them.
+		 *
+		 * The following hooks will be run:
+		 * 1. `before-highlightall`
+		 * 2. `before-all-elements-highlight`
+		 * 3. All hooks of {@link Prism.highlightElement} for each element.
+		 *
+		 * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
+		 * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
+		 * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
+		 * @memberof Prism
+		 * @public
+		 */
+		highlightAllUnder: function (container, async, callback) {
+			var env = {
+				callback: callback,
+				container: container,
+				selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
+			};
+
+			_.hooks.run('before-highlightall', env);
+
+			env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
+
+			_.hooks.run('before-all-elements-highlight', env);
+
+			for (var i = 0, element; (element = env.elements[i++]);) {
+				_.highlightElement(element, async === true, env.callback);
+			}
+		},
+
+		/**
+		 * Highlights the code inside a single element.
+		 *
+		 * The following hooks will be run:
+		 * 1. `before-sanity-check`
+		 * 2. `before-highlight`
+		 * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
+		 * 4. `before-insert`
+		 * 5. `after-highlight`
+		 * 6. `complete`
+		 *
+		 * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
+		 * the element's language.
+		 *
+		 * @param {Element} element The element containing the code.
+		 * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
+		 * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
+		 * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
+		 * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
+		 *
+		 * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
+		 * asynchronous highlighting to work. You can build your own bundle on the
+		 * [Download page](https://prismjs.com/download.html).
+		 * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
+		 * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
+		 * @memberof Prism
+		 * @public
+		 */
+		highlightElement: function (element, async, callback) {
+			// Find language
+			var language = _.util.getLanguage(element);
+			var grammar = _.languages[language];
+
+			// Set language on the element, if not present
+			_.util.setLanguage(element, language);
+
+			// Set language on the parent, for styling
+			var parent = element.parentElement;
+			if (parent && parent.nodeName.toLowerCase() === 'pre') {
+				_.util.setLanguage(parent, language);
+			}
+
+			var code = element.textContent;
+
+			var env = {
+				element: element,
+				language: language,
+				grammar: grammar,
+				code: code
+			};
+
+			function insertHighlightedCode(highlightedCode) {
+				env.highlightedCode = highlightedCode;
+
+				_.hooks.run('before-insert', env);
+
+				env.element.innerHTML = env.highlightedCode;
+
+				_.hooks.run('after-highlight', env);
+				_.hooks.run('complete', env);
+				callback && callback.call(env.element);
+			}
+
+			_.hooks.run('before-sanity-check', env);
+
+			// plugins may change/add the parent/element
+			parent = env.element.parentElement;
+			if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) {
+				parent.setAttribute('tabindex', '0');
+			}
+
+			if (!env.code) {
+				_.hooks.run('complete', env);
+				callback && callback.call(env.element);
+				return;
+			}
+
+			_.hooks.run('before-highlight', env);
+
+			if (!env.grammar) {
+				insertHighlightedCode(_.util.encode(env.code));
+				return;
+			}
+
+			if (async && _self.Worker) {
+				var worker = new Worker(_.filename);
+
+				worker.onmessage = function (evt) {
+					insertHighlightedCode(evt.data);
+				};
+
+				worker.postMessage(JSON.stringify({
+					language: env.language,
+					code: env.code,
+					immediateClose: true
+				}));
+			} else {
+				insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
+			}
+		},
+
+		/**
+		 * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
+		 * and the language definitions to use, and returns a string with the HTML produced.
+		 *
+		 * The following hooks will be run:
+		 * 1. `before-tokenize`
+		 * 2. `after-tokenize`
+		 * 3. `wrap`: On each {@link Token}.
+		 *
+		 * @param {string} text A string with the code to be highlighted.
+		 * @param {Grammar} grammar An object containing the tokens to use.
+		 *
+		 * Usually a language definition like `Prism.languages.markup`.
+		 * @param {string} language The name of the language definition passed to `grammar`.
+		 * @returns {string} The highlighted HTML.
+		 * @memberof Prism
+		 * @public
+		 * @example
+		 * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
+		 */
+		highlight: function (text, grammar, language) {
+			var env = {
+				code: text,
+				grammar: grammar,
+				language: language
+			};
+			_.hooks.run('before-tokenize', env);
+			if (!env.grammar) {
+				throw new Error('The language "' + env.language + '" has no grammar.');
+			}
+			env.tokens = _.tokenize(env.code, env.grammar);
+			_.hooks.run('after-tokenize', env);
+			return Token.stringify(_.util.encode(env.tokens), env.language);
+		},
+
+		/**
+		 * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
+		 * and the language definitions to use, and returns an array with the tokenized code.
+		 *
+		 * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
+		 *
+		 * This method could be useful in other contexts as well, as a very crude parser.
+		 *
+		 * @param {string} text A string with the code to be highlighted.
+		 * @param {Grammar} grammar An object containing the tokens to use.
+		 *
+		 * Usually a language definition like `Prism.languages.markup`.
+		 * @returns {TokenStream} An array of strings and tokens, a token stream.
+		 * @memberof Prism
+		 * @public
+		 * @example
+		 * let code = `var foo = 0;`;
+		 * let tokens = Prism.tokenize(code, Prism.languages.javascript);
+		 * tokens.forEach(token => {
+		 *     if (token instanceof Prism.Token && token.type === 'number') {
+		 *         console.log(`Found numeric literal: ${token.content}`);
+		 *     }
+		 * });
+		 */
+		tokenize: function (text, grammar) {
+			var rest = grammar.rest;
+			if (rest) {
+				for (var token in rest) {
+					grammar[token] = rest[token];
+				}
+
+				delete grammar.rest;
+			}
+
+			var tokenList = new LinkedList();
+			addAfter(tokenList, tokenList.head, text);
+
+			matchGrammar(text, tokenList, grammar, tokenList.head, 0);
+
+			return toArray(tokenList);
+		},
+
+		/**
+		 * @namespace
+		 * @memberof Prism
+		 * @public
+		 */
+		hooks: {
+			all: {},
+
+			/**
+			 * Adds the given callback to the list of callbacks for the given hook.
+			 *
+			 * The callback will be invoked when the hook it is registered for is run.
+			 * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
+			 *
+			 * One callback function can be registered to multiple hooks and the same hook multiple times.
+			 *
+			 * @param {string} name The name of the hook.
+			 * @param {HookCallback} callback The callback function which is given environment variables.
+			 * @public
+			 */
+			add: function (name, callback) {
+				var hooks = _.hooks.all;
+
+				hooks[name] = hooks[name] || [];
+
+				hooks[name].push(callback);
+			},
+
+			/**
+			 * Runs a hook invoking all registered callbacks with the given environment variables.
+			 *
+			 * Callbacks will be invoked synchronously and in the order in which they were registered.
+			 *
+			 * @param {string} name The name of the hook.
+			 * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
+			 * @public
+			 */
+			run: function (name, env) {
+				var callbacks = _.hooks.all[name];
+
+				if (!callbacks || !callbacks.length) {
+					return;
+				}
+
+				for (var i = 0, callback; (callback = callbacks[i++]);) {
+					callback(env);
+				}
+			}
+		},
+
+		Token: Token
+	};
+	_self.Prism = _;
+
+
+	// Typescript note:
+	// The following can be used to import the Token type in JSDoc:
+	//
+	//   @typedef {InstanceType<import("./prism-core")["Token"]>} Token
+
+	/**
+	 * Creates a new token.
+	 *
+	 * @param {string} type See {@link Token#type type}
+	 * @param {string | TokenStream} content See {@link Token#content content}
+	 * @param {string|string[]} [alias] The alias(es) of the token.
+	 * @param {string} [matchedStr=""] A copy of the full string this token was created from.
+	 * @class
+	 * @global
+	 * @public
+	 */
+	function Token(type, content, alias, matchedStr) {
+		/**
+		 * The type of the token.
+		 *
+		 * This is usually the key of a pattern in a {@link Grammar}.
+		 *
+		 * @type {string}
+		 * @see GrammarToken
+		 * @public
+		 */
+		this.type = type;
+		/**
+		 * The strings or tokens contained by this token.
+		 *
+		 * This will be a token stream if the pattern matched also defined an `inside` grammar.
+		 *
+		 * @type {string | TokenStream}
+		 * @public
+		 */
+		this.content = content;
+		/**
+		 * The alias(es) of the token.
+		 *
+		 * @type {string|string[]}
+		 * @see GrammarToken
+		 * @public
+		 */
+		this.alias = alias;
+		// Copy of the full string this token was created from
+		this.length = (matchedStr || '').length | 0;
+	}
+
+	/**
+	 * A token stream is an array of strings and {@link Token Token} objects.
+	 *
+	 * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
+	 * them.
+	 *
+	 * 1. No adjacent strings.
+	 * 2. No empty strings.
+	 *
+	 *    The only exception here is the token stream that only contains the empty string and nothing else.
+	 *
+	 * @typedef {Array<string | Token>} TokenStream
+	 * @global
+	 * @public
+	 */
+
+	/**
+	 * Converts the given token or token stream to an HTML representation.
+	 *
+	 * The following hooks will be run:
+	 * 1. `wrap`: On each {@link Token}.
+	 *
+	 * @param {string | Token | TokenStream} o The token or token stream to be converted.
+	 * @param {string} language The name of current language.
+	 * @returns {string} The HTML representation of the token or token stream.
+	 * @memberof Token
+	 * @static
+	 */
+	Token.stringify = function stringify(o, language) {
+		if (typeof o == 'string') {
+			return o;
+		}
+		if (Array.isArray(o)) {
+			var s = '';
+			o.forEach(function (e) {
+				s += stringify(e, language);
+			});
+			return s;
+		}
+
+		var env = {
+			type: o.type,
+			content: stringify(o.content, language),
+			tag: 'span',
+			classes: ['token', o.type],
+			attributes: {},
+			language: language
+		};
+
+		var aliases = o.alias;
+		if (aliases) {
+			if (Array.isArray(aliases)) {
+				Array.prototype.push.apply(env.classes, aliases);
+			} else {
+				env.classes.push(aliases);
+			}
+		}
+
+		_.hooks.run('wrap', env);
+
+		var attributes = '';
+		for (var name in env.attributes) {
+			attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
+		}
+
+		return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
+	};
+
+	/**
+	 * @param {RegExp} pattern
+	 * @param {number} pos
+	 * @param {string} text
+	 * @param {boolean} lookbehind
+	 * @returns {RegExpExecArray | null}
+	 */
+	function matchPattern(pattern, pos, text, lookbehind) {
+		pattern.lastIndex = pos;
+		var match = pattern.exec(text);
+		if (match && lookbehind && match[1]) {
+			// change the match to remove the text matched by the Prism lookbehind group
+			var lookbehindLength = match[1].length;
+			match.index += lookbehindLength;
+			match[0] = match[0].slice(lookbehindLength);
+		}
+		return match;
+	}
+
+	/**
+	 * @param {string} text
+	 * @param {LinkedList<string | Token>} tokenList
+	 * @param {any} grammar
+	 * @param {LinkedListNode<string | Token>} startNode
+	 * @param {number} startPos
+	 * @param {RematchOptions} [rematch]
+	 * @returns {void}
+	 * @private
+	 *
+	 * @typedef RematchOptions
+	 * @property {string} cause
+	 * @property {number} reach
+	 */
+	function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
+		for (var token in grammar) {
+			if (!grammar.hasOwnProperty(token) || !grammar[token]) {
+				continue;
+			}
+
+			var patterns = grammar[token];
+			patterns = Array.isArray(patterns) ? patterns : [patterns];
+
+			for (var j = 0; j < patterns.length; ++j) {
+				if (rematch && rematch.cause == token + ',' + j) {
+					return;
+				}
+
+				var patternObj = patterns[j];
+				var inside = patternObj.inside;
+				var lookbehind = !!patternObj.lookbehind;
+				var greedy = !!patternObj.greedy;
+				var alias = patternObj.alias;
+
+				if (greedy && !patternObj.pattern.global) {
+					// Without the global flag, lastIndex won't work
+					var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
+					patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
+				}
+
+				/** @type {RegExp} */
+				var pattern = patternObj.pattern || patternObj;
+
+				for ( // iterate the token list and keep track of the current token/string position
+					var currentNode = startNode.next, pos = startPos;
+					currentNode !== tokenList.tail;
+					pos += currentNode.value.length, currentNode = currentNode.next
+				) {
+
+					if (rematch && pos >= rematch.reach) {
+						break;
+					}
+
+					var str = currentNode.value;
+
+					if (tokenList.length > text.length) {
+						// Something went terribly wrong, ABORT, ABORT!
+						return;
+					}
+
+					if (str instanceof Token) {
+						continue;
+					}
+
+					var removeCount = 1; // this is the to parameter of removeBetween
+					var match;
+
+					if (greedy) {
+						match = matchPattern(pattern, pos, text, lookbehind);
+						if (!match || match.index >= text.length) {
+							break;
+						}
+
+						var from = match.index;
+						var to = match.index + match[0].length;
+						var p = pos;
+
+						// find the node that contains the match
+						p += currentNode.value.length;
+						while (from >= p) {
+							currentNode = currentNode.next;
+							p += currentNode.value.length;
+						}
+						// adjust pos (and p)
+						p -= currentNode.value.length;
+						pos = p;
+
+						// the current node is a Token, then the match starts inside another Token, which is invalid
+						if (currentNode.value instanceof Token) {
+							continue;
+						}
+
+						// find the last node which is affected by this match
+						for (
+							var k = currentNode;
+							k !== tokenList.tail && (p < to || typeof k.value === 'string');
+							k = k.next
+						) {
+							removeCount++;
+							p += k.value.length;
+						}
+						removeCount--;
+
+						// replace with the new match
+						str = text.slice(pos, p);
+						match.index -= pos;
+					} else {
+						match = matchPattern(pattern, 0, str, lookbehind);
+						if (!match) {
+							continue;
+						}
+					}
+
+					// eslint-disable-next-line no-redeclare
+					var from = match.index;
+					var matchStr = match[0];
+					var before = str.slice(0, from);
+					var after = str.slice(from + matchStr.length);
+
+					var reach = pos + str.length;
+					if (rematch && reach > rematch.reach) {
+						rematch.reach = reach;
+					}
+
+					var removeFrom = currentNode.prev;
+
+					if (before) {
+						removeFrom = addAfter(tokenList, removeFrom, before);
+						pos += before.length;
+					}
+
+					removeRange(tokenList, removeFrom, removeCount);
+
+					var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
+					currentNode = addAfter(tokenList, removeFrom, wrapped);
+
+					if (after) {
+						addAfter(tokenList, currentNode, after);
+					}
+
+					if (removeCount > 1) {
+						// at least one Token object was removed, so we have to do some rematching
+						// this can only happen if the current pattern is greedy
+
+						/** @type {RematchOptions} */
+						var nestedRematch = {
+							cause: token + ',' + j,
+							reach: reach
+						};
+						matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);
+
+						// the reach might have been extended because of the rematching
+						if (rematch && nestedRematch.reach > rematch.reach) {
+							rematch.reach = nestedRematch.reach;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * @typedef LinkedListNode
+	 * @property {T} value
+	 * @property {LinkedListNode<T> | null} prev The previous node.
+	 * @property {LinkedListNode<T> | null} next The next node.
+	 * @template T
+	 * @private
+	 */
+
+	/**
+	 * @template T
+	 * @private
+	 */
+	function LinkedList() {
+		/** @type {LinkedListNode<T>} */
+		var head = { value: null, prev: null, next: null };
+		/** @type {LinkedListNode<T>} */
+		var tail = { value: null, prev: head, next: null };
+		head.next = tail;
+
+		/** @type {LinkedListNode<T>} */
+		this.head = head;
+		/** @type {LinkedListNode<T>} */
+		this.tail = tail;
+		this.length = 0;
+	}
+
+	/**
+	 * Adds a new node with the given value to the list.
+	 *
+	 * @param {LinkedList<T>} list
+	 * @param {LinkedListNode<T>} node
+	 * @param {T} value
+	 * @returns {LinkedListNode<T>} The added node.
+	 * @template T
+	 */
+	function addAfter(list, node, value) {
+		// assumes that node != list.tail && values.length >= 0
+		var next = node.next;
+
+		var newNode = { value: value, prev: node, next: next };
+		node.next = newNode;
+		next.prev = newNode;
+		list.length++;
+
+		return newNode;
+	}
+	/**
+	 * Removes `count` nodes after the given node. The given node will not be removed.
+	 *
+	 * @param {LinkedList<T>} list
+	 * @param {LinkedListNode<T>} node
+	 * @param {number} count
+	 * @template T
+	 */
+	function removeRange(list, node, count) {
+		var next = node.next;
+		for (var i = 0; i < count && next !== list.tail; i++) {
+			next = next.next;
+		}
+		node.next = next;
+		next.prev = node;
+		list.length -= i;
+	}
+	/**
+	 * @param {LinkedList<T>} list
+	 * @returns {T[]}
+	 * @template T
+	 */
+	function toArray(list) {
+		var array = [];
+		var node = list.head.next;
+		while (node !== list.tail) {
+			array.push(node.value);
+			node = node.next;
+		}
+		return array;
+	}
+
+
+	if (!_self.document) {
+		if (!_self.addEventListener) {
+			// in Node.js
+			return _;
+		}
+
+		if (!_.disableWorkerMessageHandler) {
+			// In worker
+			_self.addEventListener('message', function (evt) {
+				var message = JSON.parse(evt.data);
+				var lang = message.language;
+				var code = message.code;
+				var immediateClose = message.immediateClose;
+
+				_self.postMessage(_.highlight(code, _.languages[lang], lang));
+				if (immediateClose) {
+					_self.close();
+				}
+			}, false);
+		}
+
+		return _;
+	}
+
+	// Get current script and highlight
+	var script = _.util.currentScript();
+
+	if (script) {
+		_.filename = script.src;
+
+		if (script.hasAttribute('data-manual')) {
+			_.manual = true;
+		}
+	}
+
+	function highlightAutomaticallyCallback() {
+		if (!_.manual) {
+			_.highlightAll();
+		}
+	}
+
+	if (!_.manual) {
+		// If the document state is "loading", then we'll use DOMContentLoaded.
+		// If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
+		// DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
+		// might take longer one animation frame to execute which can create a race condition where only some plugins have
+		// been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
+		// See https://github.com/PrismJS/prism/issues/2102
+		var readyState = document.readyState;
+		if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
+			document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
+		} else {
+			if (window.requestAnimationFrame) {
+				window.requestAnimationFrame(highlightAutomaticallyCallback);
+			} else {
+				window.setTimeout(highlightAutomaticallyCallback, 16);
+			}
+		}
+	}
+
+	return _;
+
+}(_self));
+
+if (typeof module !== 'undefined' && module.exports) {
+	module.exports = Prism;
 }
 
 // hack for components to work correctly in node.js
-if (typeof global !== "undefined") {
-  global.Prism = Prism;
+if (typeof global !== 'undefined') {
+	global.Prism = Prism;
 }
 
 // some additional documentation/types
@@ -1323,1096 +1263,1007 @@ if (typeof global !== "undefined") {
  * @global
  * @public
  */
+;
 Prism.languages.markup = {
-  comment: {
-    pattern: /<!--(?:(?!<!--)[\s\S])*?-->/,
-    greedy: true,
-  },
-  prolog: {
-    pattern: /<\?[\s\S]+?\?>/,
-    greedy: true,
-  },
-  doctype: {
-    // https://www.w3.org/TR/xml/#NT-doctypedecl
-    pattern:
-      /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,
-    greedy: true,
-    inside: {
-      "internal-subset": {
-        pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/,
-        lookbehind: true,
-        greedy: true,
-        inside: null, // see below
-      },
-      string: {
-        pattern: /"[^"]*"|'[^']*'/,
-        greedy: true,
-      },
-      punctuation: /^<!|>$|[[\]]/,
-      "doctype-tag": /^DOCTYPE/i,
-      name: /[^\s<>'"]+/,
-    },
-  },
-  cdata: {
-    pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
-    greedy: true,
-  },
-  tag: {
-    pattern:
-      /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,
-    greedy: true,
-    inside: {
-      tag: {
-        pattern: /^<\/?[^\s>\/]+/,
-        inside: {
-          punctuation: /^<\/?/,
-          namespace: /^[^\s>\/:]+:/,
-        },
-      },
-      "special-attr": [],
-      "attr-value": {
-        pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
-        inside: {
-          punctuation: [
-            {
-              pattern: /^=/,
-              alias: "attr-equals",
-            },
-            {
-              pattern: /^(\s*)["']|["']$/,
-              lookbehind: true,
-            },
-          ],
-        },
-      },
-      punctuation: /\/?>/,
-      "attr-name": {
-        pattern: /[^\s>\/]+/,
-        inside: {
-          namespace: /^[^\s>\/:]+:/,
-        },
-      },
-    },
-  },
-  entity: [
-    {
-      pattern: /&[\da-z]{1,8};/i,
-      alias: "named-entity",
-    },
-    /&#x?[\da-f]{1,8};/i,
-  ],
+	'comment': {
+		pattern: /<!--(?:(?!<!--)[\s\S])*?-->/,
+		greedy: true
+	},
+	'prolog': {
+		pattern: /<\?[\s\S]+?\?>/,
+		greedy: true
+	},
+	'doctype': {
+		// https://www.w3.org/TR/xml/#NT-doctypedecl
+		pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,
+		greedy: true,
+		inside: {
+			'internal-subset': {
+				pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/,
+				lookbehind: true,
+				greedy: true,
+				inside: null // see below
+			},
+			'string': {
+				pattern: /"[^"]*"|'[^']*'/,
+				greedy: true
+			},
+			'punctuation': /^<!|>$|[[\]]/,
+			'doctype-tag': /^DOCTYPE/i,
+			'name': /[^\s<>'"]+/
+		}
+	},
+	'cdata': {
+		pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
+		greedy: true
+	},
+	'tag': {
+		pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,
+		greedy: true,
+		inside: {
+			'tag': {
+				pattern: /^<\/?[^\s>\/]+/,
+				inside: {
+					'punctuation': /^<\/?/,
+					'namespace': /^[^\s>\/:]+:/
+				}
+			},
+			'special-attr': [],
+			'attr-value': {
+				pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
+				inside: {
+					'punctuation': [
+						{
+							pattern: /^=/,
+							alias: 'attr-equals'
+						},
+						{
+							pattern: /^(\s*)["']|["']$/,
+							lookbehind: true
+						}
+					]
+				}
+			},
+			'punctuation': /\/?>/,
+			'attr-name': {
+				pattern: /[^\s>\/]+/,
+				inside: {
+					'namespace': /^[^\s>\/:]+:/
+				}
+			}
+
+		}
+	},
+	'entity': [
+		{
+			pattern: /&[\da-z]{1,8};/i,
+			alias: 'named-entity'
+		},
+		/&#x?[\da-f]{1,8};/i
+	]
 };
 
-Prism.languages.markup["tag"].inside["attr-value"].inside["entity"] =
-  Prism.languages.markup["entity"];
-Prism.languages.markup["doctype"].inside["internal-subset"].inside =
-  Prism.languages.markup;
+Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] =
+	Prism.languages.markup['entity'];
+Prism.languages.markup['doctype'].inside['internal-subset'].inside = Prism.languages.markup;
 
 // Plugin to make entity title show the real entity, idea by Roman Komarov
-Prism.hooks.add("wrap", function (env) {
-  if (env.type === "entity") {
-    env.attributes["title"] = env.content.replace(/&amp;/, "&");
-  }
+Prism.hooks.add('wrap', function (env) {
+
+	if (env.type === 'entity') {
+		env.attributes['title'] = env.content.replace(/&amp;/, '&');
+	}
 });
 
-Object.defineProperty(Prism.languages.markup.tag, "addInlined", {
-  /**
-   * Adds an inlined language to markup.
-   *
-   * An example of an inlined language is CSS with `<style>` tags.
-   *
-   * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as
-   * case insensitive.
-   * @param {string} lang The language key.
-   * @example
-   * addInlined('style', 'css');
-   */
-  value: function addInlined(tagName, lang) {
-    var includedCdataInside = {};
-    includedCdataInside["language-" + lang] = {
-      pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,
-      lookbehind: true,
-      inside: Prism.languages[lang],
-    };
-    includedCdataInside["cdata"] = /^<!\[CDATA\[|\]\]>$/i;
-
-    var inside = {
-      "included-cdata": {
-        pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
-        inside: includedCdataInside,
-      },
-    };
-    inside["language-" + lang] = {
-      pattern: /[\s\S]+/,
-      inside: Prism.languages[lang],
-    };
-
-    var def = {};
-    def[tagName] = {
-      pattern: RegExp(
-        /(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(
-          /__/g,
-          function () {
-            return tagName;
-          },
-        ),
-        "i",
-      ),
-      lookbehind: true,
-      greedy: true,
-      inside: inside,
-    };
-
-    Prism.languages.insertBefore("markup", "cdata", def);
-  },
+Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
+	/**
+	 * Adds an inlined language to markup.
+	 *
+	 * An example of an inlined language is CSS with `<style>` tags.
+	 *
+	 * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as
+	 * case insensitive.
+	 * @param {string} lang The language key.
+	 * @example
+	 * addInlined('style', 'css');
+	 */
+	value: function addInlined(tagName, lang) {
+		var includedCdataInside = {};
+		includedCdataInside['language-' + lang] = {
+			pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,
+			lookbehind: true,
+			inside: Prism.languages[lang]
+		};
+		includedCdataInside['cdata'] = /^<!\[CDATA\[|\]\]>$/i;
+
+		var inside = {
+			'included-cdata': {
+				pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
+				inside: includedCdataInside
+			}
+		};
+		inside['language-' + lang] = {
+			pattern: /[\s\S]+/,
+			inside: Prism.languages[lang]
+		};
+
+		var def = {};
+		def[tagName] = {
+			pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'),
+			lookbehind: true,
+			greedy: true,
+			inside: inside
+		};
+
+		Prism.languages.insertBefore('markup', 'cdata', def);
+	}
 });
-Object.defineProperty(Prism.languages.markup.tag, "addAttribute", {
-  /**
-   * Adds an pattern to highlight languages embedded in HTML attributes.
-   *
-   * An example of an inlined language is CSS with `style` attributes.
-   *
-   * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as
-   * case insensitive.
-   * @param {string} lang The language key.
-   * @example
-   * addAttribute('style', 'css');
-   */
-  value: function (attrName, lang) {
-    Prism.languages.markup.tag.inside["special-attr"].push({
-      pattern: RegExp(
-        /(^|["'\s])/.source +
-          "(?:" +
-          attrName +
-          ")" +
-          /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,
-        "i",
-      ),
-      lookbehind: true,
-      inside: {
-        "attr-name": /^[^\s=]+/,
-        "attr-value": {
-          pattern: /=[\s\S]+/,
-          inside: {
-            value: {
-              pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
-              lookbehind: true,
-              alias: [lang, "language-" + lang],
-              inside: Prism.languages[lang],
-            },
-            punctuation: [
-              {
-                pattern: /^=/,
-                alias: "attr-equals",
-              },
-              /"|'/,
-            ],
-          },
-        },
-      },
-    });
-  },
+Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', {
+	/**
+	 * Adds an pattern to highlight languages embedded in HTML attributes.
+	 *
+	 * An example of an inlined language is CSS with `style` attributes.
+	 *
+	 * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as
+	 * case insensitive.
+	 * @param {string} lang The language key.
+	 * @example
+	 * addAttribute('style', 'css');
+	 */
+	value: function (attrName, lang) {
+		Prism.languages.markup.tag.inside['special-attr'].push({
+			pattern: RegExp(
+				/(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,
+				'i'
+			),
+			lookbehind: true,
+			inside: {
+				'attr-name': /^[^\s=]+/,
+				'attr-value': {
+					pattern: /=[\s\S]+/,
+					inside: {
+						'value': {
+							pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
+							lookbehind: true,
+							alias: [lang, 'language-' + lang],
+							inside: Prism.languages[lang]
+						},
+						'punctuation': [
+							{
+								pattern: /^=/,
+								alias: 'attr-equals'
+							},
+							/"|'/
+						]
+					}
+				}
+			}
+		});
+	}
 });
 
 Prism.languages.html = Prism.languages.markup;
 Prism.languages.mathml = Prism.languages.markup;
 Prism.languages.svg = Prism.languages.markup;
 
-Prism.languages.xml = Prism.languages.extend("markup", {});
+Prism.languages.xml = Prism.languages.extend('markup', {});
 Prism.languages.ssml = Prism.languages.xml;
 Prism.languages.atom = Prism.languages.xml;
 Prism.languages.rss = Prism.languages.xml;
 
 (function (Prism) {
-  var string =
-    /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;
-
-  Prism.languages.css = {
-    comment: /\/\*[\s\S]*?\*\//,
-    atrule: {
-      pattern: RegExp(
-        "@[\\w-](?:" +
-          /[^;{\s"']|\s+(?!\s)/.source +
-          "|" +
-          string.source +
-          ")*?" +
-          /(?:;|(?=\s*\{))/.source,
-      ),
-      inside: {
-        rule: /^@[\w-]+/,
-        "selector-function-argument": {
-          pattern:
-            /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
-          lookbehind: true,
-          alias: "selector",
-        },
-        keyword: {
-          pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/,
-          lookbehind: true,
-        },
-        // See rest below
-      },
-    },
-    url: {
-      // https://drafts.csswg.org/css-values-3/#urls
-      pattern: RegExp(
-        "\\burl\\((?:" +
-          string.source +
-          "|" +
-          /(?:[^\\\r\n()"']|\\[\s\S])*/.source +
-          ")\\)",
-        "i",
-      ),
-      greedy: true,
-      inside: {
-        function: /^url/i,
-        punctuation: /^\(|\)$/,
-        string: {
-          pattern: RegExp("^" + string.source + "$"),
-          alias: "url",
-        },
-      },
-    },
-    selector: {
-      pattern: RegExp(
-        "(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|" +
-          string.source +
-          ")*(?=\\s*\\{)",
-      ),
-      lookbehind: true,
-    },
-    string: {
-      pattern: string,
-      greedy: true,
-    },
-    property: {
-      pattern:
-        /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,
-      lookbehind: true,
-    },
-    important: /!important\b/i,
-    function: {
-      pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,
-      lookbehind: true,
-    },
-    punctuation: /[(){};:,]/,
-  };
-
-  Prism.languages.css["atrule"].inside.rest = Prism.languages.css;
-
-  var markup = Prism.languages.markup;
-  if (markup) {
-    markup.tag.addInlined("style", "css");
-    markup.tag.addAttribute("style", "css");
-  }
-})(Prism);
+
+	var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;
+
+	Prism.languages.css = {
+		'comment': /\/\*[\s\S]*?\*\//,
+		'atrule': {
+			pattern: RegExp('@[\\w-](?:' + /[^;{\s"']|\s+(?!\s)/.source + '|' + string.source + ')*?' + /(?:;|(?=\s*\{))/.source),
+			inside: {
+				'rule': /^@[\w-]+/,
+				'selector-function-argument': {
+					pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
+					lookbehind: true,
+					alias: 'selector'
+				},
+				'keyword': {
+					pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/,
+					lookbehind: true
+				}
+				// See rest below
+			}
+		},
+		'url': {
+			// https://drafts.csswg.org/css-values-3/#urls
+			pattern: RegExp('\\burl\\((?:' + string.source + '|' + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ')\\)', 'i'),
+			greedy: true,
+			inside: {
+				'function': /^url/i,
+				'punctuation': /^\(|\)$/,
+				'string': {
+					pattern: RegExp('^' + string.source + '$'),
+					alias: 'url'
+				}
+			}
+		},
+		'selector': {
+			pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'),
+			lookbehind: true
+		},
+		'string': {
+			pattern: string,
+			greedy: true
+		},
+		'property': {
+			pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,
+			lookbehind: true
+		},
+		'important': /!important\b/i,
+		'function': {
+			pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,
+			lookbehind: true
+		},
+		'punctuation': /[(){};:,]/
+	};
+
+	Prism.languages.css['atrule'].inside.rest = Prism.languages.css;
+
+	var markup = Prism.languages.markup;
+	if (markup) {
+		markup.tag.addInlined('style', 'css');
+		markup.tag.addAttribute('style', 'css');
+	}
+
+}(Prism));
 
 Prism.languages.clike = {
-  comment: [
-    {
-      pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
-      lookbehind: true,
-      greedy: true,
-    },
-    {
-      pattern: /(^|[^\\:])\/\/.*/,
-      lookbehind: true,
-      greedy: true,
-    },
-  ],
-  string: {
-    pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
-    greedy: true,
-  },
-  "class-name": {
-    pattern:
-      /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,
-    lookbehind: true,
-    inside: {
-      punctuation: /[.\\]/,
-    },
-  },
-  keyword:
-    /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,
-  boolean: /\b(?:false|true)\b/,
-  function: /\b\w+(?=\()/,
-  number: /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
-  operator: /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
-  punctuation: /[{}[\];(),.:]/,
+	'comment': [
+		{
+			pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
+			lookbehind: true,
+			greedy: true
+		},
+		{
+			pattern: /(^|[^\\:])\/\/.*/,
+			lookbehind: true,
+			greedy: true
+		}
+	],
+	'string': {
+		pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
+		greedy: true
+	},
+	'class-name': {
+		pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,
+		lookbehind: true,
+		inside: {
+			'punctuation': /[.\\]/
+		}
+	},
+	'keyword': /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,
+	'boolean': /\b(?:false|true)\b/,
+	'function': /\b\w+(?=\()/,
+	'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
+	'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
+	'punctuation': /[{}[\];(),.:]/
 };
 
-Prism.languages.javascript = Prism.languages.extend("clike", {
-  "class-name": [
-    Prism.languages.clike["class-name"],
-    {
-      pattern:
-        /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,
-      lookbehind: true,
-    },
-  ],
-  keyword: [
-    {
-      pattern: /((?:^|\})\s*)catch\b/,
-      lookbehind: true,
-    },
-    {
-      pattern:
-        /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,
-      lookbehind: true,
-    },
-  ],
-  // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
-  function:
-    /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
-  number: {
-    pattern: RegExp(
-      /(^|[^\w$])/.source +
-        "(?:" +
-        // constant
-        (/NaN|Infinity/.source +
-          "|" +
-          // binary integer
-          /0[bB][01]+(?:_[01]+)*n?/.source +
-          "|" +
-          // octal integer
-          /0[oO][0-7]+(?:_[0-7]+)*n?/.source +
-          "|" +
-          // hexadecimal integer
-          /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source +
-          "|" +
-          // decimal bigint
-          /\d+(?:_\d+)*n/.source +
-          "|" +
-          // decimal number (integer or float) but no bigint
-          /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/
-            .source) +
-        ")" +
-        /(?![\w$])/.source,
-    ),
-    lookbehind: true,
-  },
-  operator:
-    /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/,
+Prism.languages.javascript = Prism.languages.extend('clike', {
+	'class-name': [
+		Prism.languages.clike['class-name'],
+		{
+			pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,
+			lookbehind: true
+		}
+	],
+	'keyword': [
+		{
+			pattern: /((?:^|\})\s*)catch\b/,
+			lookbehind: true
+		},
+		{
+			pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,
+			lookbehind: true
+		},
+	],
+	// Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
+	'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
+	'number': {
+		pattern: RegExp(
+			/(^|[^\w$])/.source +
+			'(?:' +
+			(
+				// constant
+				/NaN|Infinity/.source +
+				'|' +
+				// binary integer
+				/0[bB][01]+(?:_[01]+)*n?/.source +
+				'|' +
+				// octal integer
+				/0[oO][0-7]+(?:_[0-7]+)*n?/.source +
+				'|' +
+				// hexadecimal integer
+				/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source +
+				'|' +
+				// decimal bigint
+				/\d+(?:_\d+)*n/.source +
+				'|' +
+				// decimal number (integer or float) but no bigint
+				/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source
+			) +
+			')' +
+			/(?![\w$])/.source
+		),
+		lookbehind: true
+	},
+	'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/
 });
 
-Prism.languages.javascript["class-name"][0].pattern =
-  /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/;
-
-Prism.languages.insertBefore("javascript", "keyword", {
-  regex: {
-    pattern: RegExp(
-      // lookbehind
-      // eslint-disable-next-line regexp/no-dupe-characters-character-class
-      /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source +
-        // Regex pattern:
-        // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character
-        // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible
-        // with the only syntax, so we have to define 2 different regex patterns.
-        /\//.source +
-        "(?:" +
-        /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/
-          .source +
-        "|" +
-        // `v` flag syntax. This supports 3 levels of nested character classes.
-        /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/
-          .source +
-        ")" +
-        // lookahead
-        /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/
-          .source,
-    ),
-    lookbehind: true,
-    greedy: true,
-    inside: {
-      "regex-source": {
-        pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/,
-        lookbehind: true,
-        alias: "language-regex",
-        inside: Prism.languages.regex,
-      },
-      "regex-delimiter": /^\/|\/$/,
-      "regex-flags": /^[a-z]+$/,
-    },
-  },
-  // This must be declared before keyword because we use "function" inside the look-forward
-  "function-variable": {
-    pattern:
-      /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,
-    alias: "function",
-  },
-  parameter: [
-    {
-      pattern:
-        /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,
-      lookbehind: true,
-      inside: Prism.languages.javascript,
-    },
-    {
-      pattern:
-        /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,
-      lookbehind: true,
-      inside: Prism.languages.javascript,
-    },
-    {
-      pattern:
-        /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,
-      lookbehind: true,
-      inside: Prism.languages.javascript,
-    },
-    {
-      pattern:
-        /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,
-      lookbehind: true,
-      inside: Prism.languages.javascript,
-    },
-  ],
-  constant: /\b[A-Z](?:[A-Z_]|\dx?)*\b/,
+Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/;
+
+Prism.languages.insertBefore('javascript', 'keyword', {
+	'regex': {
+		pattern: RegExp(
+			// lookbehind
+			// eslint-disable-next-line regexp/no-dupe-characters-character-class
+			/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source +
+			// Regex pattern:
+			// There are 2 regex patterns here. The RegExp set notation proposal added support for nested character
+			// classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible
+			// with the only syntax, so we have to define 2 different regex patterns.
+			/\//.source +
+			'(?:' +
+			/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source +
+			'|' +
+			// `v` flag syntax. This supports 3 levels of nested character classes.
+			/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source +
+			')' +
+			// lookahead
+			/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source
+		),
+		lookbehind: true,
+		greedy: true,
+		inside: {
+			'regex-source': {
+				pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/,
+				lookbehind: true,
+				alias: 'language-regex',
+				inside: Prism.languages.regex
+			},
+			'regex-delimiter': /^\/|\/$/,
+			'regex-flags': /^[a-z]+$/,
+		}
+	},
+	// This must be declared before keyword because we use "function" inside the look-forward
+	'function-variable': {
+		pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,
+		alias: 'function'
+	},
+	'parameter': [
+		{
+			pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,
+			lookbehind: true,
+			inside: Prism.languages.javascript
+		},
+		{
+			pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,
+			lookbehind: true,
+			inside: Prism.languages.javascript
+		},
+		{
+			pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,
+			lookbehind: true,
+			inside: Prism.languages.javascript
+		},
+		{
+			pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,
+			lookbehind: true,
+			inside: Prism.languages.javascript
+		}
+	],
+	'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/
 });
 
-Prism.languages.insertBefore("javascript", "string", {
-  hashbang: {
-    pattern: /^#!.*/,
-    greedy: true,
-    alias: "comment",
-  },
-  "template-string": {
-    pattern:
-      /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,
-    greedy: true,
-    inside: {
-      "template-punctuation": {
-        pattern: /^`|`$/,
-        alias: "string",
-      },
-      interpolation: {
-        pattern:
-          /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,
-        lookbehind: true,
-        inside: {
-          "interpolation-punctuation": {
-            pattern: /^\$\{|\}$/,
-            alias: "punctuation",
-          },
-          rest: Prism.languages.javascript,
-        },
-      },
-      string: /[\s\S]+/,
-    },
-  },
-  "string-property": {
-    pattern:
-      /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,
-    lookbehind: true,
-    greedy: true,
-    alias: "property",
-  },
+Prism.languages.insertBefore('javascript', 'string', {
+	'hashbang': {
+		pattern: /^#!.*/,
+		greedy: true,
+		alias: 'comment'
+	},
+	'template-string': {
+		pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,
+		greedy: true,
+		inside: {
+			'template-punctuation': {
+				pattern: /^`|`$/,
+				alias: 'string'
+			},
+			'interpolation': {
+				pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,
+				lookbehind: true,
+				inside: {
+					'interpolation-punctuation': {
+						pattern: /^\$\{|\}$/,
+						alias: 'punctuation'
+					},
+					rest: Prism.languages.javascript
+				}
+			},
+			'string': /[\s\S]+/
+		}
+	},
+	'string-property': {
+		pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,
+		lookbehind: true,
+		greedy: true,
+		alias: 'property'
+	}
 });
 
-Prism.languages.insertBefore("javascript", "operator", {
-  "literal-property": {
-    pattern:
-      /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,
-    lookbehind: true,
-    alias: "property",
-  },
+Prism.languages.insertBefore('javascript', 'operator', {
+	'literal-property': {
+		pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,
+		lookbehind: true,
+		alias: 'property'
+	},
 });
 
 if (Prism.languages.markup) {
-  Prism.languages.markup.tag.addInlined("script", "javascript");
-
-  // add attribute support for all DOM events.
-  // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events
-  Prism.languages.markup.tag.addAttribute(
-    /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/
-      .source,
-    "javascript",
-  );
+	Prism.languages.markup.tag.addInlined('script', 'javascript');
+
+	// add attribute support for all DOM events.
+	// https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events
+	Prism.languages.markup.tag.addAttribute(
+		/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,
+		'javascript'
+	);
 }
 
 Prism.languages.js = Prism.languages.javascript;
 
 (function (Prism) {
-  // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|'
-  // + LC_ALL, RANDOM, REPLY, SECONDS.
-  // + make sure PS1..4 are here as they are not always set,
-  // - some useless things.
-  var envVars =
-    "\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b";
-
-  var commandAfterHeredoc = {
-    pattern: /(^(["']?)\w+\2)[ \t]+\S.*/,
-    lookbehind: true,
-    alias: "punctuation", // this looks reasonably well in all themes
-    inside: null, // see below
-  };
-
-  var insideString = {
-    bash: commandAfterHeredoc,
-    environment: {
-      pattern: RegExp("\\$" + envVars),
-      alias: "constant",
-    },
-    variable: [
-      // [0]: Arithmetic Environment
-      {
-        pattern: /\$?\(\([\s\S]+?\)\)/,
-        greedy: true,
-        inside: {
-          // If there is a $ sign at the beginning highlight $(( and )) as variable
-          variable: [
-            {
-              pattern: /(^\$\(\([\s\S]+)\)\)/,
-              lookbehind: true,
-            },
-            /^\$\(\(/,
-          ],
-          number: /\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,
-          // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
-          operator: /--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,
-          // If there is no $ sign at the beginning highlight (( and )) as punctuation
-          punctuation: /\(\(?|\)\)?|,|;/,
-        },
-      },
-      // [1]: Command Substitution
-      {
-        pattern: /\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,
-        greedy: true,
-        inside: {
-          variable: /^\$\(|^`|\)$|`$/,
-        },
-      },
-      // [2]: Brace expansion
-      {
-        pattern: /\$\{[^}]+\}/,
-        greedy: true,
-        inside: {
-          operator: /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,
-          punctuation: /[\[\]]/,
-          environment: {
-            pattern: RegExp("(\\{)" + envVars),
-            lookbehind: true,
-            alias: "constant",
-          },
-        },
-      },
-      /\$(?:\w+|[#?*!@$])/,
-    ],
-    // Escape sequences from echo and printf's manuals, and escaped quotes.
-    entity:
-      /\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/,
-  };
-
-  Prism.languages.bash = {
-    shebang: {
-      pattern: /^#!\s*\/.*/,
-      alias: "important",
-    },
-    comment: {
-      pattern: /(^|[^"{\\$])#.*/,
-      lookbehind: true,
-    },
-    "function-name": [
-      // a) function foo {
-      // b) foo() {
-      // c) function foo() {
-      // but not “foo {”
-      {
-        // a) and c)
-        pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,
-        lookbehind: true,
-        alias: "function",
-      },
-      {
-        // b)
-        pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/,
-        alias: "function",
-      },
-    ],
-    // Highlight variable names as variables in for and select beginnings.
-    "for-or-select": {
-      pattern: /(\b(?:for|select)\s+)\w+(?=\s+in\s)/,
-      alias: "variable",
-      lookbehind: true,
-    },
-    // Highlight variable names as variables in the left-hand part
-    // of assignments (“=” and “+=”).
-    "assign-left": {
-      pattern: /(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,
-      inside: {
-        environment: {
-          pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars),
-          lookbehind: true,
-          alias: "constant",
-        },
-      },
-      alias: "variable",
-      lookbehind: true,
-    },
-    // Highlight parameter names as variables
-    parameter: {
-      pattern: /(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,
-      alias: "variable",
-      lookbehind: true,
-    },
-    string: [
-      // Support for Here-documents https://en.wikipedia.org/wiki/Here_document
-      {
-        pattern: /((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,
-        lookbehind: true,
-        greedy: true,
-        inside: insideString,
-      },
-      // Here-document with quotes around the tag
-      // → No expansion (so no “inside”).
-      {
-        pattern: /((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,
-        lookbehind: true,
-        greedy: true,
-        inside: {
-          bash: commandAfterHeredoc,
-        },
-      },
-      // “Normal” string
-      {
-        // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
-        pattern:
-          /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,
-        lookbehind: true,
-        greedy: true,
-        inside: insideString,
-      },
-      {
-        // https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html
-        pattern: /(^|[^$\\])'[^']*'/,
-        lookbehind: true,
-        greedy: true,
-      },
-      {
-        // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
-        pattern: /\$'(?:[^'\\]|\\[\s\S])*'/,
-        greedy: true,
-        inside: {
-          entity: insideString.entity,
-        },
-      },
-    ],
-    environment: {
-      pattern: RegExp("\\$?" + envVars),
-      alias: "constant",
-    },
-    variable: insideString.variable,
-    function: {
-      pattern:
-        /(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,
-      lookbehind: true,
-    },
-    keyword: {
-      pattern:
-        /(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,
-      lookbehind: true,
-    },
-    // https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html
-    builtin: {
-      pattern:
-        /(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,
-      lookbehind: true,
-      // Alias added to make those easier to distinguish from strings.
-      alias: "class-name",
-    },
-    boolean: {
-      pattern: /(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,
-      lookbehind: true,
-    },
-    "file-descriptor": {
-      pattern: /\B&\d\b/,
-      alias: "important",
-    },
-    operator: {
-      // Lots of redirections here, but not just that.
-      pattern:
-        /\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,
-      inside: {
-        "file-descriptor": {
-          pattern: /^\d/,
-          alias: "important",
-        },
-      },
-    },
-    punctuation: /\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,
-    number: {
-      pattern: /(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,
-      lookbehind: true,
-    },
-  };
-
-  commandAfterHeredoc.inside = Prism.languages.bash;
-
-  /* Patterns in command substitution. */
-  var toBeCopied = [
-    "comment",
-    "function-name",
-    "for-or-select",
-    "assign-left",
-    "parameter",
-    "string",
-    "environment",
-    "function",
-    "keyword",
-    "builtin",
-    "boolean",
-    "file-descriptor",
-    "operator",
-    "punctuation",
-    "number",
-  ];
-  var inside = insideString.variable[1].inside;
-  for (var i = 0; i < toBeCopied.length; i++) {
-    inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]];
-  }
-
-  Prism.languages.sh = Prism.languages.bash;
-  Prism.languages.shell = Prism.languages.bash;
-})(Prism);
-
-Prism.languages.c = Prism.languages.extend("clike", {
-  comment: {
-    pattern:
-      /\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,
-    greedy: true,
-  },
-  string: {
-    // https://en.cppreference.com/w/c/language/string_literal
-    pattern: /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,
-    greedy: true,
-  },
-  "class-name": {
-    pattern:
-      /(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,
-    lookbehind: true,
-  },
-  keyword:
-    /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,
-  function: /\b[a-z_]\w*(?=\s*\()/i,
-  number:
-    /(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,
-  operator: />>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/,
+	// $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|'
+	// + LC_ALL, RANDOM, REPLY, SECONDS.
+	// + make sure PS1..4 are here as they are not always set,
+	// - some useless things.
+	var envVars = '\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b';
+
+	var commandAfterHeredoc = {
+		pattern: /(^(["']?)\w+\2)[ \t]+\S.*/,
+		lookbehind: true,
+		alias: 'punctuation', // this looks reasonably well in all themes
+		inside: null // see below
+	};
+
+	var insideString = {
+		'bash': commandAfterHeredoc,
+		'environment': {
+			pattern: RegExp('\\$' + envVars),
+			alias: 'constant'
+		},
+		'variable': [
+			// [0]: Arithmetic Environment
+			{
+				pattern: /\$?\(\([\s\S]+?\)\)/,
+				greedy: true,
+				inside: {
+					// If there is a $ sign at the beginning highlight $(( and )) as variable
+					'variable': [
+						{
+							pattern: /(^\$\(\([\s\S]+)\)\)/,
+							lookbehind: true
+						},
+						/^\$\(\(/
+					],
+					'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,
+					// Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
+					'operator': /--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,
+					// If there is no $ sign at the beginning highlight (( and )) as punctuation
+					'punctuation': /\(\(?|\)\)?|,|;/
+				}
+			},
+			// [1]: Command Substitution
+			{
+				pattern: /\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,
+				greedy: true,
+				inside: {
+					'variable': /^\$\(|^`|\)$|`$/
+				}
+			},
+			// [2]: Brace expansion
+			{
+				pattern: /\$\{[^}]+\}/,
+				greedy: true,
+				inside: {
+					'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,
+					'punctuation': /[\[\]]/,
+					'environment': {
+						pattern: RegExp('(\\{)' + envVars),
+						lookbehind: true,
+						alias: 'constant'
+					}
+				}
+			},
+			/\$(?:\w+|[#?*!@$])/
+		],
+		// Escape sequences from echo and printf's manuals, and escaped quotes.
+		'entity': /\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/
+	};
+
+	Prism.languages.bash = {
+		'shebang': {
+			pattern: /^#!\s*\/.*/,
+			alias: 'important'
+		},
+		'comment': {
+			pattern: /(^|[^"{\\$])#.*/,
+			lookbehind: true
+		},
+		'function-name': [
+			// a) function foo {
+			// b) foo() {
+			// c) function foo() {
+			// but not “foo {”
+			{
+				// a) and c)
+				pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,
+				lookbehind: true,
+				alias: 'function'
+			},
+			{
+				// b)
+				pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/,
+				alias: 'function'
+			}
+		],
+		// Highlight variable names as variables in for and select beginnings.
+		'for-or-select': {
+			pattern: /(\b(?:for|select)\s+)\w+(?=\s+in\s)/,
+			alias: 'variable',
+			lookbehind: true
+		},
+		// Highlight variable names as variables in the left-hand part
+		// of assignments (“=” and “+=”).
+		'assign-left': {
+			pattern: /(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,
+			inside: {
+				'environment': {
+					pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars),
+					lookbehind: true,
+					alias: 'constant'
+				}
+			},
+			alias: 'variable',
+			lookbehind: true
+		},
+		// Highlight parameter names as variables
+		'parameter': {
+			pattern: /(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,
+			alias: 'variable',
+			lookbehind: true
+		},
+		'string': [
+			// Support for Here-documents https://en.wikipedia.org/wiki/Here_document
+			{
+				pattern: /((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,
+				lookbehind: true,
+				greedy: true,
+				inside: insideString
+			},
+			// Here-document with quotes around the tag
+			// → No expansion (so no “inside”).
+			{
+				pattern: /((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,
+				lookbehind: true,
+				greedy: true,
+				inside: {
+					'bash': commandAfterHeredoc
+				}
+			},
+			// “Normal” string
+			{
+				// https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
+				pattern: /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,
+				lookbehind: true,
+				greedy: true,
+				inside: insideString
+			},
+			{
+				// https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html
+				pattern: /(^|[^$\\])'[^']*'/,
+				lookbehind: true,
+				greedy: true
+			},
+			{
+				// https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
+				pattern: /\$'(?:[^'\\]|\\[\s\S])*'/,
+				greedy: true,
+				inside: {
+					'entity': insideString.entity
+				}
+			}
+		],
+		'environment': {
+			pattern: RegExp('\\$?' + envVars),
+			alias: 'constant'
+		},
+		'variable': insideString.variable,
+		'function': {
+			pattern: /(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,
+			lookbehind: true
+		},
+		'keyword': {
+			pattern: /(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,
+			lookbehind: true
+		},
+		// https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html
+		'builtin': {
+			pattern: /(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,
+			lookbehind: true,
+			// Alias added to make those easier to distinguish from strings.
+			alias: 'class-name'
+		},
+		'boolean': {
+			pattern: /(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,
+			lookbehind: true
+		},
+		'file-descriptor': {
+			pattern: /\B&\d\b/,
+			alias: 'important'
+		},
+		'operator': {
+			// Lots of redirections here, but not just that.
+			pattern: /\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,
+			inside: {
+				'file-descriptor': {
+					pattern: /^\d/,
+					alias: 'important'
+				}
+			}
+		},
+		'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,
+		'number': {
+			pattern: /(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,
+			lookbehind: true
+		}
+	};
+
+	commandAfterHeredoc.inside = Prism.languages.bash;
+
+	/* Patterns in command substitution. */
+	var toBeCopied = [
+		'comment',
+		'function-name',
+		'for-or-select',
+		'assign-left',
+		'parameter',
+		'string',
+		'environment',
+		'function',
+		'keyword',
+		'builtin',
+		'boolean',
+		'file-descriptor',
+		'operator',
+		'punctuation',
+		'number'
+	];
+	var inside = insideString.variable[1].inside;
+	for (var i = 0; i < toBeCopied.length; i++) {
+		inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]];
+	}
+
+	Prism.languages.sh = Prism.languages.bash;
+	Prism.languages.shell = Prism.languages.bash;
+}(Prism));
+
+Prism.languages.c = Prism.languages.extend('clike', {
+	'comment': {
+		pattern: /\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,
+		greedy: true
+	},
+	'string': {
+		// https://en.cppreference.com/w/c/language/string_literal
+		pattern: /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,
+		greedy: true
+	},
+	'class-name': {
+		pattern: /(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,
+		lookbehind: true
+	},
+	'keyword': /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,
+	'function': /\b[a-z_]\w*(?=\s*\()/i,
+	'number': /(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,
+	'operator': />>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/
 });
 
-Prism.languages.insertBefore("c", "string", {
-  char: {
-    // https://en.cppreference.com/w/c/language/character_constant
-    pattern: /'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,
-    greedy: true,
-  },
+Prism.languages.insertBefore('c', 'string', {
+	'char': {
+		// https://en.cppreference.com/w/c/language/character_constant
+		pattern: /'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,
+		greedy: true
+	}
 });
 
-Prism.languages.insertBefore("c", "string", {
-  macro: {
-    // allow for multiline macro definitions
-    // spaces after the # character compile fine with gcc
-    pattern:
-      /(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,
-    lookbehind: true,
-    greedy: true,
-    alias: "property",
-    inside: {
-      string: [
-        {
-          // highlight the path of the include statement as a string
-          pattern: /^(#\s*include\s*)<[^>]+>/,
-          lookbehind: true,
-        },
-        Prism.languages.c["string"],
-      ],
-      char: Prism.languages.c["char"],
-      comment: Prism.languages.c["comment"],
-      "macro-name": [
-        {
-          pattern: /(^#\s*define\s+)\w+\b(?!\()/i,
-          lookbehind: true,
-        },
-        {
-          pattern: /(^#\s*define\s+)\w+\b(?=\()/i,
-          lookbehind: true,
-          alias: "function",
-        },
-      ],
-      // highlight macro directives as keywords
-      directive: {
-        pattern: /^(#\s*)[a-z]+/,
-        lookbehind: true,
-        alias: "keyword",
-      },
-      "directive-hash": /^#/,
-      punctuation: /##|\\(?=[\r\n])/,
-      expression: {
-        pattern: /\S[\s\S]*/,
-        inside: Prism.languages.c,
-      },
-    },
-  },
+Prism.languages.insertBefore('c', 'string', {
+	'macro': {
+		// allow for multiline macro definitions
+		// spaces after the # character compile fine with gcc
+		pattern: /(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,
+		lookbehind: true,
+		greedy: true,
+		alias: 'property',
+		inside: {
+			'string': [
+				{
+					// highlight the path of the include statement as a string
+					pattern: /^(#\s*include\s*)<[^>]+>/,
+					lookbehind: true
+				},
+				Prism.languages.c['string']
+			],
+			'char': Prism.languages.c['char'],
+			'comment': Prism.languages.c['comment'],
+			'macro-name': [
+				{
+					pattern: /(^#\s*define\s+)\w+\b(?!\()/i,
+					lookbehind: true
+				},
+				{
+					pattern: /(^#\s*define\s+)\w+\b(?=\()/i,
+					lookbehind: true,
+					alias: 'function'
+				}
+			],
+			// highlight macro directives as keywords
+			'directive': {
+				pattern: /^(#\s*)[a-z]+/,
+				lookbehind: true,
+				alias: 'keyword'
+			},
+			'directive-hash': /^#/,
+			'punctuation': /##|\\(?=[\r\n])/,
+			'expression': {
+				pattern: /\S[\s\S]*/,
+				inside: Prism.languages.c
+			}
+		}
+	}
 });
 
-Prism.languages.insertBefore("c", "function", {
-  // highlight predefined macros as constants
-  constant:
-    /\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/,
+Prism.languages.insertBefore('c', 'function', {
+	// highlight predefined macros as constants
+	'constant': /\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/
 });
 
-delete Prism.languages.c["boolean"];
+delete Prism.languages.c['boolean'];
 
 (function (Prism) {
-  var keyword =
-    /\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/;
-  var modName = /\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(
-    /<keyword>/g,
-    function () {
-      return keyword.source;
-    },
-  );
-
-  Prism.languages.cpp = Prism.languages.extend("c", {
-    "class-name": [
-      {
-        pattern: RegExp(
-          /(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(
-            /<keyword>/g,
-            function () {
-              return keyword.source;
-            },
-          ),
-        ),
-        lookbehind: true,
-      },
-      // This is intended to capture the class name of method implementations like:
-      //   void foo::bar() const {}
-      // However! The `foo` in the above example could also be a namespace, so we only capture the class name if
-      // it starts with an uppercase letter. This approximation should give decent results.
-      /\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,
-      // This will capture the class name before destructors like:
-      //   Foo::~Foo() {}
-      /\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,
-      // This also intends to capture the class name of method implementations but here the class has template
-      // parameters, so it can't be a namespace (until C++ adds generic namespaces).
-      /\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/,
-    ],
-    keyword: keyword,
-    number: {
-      pattern:
-        /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,
-      greedy: true,
-    },
-    operator:
-      />>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,
-    boolean: /\b(?:false|true)\b/,
-  });
-
-  Prism.languages.insertBefore("cpp", "string", {
-    module: {
-      // https://en.cppreference.com/w/cpp/language/modules
-      pattern: RegExp(
-        /(\b(?:import|module)\s+)/.source +
-          "(?:" +
-          // header-name
-          /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source +
-          "|" +
-          // module name or partition or both
-          /<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(
-            /<mod-name>/g,
-            function () {
-              return modName;
-            },
-          ) +
-          ")",
-      ),
-      lookbehind: true,
-      greedy: true,
-      inside: {
-        string: /^[<"][\s\S]+/,
-        operator: /:/,
-        punctuation: /\./,
-      },
-    },
-    "raw-string": {
-      pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,
-      alias: "string",
-      greedy: true,
-    },
-  });
-
-  Prism.languages.insertBefore("cpp", "keyword", {
-    "generic-function": {
-      pattern: /\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,
-      inside: {
-        function: /^\w+/,
-        generic: {
-          pattern: /<[\s\S]+/,
-          alias: "class-name",
-          inside: Prism.languages.cpp,
-        },
-      },
-    },
-  });
-
-  Prism.languages.insertBefore("cpp", "operator", {
-    "double-colon": {
-      pattern: /::/,
-      alias: "punctuation",
-    },
-  });
-
-  Prism.languages.insertBefore("cpp", "class-name", {
-    // the base clause is an optional list of parent classes
-    // https://en.cppreference.com/w/cpp/language/class
-    "base-clause": {
-      pattern:
-        /(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,
-      lookbehind: true,
-      greedy: true,
-      inside: Prism.languages.extend("cpp", {}),
-    },
-  });
-
-  Prism.languages.insertBefore(
-    "inside",
-    "double-colon",
-    {
-      // All untokenized words that are not namespaces should be class names
-      "class-name": /\b[a-z_]\w*\b(?!\s*::)/i,
-    },
-    Prism.languages.cpp["base-clause"],
-  );
-})(Prism);
+
+	var keyword = /\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/;
+	var modName = /\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g, function () { return keyword.source; });
+
+	Prism.languages.cpp = Prism.languages.extend('c', {
+		'class-name': [
+			{
+				pattern: RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source
+					.replace(/<keyword>/g, function () { return keyword.source; })),
+				lookbehind: true
+			},
+			// This is intended to capture the class name of method implementations like:
+			//   void foo::bar() const {}
+			// However! The `foo` in the above example could also be a namespace, so we only capture the class name if
+			// it starts with an uppercase letter. This approximation should give decent results.
+			/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,
+			// This will capture the class name before destructors like:
+			//   Foo::~Foo() {}
+			/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,
+			// This also intends to capture the class name of method implementations but here the class has template
+			// parameters, so it can't be a namespace (until C++ adds generic namespaces).
+			/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/
+		],
+		'keyword': keyword,
+		'number': {
+			pattern: /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,
+			greedy: true
+		},
+		'operator': />>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,
+		'boolean': /\b(?:false|true)\b/
+	});
+
+	Prism.languages.insertBefore('cpp', 'string', {
+		'module': {
+			// https://en.cppreference.com/w/cpp/language/modules
+			pattern: RegExp(
+				/(\b(?:import|module)\s+)/.source +
+				'(?:' +
+				// header-name
+				/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source +
+				'|' +
+				// module name or partition or both
+				/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g, function () { return modName; }) +
+				')'
+			),
+			lookbehind: true,
+			greedy: true,
+			inside: {
+				'string': /^[<"][\s\S]+/,
+				'operator': /:/,
+				'punctuation': /\./
+			}
+		},
+		'raw-string': {
+			pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,
+			alias: 'string',
+			greedy: true
+		}
+	});
+
+	Prism.languages.insertBefore('cpp', 'keyword', {
+		'generic-function': {
+			pattern: /\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,
+			inside: {
+				'function': /^\w+/,
+				'generic': {
+					pattern: /<[\s\S]+/,
+					alias: 'class-name',
+					inside: Prism.languages.cpp
+				}
+			}
+		}
+	});
+
+	Prism.languages.insertBefore('cpp', 'operator', {
+		'double-colon': {
+			pattern: /::/,
+			alias: 'punctuation'
+		}
+	});
+
+	Prism.languages.insertBefore('cpp', 'class-name', {
+		// the base clause is an optional list of parent classes
+		// https://en.cppreference.com/w/cpp/language/class
+		'base-clause': {
+			pattern: /(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,
+			lookbehind: true,
+			greedy: true,
+			inside: Prism.languages.extend('cpp', {})
+		}
+	});
+
+	Prism.languages.insertBefore('inside', 'double-colon', {
+		// All untokenized words that are not namespaces should be class names
+		'class-name': /\b[a-z_]\w*\b(?!\s*::)/i
+	}, Prism.languages.cpp['base-clause']);
+
+}(Prism));
 
 Prism.languages.cmake = {
-  comment: /#.*/,
-  string: {
-    pattern: /"(?:[^\\"]|\\.)*"/,
-    greedy: true,
-    inside: {
-      interpolation: {
-        pattern: /\$\{(?:[^{}$]|\$\{[^{}$]*\})*\}/,
-        inside: {
-          punctuation: /\$\{|\}/,
-          variable: /\w+/,
-        },
-      },
-    },
-  },
-  variable:
-    /\b(?:CMAKE_\w+|\w+_(?:(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT|VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_NAME|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE))\b/,
-  property:
-    /\b(?:cxx_\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\w+|\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\b/,
-  keyword:
-    /\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\s*\()\b/,
-  boolean: /\b(?:FALSE|OFF|ON|TRUE)\b/,
-  namespace:
-    /\b(?:INTERFACE|PRIVATE|PROPERTIES|PUBLIC|SHARED|STATIC|TARGET_OBJECTS)\b/,
-  operator:
-    /\b(?:AND|DEFINED|EQUAL|GREATER|LESS|MATCHES|NOT|OR|STREQUAL|STRGREATER|STRLESS|VERSION_EQUAL|VERSION_GREATER|VERSION_LESS)\b/,
-  inserted: {
-    pattern: /\b\w+::\w+\b/,
-    alias: "class-name",
-  },
-  number: /\b\d+(?:\.\d+)*\b/,
-  function: /\b[a-z_]\w*(?=\s*\()\b/i,
-  punctuation: /[()>}]|\$[<{]/,
+	'comment': /#.*/,
+	'string': {
+		pattern: /"(?:[^\\"]|\\.)*"/,
+		greedy: true,
+		inside: {
+			'interpolation': {
+				pattern: /\$\{(?:[^{}$]|\$\{[^{}$]*\})*\}/,
+				inside: {
+					'punctuation': /\$\{|\}/,
+					'variable': /\w+/
+				}
+			}
+		}
+	},
+	'variable': /\b(?:CMAKE_\w+|\w+_(?:(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT|VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_NAME|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE))\b/,
+	'property': /\b(?:cxx_\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\w+|\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\b/,
+	'keyword': /\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\s*\()\b/,
+	'boolean': /\b(?:FALSE|OFF|ON|TRUE)\b/,
+	'namespace': /\b(?:INTERFACE|PRIVATE|PROPERTIES|PUBLIC|SHARED|STATIC|TARGET_OBJECTS)\b/,
+	'operator': /\b(?:AND|DEFINED|EQUAL|GREATER|LESS|MATCHES|NOT|OR|STREQUAL|STRGREATER|STRLESS|VERSION_EQUAL|VERSION_GREATER|VERSION_LESS)\b/,
+	'inserted': {
+		pattern: /\b\w+::\w+\b/,
+		alias: 'class-name'
+	},
+	'number': /\b\d+(?:\.\d+)*\b/,
+	'function': /\b[a-z_]\w*(?=\s*\()\b/i,
+	'punctuation': /[()>}]|\$[<{]/
 };
 
 (function (Prism) {
-  // Ignore comments starting with { to privilege string interpolation highlighting
-  var comment = /#(?!\{).+/;
-  var interpolation = {
-    pattern: /#\{[^}]+\}/,
-    alias: "variable",
-  };
-
-  Prism.languages.coffeescript = Prism.languages.extend("javascript", {
-    comment: comment,
-    string: [
-      // Strings are multiline
-      {
-        pattern: /'(?:\\[\s\S]|[^\\'])*'/,
-        greedy: true,
-      },
-
-      {
-        // Strings are multiline
-        pattern: /"(?:\\[\s\S]|[^\\"])*"/,
-        greedy: true,
-        inside: {
-          interpolation: interpolation,
-        },
-      },
-    ],
-    keyword:
-      /\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,
-    "class-member": {
-      pattern: /@(?!\d)\w+/,
-      alias: "variable",
-    },
-  });
-
-  Prism.languages.insertBefore("coffeescript", "comment", {
-    "multiline-comment": {
-      pattern: /###[\s\S]+?###/,
-      alias: "comment",
-    },
-
-    // Block regexp can contain comments and interpolation
-    "block-regex": {
-      pattern: /\/{3}[\s\S]*?\/{3}/,
-      alias: "regex",
-      inside: {
-        comment: comment,
-        interpolation: interpolation,
-      },
-    },
-  });
-
-  Prism.languages.insertBefore("coffeescript", "string", {
-    "inline-javascript": {
-      pattern: /`(?:\\[\s\S]|[^\\`])*`/,
-      inside: {
-        delimiter: {
-          pattern: /^`|`$/,
-          alias: "punctuation",
-        },
-        script: {
-          pattern: /[\s\S]+/,
-          alias: "language-javascript",
-          inside: Prism.languages.javascript,
-        },
-      },
-    },
-
-    // Block strings
-    "multiline-string": [
-      {
-        pattern: /'''[\s\S]*?'''/,
-        greedy: true,
-        alias: "string",
-      },
-      {
-        pattern: /"""[\s\S]*?"""/,
-        greedy: true,
-        alias: "string",
-        inside: {
-          interpolation: interpolation,
-        },
-      },
-    ],
-  });
-
-  Prism.languages.insertBefore("coffeescript", "keyword", {
-    // Object property
-    property: /(?!\d)\w+(?=\s*:(?!:))/,
-  });
-
-  delete Prism.languages.coffeescript["template-string"];
-
-  Prism.languages.coffee = Prism.languages.coffeescript;
-})(Prism);
+
+	// Ignore comments starting with { to privilege string interpolation highlighting
+	var comment = /#(?!\{).+/;
+	var interpolation = {
+		pattern: /#\{[^}]+\}/,
+		alias: 'variable'
+	};
+
+	Prism.languages.coffeescript = Prism.languages.extend('javascript', {
+		'comment': comment,
+		'string': [
+
+			// Strings are multiline
+			{
+				pattern: /'(?:\\[\s\S]|[^\\'])*'/,
+				greedy: true
+			},
+
+			{
+				// Strings are multiline
+				pattern: /"(?:\\[\s\S]|[^\\"])*"/,
+				greedy: true,
+				inside: {
+					'interpolation': interpolation
+				}
+			}
+		],
+		'keyword': /\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,
+		'class-member': {
+			pattern: /@(?!\d)\w+/,
+			alias: 'variable'
+		}
+	});
+
+	Prism.languages.insertBefore('coffeescript', 'comment', {
+		'multiline-comment': {
+			pattern: /###[\s\S]+?###/,
+			alias: 'comment'
+		},
+
+		// Block regexp can contain comments and interpolation
+		'block-regex': {
+			pattern: /\/{3}[\s\S]*?\/{3}/,
+			alias: 'regex',
+			inside: {
+				'comment': comment,
+				'interpolation': interpolation
+			}
+		}
+	});
+
+	Prism.languages.insertBefore('coffeescript', 'string', {
+		'inline-javascript': {
+			pattern: /`(?:\\[\s\S]|[^\\`])*`/,
+			inside: {
+				'delimiter': {
+					pattern: /^`|`$/,
+					alias: 'punctuation'
+				},
+				'script': {
+					pattern: /[\s\S]+/,
+					alias: 'language-javascript',
+					inside: Prism.languages.javascript
+				}
+			}
+		},
+
+		// Block strings
+		'multiline-string': [
+			{
+				pattern: /'''[\s\S]*?'''/,
+				greedy: true,
+				alias: 'string'
+			},
+			{
+				pattern: /"""[\s\S]*?"""/,
+				greedy: true,
+				alias: 'string',
+				inside: {
+					interpolation: interpolation
+				}
+			}
+		]
+
+	});
+
+	Prism.languages.insertBefore('coffeescript', 'keyword', {
+		// Object property
+		'property': /(?!\d)\w+(?=\s*:(?!:))/
+	});
+
+	delete Prism.languages.coffeescript['template-string'];
+
+	Prism.languages.coffee = Prism.languages.coffeescript;
+}(Prism));
 
 /**
  * Original by Samuel Flores
@@ -2421,1968 +2272,1833 @@ Prism.languages.cmake = {
  *     constant, builtin, variable, symbol, regex
  */
 (function (Prism) {
-  Prism.languages.ruby = Prism.languages.extend("clike", {
-    comment: {
-      pattern: /#.*|^=begin\s[\s\S]*?^=end/m,
-      greedy: true,
-    },
-    "class-name": {
-      pattern:
-        /(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/,
-      lookbehind: true,
-      inside: {
-        punctuation: /[.\\]/,
-      },
-    },
-    keyword:
-      /\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/,
-    operator:
-      /\.{2,3}|&\.|===|<?=>|[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/,
-    punctuation: /[(){}[\].,;]/,
-  });
-
-  Prism.languages.insertBefore("ruby", "operator", {
-    "double-colon": {
-      pattern: /::/,
-      alias: "punctuation",
-    },
-  });
-
-  var interpolation = {
-    pattern: /((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/,
-    lookbehind: true,
-    inside: {
-      content: {
-        pattern: /^(#\{)[\s\S]+(?=\}$)/,
-        lookbehind: true,
-        inside: Prism.languages.ruby,
-      },
-      delimiter: {
-        pattern: /^#\{|\}$/,
-        alias: "punctuation",
-      },
-    },
-  };
-
-  delete Prism.languages.ruby.function;
-
-  var percentExpression =
-    "(?:" +
-    [
-      /([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
-      /\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source,
-      /\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source,
-      /\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source,
-      /<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source,
-    ].join("|") +
-    ")";
-
-  var symbolName =
-    /(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/
-      .source;
-
-  Prism.languages.insertBefore("ruby", "keyword", {
-    "regex-literal": [
-      {
-        pattern: RegExp(
-          /%r/.source + percentExpression + /[egimnosux]{0,6}/.source,
-        ),
-        greedy: true,
-        inside: {
-          interpolation: interpolation,
-          regex: /[\s\S]+/,
-        },
-      },
-      {
-        pattern:
-          /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,
-        lookbehind: true,
-        greedy: true,
-        inside: {
-          interpolation: interpolation,
-          regex: /[\s\S]+/,
-        },
-      },
-    ],
-    variable: /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,
-    symbol: [
-      {
-        pattern: RegExp(/(^|[^:]):/.source + symbolName),
-        lookbehind: true,
-        greedy: true,
-      },
-      {
-        pattern: RegExp(
-          /([\r\n{(,][ \t]*)/.source + symbolName + /(?=:(?!:))/.source,
-        ),
-        lookbehind: true,
-        greedy: true,
-      },
-    ],
-    "method-definition": {
-      pattern: /(\bdef\s+)\w+(?:\s*\.\s*\w+)?/,
-      lookbehind: true,
-      inside: {
-        function: /\b\w+$/,
-        keyword: /^self\b/,
-        "class-name": /^\w+/,
-        punctuation: /\./,
-      },
-    },
-  });
-
-  Prism.languages.insertBefore("ruby", "string", {
-    "string-literal": [
-      {
-        pattern: RegExp(/%[qQiIwWs]?/.source + percentExpression),
-        greedy: true,
-        inside: {
-          interpolation: interpolation,
-          string: /[\s\S]+/,
-        },
-      },
-      {
-        pattern:
-          /("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,
-        greedy: true,
-        inside: {
-          interpolation: interpolation,
-          string: /[\s\S]+/,
-        },
-      },
-      {
-        pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,
-        alias: "heredoc-string",
-        greedy: true,
-        inside: {
-          delimiter: {
-            pattern: /^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i,
-            inside: {
-              symbol: /\b\w+/,
-              punctuation: /^<<[-~]?/,
-            },
-          },
-          interpolation: interpolation,
-          string: /[\s\S]+/,
-        },
-      },
-      {
-        pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,
-        alias: "heredoc-string",
-        greedy: true,
-        inside: {
-          delimiter: {
-            pattern: /^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i,
-            inside: {
-              symbol: /\b\w+/,
-              punctuation: /^<<[-~]?'|'$/,
-            },
-          },
-          string: /[\s\S]+/,
-        },
-      },
-    ],
-    "command-literal": [
-      {
-        pattern: RegExp(/%x/.source + percentExpression),
-        greedy: true,
-        inside: {
-          interpolation: interpolation,
-          command: {
-            pattern: /[\s\S]+/,
-            alias: "string",
-          },
-        },
-      },
-      {
-        pattern: /`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/,
-        greedy: true,
-        inside: {
-          interpolation: interpolation,
-          command: {
-            pattern: /[\s\S]+/,
-            alias: "string",
-          },
-        },
-      },
-    ],
-  });
-
-  delete Prism.languages.ruby.string;
-
-  Prism.languages.insertBefore("ruby", "number", {
-    builtin:
-      /\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/,
-    constant: /\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/,
-  });
-
-  Prism.languages.rb = Prism.languages.ruby;
-})(Prism);
+	Prism.languages.ruby = Prism.languages.extend('clike', {
+		'comment': {
+			pattern: /#.*|^=begin\s[\s\S]*?^=end/m,
+			greedy: true
+		},
+		'class-name': {
+			pattern: /(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/,
+			lookbehind: true,
+			inside: {
+				'punctuation': /[.\\]/
+			}
+		},
+		'keyword': /\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/,
+		'operator': /\.{2,3}|&\.|===|<?=>|[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/,
+		'punctuation': /[(){}[\].,;]/,
+	});
+
+	Prism.languages.insertBefore('ruby', 'operator', {
+		'double-colon': {
+			pattern: /::/,
+			alias: 'punctuation'
+		},
+	});
+
+	var interpolation = {
+		pattern: /((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/,
+		lookbehind: true,
+		inside: {
+			'content': {
+				pattern: /^(#\{)[\s\S]+(?=\}$)/,
+				lookbehind: true,
+				inside: Prism.languages.ruby
+			},
+			'delimiter': {
+				pattern: /^#\{|\}$/,
+				alias: 'punctuation'
+			}
+		}
+	};
+
+	delete Prism.languages.ruby.function;
+
+	var percentExpression = '(?:' + [
+		/([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
+		/\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source,
+		/\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source,
+		/\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source,
+		/<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source
+	].join('|') + ')';
+
+	var symbolName = /(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source;
+
+	Prism.languages.insertBefore('ruby', 'keyword', {
+		'regex-literal': [
+			{
+				pattern: RegExp(/%r/.source + percentExpression + /[egimnosux]{0,6}/.source),
+				greedy: true,
+				inside: {
+					'interpolation': interpolation,
+					'regex': /[\s\S]+/
+				}
+			},
+			{
+				pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,
+				lookbehind: true,
+				greedy: true,
+				inside: {
+					'interpolation': interpolation,
+					'regex': /[\s\S]+/
+				}
+			}
+		],
+		'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,
+		'symbol': [
+			{
+				pattern: RegExp(/(^|[^:]):/.source + symbolName),
+				lookbehind: true,
+				greedy: true
+			},
+			{
+				pattern: RegExp(/([\r\n{(,][ \t]*)/.source + symbolName + /(?=:(?!:))/.source),
+				lookbehind: true,
+				greedy: true
+			},
+		],
+		'method-definition': {
+			pattern: /(\bdef\s+)\w+(?:\s*\.\s*\w+)?/,
+			lookbehind: true,
+			inside: {
+				'function': /\b\w+$/,
+				'keyword': /^self\b/,
+				'class-name': /^\w+/,
+				'punctuation': /\./
+			}
+		}
+	});
+
+	Prism.languages.insertBefore('ruby', 'string', {
+		'string-literal': [
+			{
+				pattern: RegExp(/%[qQiIwWs]?/.source + percentExpression),
+				greedy: true,
+				inside: {
+					'interpolation': interpolation,
+					'string': /[\s\S]+/
+				}
+			},
+			{
+				pattern: /("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,
+				greedy: true,
+				inside: {
+					'interpolation': interpolation,
+					'string': /[\s\S]+/
+				}
+			},
+			{
+				pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,
+				alias: 'heredoc-string',
+				greedy: true,
+				inside: {
+					'delimiter': {
+						pattern: /^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i,
+						inside: {
+							'symbol': /\b\w+/,
+							'punctuation': /^<<[-~]?/
+						}
+					},
+					'interpolation': interpolation,
+					'string': /[\s\S]+/
+				}
+			},
+			{
+				pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,
+				alias: 'heredoc-string',
+				greedy: true,
+				inside: {
+					'delimiter': {
+						pattern: /^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i,
+						inside: {
+							'symbol': /\b\w+/,
+							'punctuation': /^<<[-~]?'|'$/,
+						}
+					},
+					'string': /[\s\S]+/
+				}
+			}
+		],
+		'command-literal': [
+			{
+				pattern: RegExp(/%x/.source + percentExpression),
+				greedy: true,
+				inside: {
+					'interpolation': interpolation,
+					'command': {
+						pattern: /[\s\S]+/,
+						alias: 'string'
+					}
+				}
+			},
+			{
+				pattern: /`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/,
+				greedy: true,
+				inside: {
+					'interpolation': interpolation,
+					'command': {
+						pattern: /[\s\S]+/,
+						alias: 'string'
+					}
+				}
+			}
+		]
+	});
+
+	delete Prism.languages.ruby.string;
+
+	Prism.languages.insertBefore('ruby', 'number', {
+		'builtin': /\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/,
+		'constant': /\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/
+	});
+
+	Prism.languages.rb = Prism.languages.ruby;
+}(Prism));
 
 (function (Prism) {
-  Prism.languages.crystal = Prism.languages.extend("ruby", {
-    keyword: [
-      /\b(?:__DIR__|__END_LINE__|__FILE__|__LINE__|abstract|alias|annotation|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|ifdef|include|instance_sizeof|lib|macro|module|next|of|out|pointerof|private|protected|ptr|require|rescue|return|select|self|sizeof|struct|super|then|type|typeof|undef|uninitialized|union|unless|until|when|while|with|yield)\b/,
-      {
-        pattern: /(\.\s*)(?:is_a|responds_to)\?/,
-        lookbehind: true,
-      },
-    ],
-    number:
-      /\b(?:0b[01_]*[01]|0o[0-7_]*[0-7]|0x[\da-fA-F_]*[\da-fA-F]|(?:\d(?:[\d_]*\d)?)(?:\.[\d_]*\d)?(?:[eE][+-]?[\d_]*\d)?)(?:_(?:[uif](?:8|16|32|64))?)?\b/,
-    operator: [/->/, Prism.languages.ruby.operator],
-    punctuation: /[(){}[\].,;\\]/,
-  });
-
-  Prism.languages.insertBefore("crystal", "string-literal", {
-    attribute: {
-      pattern: /@\[.*?\]/,
-      inside: {
-        delimiter: {
-          pattern: /^@\[|\]$/,
-          alias: "punctuation",
-        },
-        attribute: {
-          pattern: /^(\s*)\w+/,
-          lookbehind: true,
-          alias: "class-name",
-        },
-        args: {
-          pattern: /\S(?:[\s\S]*\S)?/,
-          inside: Prism.languages.crystal,
-        },
-      },
-    },
-    expansion: {
-      pattern: /\{(?:\{.*?\}|%.*?%)\}/,
-      inside: {
-        content: {
-          pattern: /^(\{.)[\s\S]+(?=.\}$)/,
-          lookbehind: true,
-          inside: Prism.languages.crystal,
-        },
-        delimiter: {
-          pattern: /^\{[\{%]|[\}%]\}$/,
-          alias: "operator",
-        },
-      },
-    },
-    char: {
-      pattern:
-        /'(?:[^\\\r\n]{1,2}|\\(?:.|u(?:[A-Fa-f0-9]{1,4}|\{[A-Fa-f0-9]{1,6}\})))'/,
-      greedy: true,
-    },
-  });
-})(Prism);
-
-Prism.languages.d = Prism.languages.extend("clike", {
-  comment: [
-    {
-      // Shebang
-      pattern: /^\s*#!.+/,
-      greedy: true,
-    },
-    {
-      pattern: RegExp(
-        /(^|[^\\])/.source +
-          "(?:" +
-          [
-            // /+ comment +/
-            // Allow one level of nesting
-            /\/\+(?:\/\+(?:[^+]|\+(?!\/))*\+\/|(?!\/\+)[\s\S])*?\+\//.source,
-            // // comment
-            /\/\/.*/.source,
-            // /* comment */
-            /\/\*[\s\S]*?\*\//.source,
-          ].join("|") +
-          ")",
-      ),
-      lookbehind: true,
-      greedy: true,
-    },
-  ],
-  string: [
-    {
-      pattern: RegExp(
-        [
-          // r"", x""
-          /\b[rx]"(?:\\[\s\S]|[^\\"])*"[cwd]?/.source,
-
-          // q"[]", q"()", q"<>", q"{}"
-          /\bq"(?:\[[\s\S]*?\]|\([\s\S]*?\)|<[\s\S]*?>|\{[\s\S]*?\})"/.source,
-
-          // q"IDENT
-          // ...
-          // IDENT"
-          /\bq"((?!\d)\w+)$[\s\S]*?^\1"/.source,
-
-          // q"//", q"||", etc.
-          // eslint-disable-next-line regexp/strict
-          /\bq"(.)[\s\S]*?\2"/.source,
-
-          // eslint-disable-next-line regexp/strict
-          /(["`])(?:\\[\s\S]|(?!\3)[^\\])*\3[cwd]?/.source,
-        ].join("|"),
-        "m",
-      ),
-      greedy: true,
-    },
-    {
-      pattern: /\bq\{(?:\{[^{}]*\}|[^{}])*\}/,
-      greedy: true,
-      alias: "token-string",
-    },
-  ],
-
-  // In order: $, keywords and special tokens, globally defined symbols
-  keyword:
-    /\$|\b(?:__(?:(?:DATE|EOF|FILE|FUNCTION|LINE|MODULE|PRETTY_FUNCTION|TIMESTAMP|TIME|VENDOR|VERSION)__|gshared|parameters|traits|vector)|abstract|alias|align|asm|assert|auto|body|bool|break|byte|case|cast|catch|cdouble|cent|cfloat|char|class|const|continue|creal|dchar|debug|default|delegate|delete|deprecated|do|double|dstring|else|enum|export|extern|false|final|finally|float|for|foreach|foreach_reverse|function|goto|idouble|if|ifloat|immutable|import|inout|int|interface|invariant|ireal|lazy|long|macro|mixin|module|new|nothrow|null|out|override|package|pragma|private|protected|ptrdiff_t|public|pure|real|ref|return|scope|shared|short|size_t|static|string|struct|super|switch|synchronized|template|this|throw|true|try|typedef|typeid|typeof|ubyte|ucent|uint|ulong|union|unittest|ushort|version|void|volatile|wchar|while|with|wstring)\b/,
-
-  number: [
-    // The lookbehind and the negative look-ahead try to prevent bad highlighting of the .. operator
-    // Hexadecimal numbers must be handled separately to avoid problems with exponent "e"
-    /\b0x\.?[a-f\d_]+(?:(?!\.\.)\.[a-f\d_]*)?(?:p[+-]?[a-f\d_]+)?[ulfi]{0,4}/i,
-    {
-      pattern:
-        /((?:\.\.)?)(?:\b0b\.?|\b|\.)\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:e[+-]?\d[\d_]*)?[ulfi]{0,4}/i,
-      lookbehind: true,
-    },
-  ],
-
-  operator:
-    /\|[|=]?|&[&=]?|\+[+=]?|-[-=]?|\.?\.\.|=[>=]?|!(?:i[ns]\b|<>?=?|>=?|=)?|\bi[ns]\b|(?:<[<>]?|>>?>?|\^\^|[*\/%^~])=?/,
+	Prism.languages.crystal = Prism.languages.extend('ruby', {
+		'keyword': [
+			/\b(?:__DIR__|__END_LINE__|__FILE__|__LINE__|abstract|alias|annotation|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|ifdef|include|instance_sizeof|lib|macro|module|next|of|out|pointerof|private|protected|ptr|require|rescue|return|select|self|sizeof|struct|super|then|type|typeof|undef|uninitialized|union|unless|until|when|while|with|yield)\b/,
+			{
+				pattern: /(\.\s*)(?:is_a|responds_to)\?/,
+				lookbehind: true
+			}
+		],
+		'number': /\b(?:0b[01_]*[01]|0o[0-7_]*[0-7]|0x[\da-fA-F_]*[\da-fA-F]|(?:\d(?:[\d_]*\d)?)(?:\.[\d_]*\d)?(?:[eE][+-]?[\d_]*\d)?)(?:_(?:[uif](?:8|16|32|64))?)?\b/,
+		'operator': [
+			/->/,
+			Prism.languages.ruby.operator,
+		],
+		'punctuation': /[(){}[\].,;\\]/,
+	});
+
+	Prism.languages.insertBefore('crystal', 'string-literal', {
+		'attribute': {
+			pattern: /@\[.*?\]/,
+			inside: {
+				'delimiter': {
+					pattern: /^@\[|\]$/,
+					alias: 'punctuation'
+				},
+				'attribute': {
+					pattern: /^(\s*)\w+/,
+					lookbehind: true,
+					alias: 'class-name'
+				},
+				'args': {
+					pattern: /\S(?:[\s\S]*\S)?/,
+					inside: Prism.languages.crystal
+				},
+			}
+		},
+		'expansion': {
+			pattern: /\{(?:\{.*?\}|%.*?%)\}/,
+			inside: {
+				'content': {
+					pattern: /^(\{.)[\s\S]+(?=.\}$)/,
+					lookbehind: true,
+					inside: Prism.languages.crystal
+				},
+				'delimiter': {
+					pattern: /^\{[\{%]|[\}%]\}$/,
+					alias: 'operator'
+				}
+			}
+		},
+		'char': {
+			pattern: /'(?:[^\\\r\n]{1,2}|\\(?:.|u(?:[A-Fa-f0-9]{1,4}|\{[A-Fa-f0-9]{1,6}\})))'/,
+			greedy: true
+		}
+	});
+
+}(Prism));
+
+Prism.languages.d = Prism.languages.extend('clike', {
+	'comment': [
+		{
+			// Shebang
+			pattern: /^\s*#!.+/,
+			greedy: true
+		},
+		{
+			pattern: RegExp(/(^|[^\\])/.source + '(?:' + [
+				// /+ comment +/
+				// Allow one level of nesting
+				/\/\+(?:\/\+(?:[^+]|\+(?!\/))*\+\/|(?!\/\+)[\s\S])*?\+\//.source,
+				// // comment
+				/\/\/.*/.source,
+				// /* comment */
+				/\/\*[\s\S]*?\*\//.source
+			].join('|') + ')'),
+			lookbehind: true,
+			greedy: true
+		}
+	],
+	'string': [
+		{
+			pattern: RegExp([
+				// r"", x""
+				/\b[rx]"(?:\\[\s\S]|[^\\"])*"[cwd]?/.source,
+
+				// q"[]", q"()", q"<>", q"{}"
+				/\bq"(?:\[[\s\S]*?\]|\([\s\S]*?\)|<[\s\S]*?>|\{[\s\S]*?\})"/.source,
+
+				// q"IDENT
+				// ...
+				// IDENT"
+				/\bq"((?!\d)\w+)$[\s\S]*?^\1"/.source,
+
+				// q"//", q"||", etc.
+				// eslint-disable-next-line regexp/strict
+				/\bq"(.)[\s\S]*?\2"/.source,
+
+				// eslint-disable-next-line regexp/strict
+				/(["`])(?:\\[\s\S]|(?!\3)[^\\])*\3[cwd]?/.source
+			].join('|'), 'm'),
+			greedy: true
+		},
+		{
+			pattern: /\bq\{(?:\{[^{}]*\}|[^{}])*\}/,
+			greedy: true,
+			alias: 'token-string'
+		}
+	],
+
+	// In order: $, keywords and special tokens, globally defined symbols
+	'keyword': /\$|\b(?:__(?:(?:DATE|EOF|FILE|FUNCTION|LINE|MODULE|PRETTY_FUNCTION|TIMESTAMP|TIME|VENDOR|VERSION)__|gshared|parameters|traits|vector)|abstract|alias|align|asm|assert|auto|body|bool|break|byte|case|cast|catch|cdouble|cent|cfloat|char|class|const|continue|creal|dchar|debug|default|delegate|delete|deprecated|do|double|dstring|else|enum|export|extern|false|final|finally|float|for|foreach|foreach_reverse|function|goto|idouble|if|ifloat|immutable|import|inout|int|interface|invariant|ireal|lazy|long|macro|mixin|module|new|nothrow|null|out|override|package|pragma|private|protected|ptrdiff_t|public|pure|real|ref|return|scope|shared|short|size_t|static|string|struct|super|switch|synchronized|template|this|throw|true|try|typedef|typeid|typeof|ubyte|ucent|uint|ulong|union|unittest|ushort|version|void|volatile|wchar|while|with|wstring)\b/,
+
+	'number': [
+		// The lookbehind and the negative look-ahead try to prevent bad highlighting of the .. operator
+		// Hexadecimal numbers must be handled separately to avoid problems with exponent "e"
+		/\b0x\.?[a-f\d_]+(?:(?!\.\.)\.[a-f\d_]*)?(?:p[+-]?[a-f\d_]+)?[ulfi]{0,4}/i,
+		{
+			pattern: /((?:\.\.)?)(?:\b0b\.?|\b|\.)\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:e[+-]?\d[\d_]*)?[ulfi]{0,4}/i,
+			lookbehind: true
+		}
+	],
+
+	'operator': /\|[|=]?|&[&=]?|\+[+=]?|-[-=]?|\.?\.\.|=[>=]?|!(?:i[ns]\b|<>?=?|>=?|=)?|\bi[ns]\b|(?:<[<>]?|>>?>?|\^\^|[*\/%^~])=?/
 });
 
-Prism.languages.insertBefore("d", "string", {
-  // Characters
-  // 'a', '\\', '\n', '\xFF', '\377', '\uFFFF', '\U0010FFFF', '\quot'
-  char: /'(?:\\(?:\W|\w+)|[^\\])'/,
+Prism.languages.insertBefore('d', 'string', {
+	// Characters
+	// 'a', '\\', '\n', '\xFF', '\377', '\uFFFF', '\U0010FFFF', '\quot'
+	'char': /'(?:\\(?:\W|\w+)|[^\\])'/
 });
 
-Prism.languages.insertBefore("d", "keyword", {
-  property: /\B@\w*/,
+Prism.languages.insertBefore('d', 'keyword', {
+	'property': /\B@\w*/
 });
 
-Prism.languages.insertBefore("d", "function", {
-  register: {
-    // Iasm registers
-    pattern:
-      /\b(?:[ABCD][LHX]|E?(?:BP|DI|SI|SP)|[BS]PL|[ECSDGF]S|CR[0234]|[DS]IL|DR[012367]|E[ABCD]X|X?MM[0-7]|R(?:1[0-5]|[89])[BWD]?|R[ABCD]X|R[BS]P|R[DS]I|TR[3-7]|XMM(?:1[0-5]|[89])|YMM(?:1[0-5]|\d))\b|\bST(?:\([0-7]\)|\b)/,
-    alias: "variable",
-  },
+Prism.languages.insertBefore('d', 'function', {
+	'register': {
+		// Iasm registers
+		pattern: /\b(?:[ABCD][LHX]|E?(?:BP|DI|SI|SP)|[BS]PL|[ECSDGF]S|CR[0234]|[DS]IL|DR[012367]|E[ABCD]X|X?MM[0-7]|R(?:1[0-5]|[89])[BWD]?|R[ABCD]X|R[BS]P|R[DS]I|TR[3-7]|XMM(?:1[0-5]|[89])|YMM(?:1[0-5]|\d))\b|\bST(?:\([0-7]\)|\b)/,
+		alias: 'variable'
+	}
 });
 
 (function (Prism) {
-  var keywords = [
-    /\b(?:async|sync|yield)\*/,
-    /\b(?:abstract|assert|async|await|break|case|catch|class|const|continue|covariant|default|deferred|do|dynamic|else|enum|export|extends|extension|external|factory|final|finally|for|get|hide|if|implements|import|in|interface|library|mixin|new|null|on|operator|part|rethrow|return|set|show|static|super|switch|sync|this|throw|try|typedef|var|void|while|with|yield)\b/,
-  ];
-
-  // Handles named imports, such as http.Client
-  var packagePrefix = /(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/
-    .source;
-
-  // based on the dart naming conventions
-  var className = {
-    pattern: RegExp(packagePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),
-    lookbehind: true,
-    inside: {
-      namespace: {
-        pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,
-        inside: {
-          punctuation: /\./,
-        },
-      },
-    },
-  };
-
-  Prism.languages.dart = Prism.languages.extend("clike", {
-    "class-name": [
-      className,
-      {
-        // variables and parameters
-        // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods)
-        pattern: RegExp(packagePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),
-        lookbehind: true,
-        inside: className.inside,
-      },
-    ],
-    keyword: keywords,
-    operator:
-      /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/,
-  });
-
-  Prism.languages.insertBefore("dart", "string", {
-    "string-literal": {
-      pattern:
-        /r?(?:("""|''')[\s\S]*?\1|(["'])(?:\\.|(?!\2)[^\\\r\n])*\2(?!\2))/,
-      greedy: true,
-      inside: {
-        interpolation: {
-          pattern: /((?:^|[^\\])(?:\\{2})*)\$(?:\w+|\{(?:[^{}]|\{[^{}]*\})*\})/,
-          lookbehind: true,
-          inside: {
-            punctuation: /^\$\{?|\}$/,
-            expression: {
-              pattern: /[\s\S]+/,
-              inside: Prism.languages.dart,
-            },
-          },
-        },
-        string: /[\s\S]+/,
-      },
-    },
-    string: undefined,
-  });
-
-  Prism.languages.insertBefore("dart", "class-name", {
-    metadata: {
-      pattern: /@\w+/,
-      alias: "function",
-    },
-  });
-
-  Prism.languages.insertBefore("dart", "class-name", {
-    generics: {
-      pattern:
-        /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,
-      inside: {
-        "class-name": className,
-        keyword: keywords,
-        punctuation: /[<>(),.:]/,
-        operator: /[?&|]/,
-      },
-    },
-  });
-})(Prism);
+	var keywords = [
+		/\b(?:async|sync|yield)\*/,
+		/\b(?:abstract|assert|async|await|break|case|catch|class|const|continue|covariant|default|deferred|do|dynamic|else|enum|export|extends|extension|external|factory|final|finally|for|get|hide|if|implements|import|in|interface|library|mixin|new|null|on|operator|part|rethrow|return|set|show|static|super|switch|sync|this|throw|try|typedef|var|void|while|with|yield)\b/
+	];
+
+	// Handles named imports, such as http.Client
+	var packagePrefix = /(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source;
+
+	// based on the dart naming conventions
+	var className = {
+		pattern: RegExp(packagePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),
+		lookbehind: true,
+		inside: {
+			'namespace': {
+				pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,
+				inside: {
+					'punctuation': /\./
+				}
+			},
+		}
+	};
+
+	Prism.languages.dart = Prism.languages.extend('clike', {
+		'class-name': [
+			className,
+			{
+				// variables and parameters
+				// this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods)
+				pattern: RegExp(packagePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),
+				lookbehind: true,
+				inside: className.inside
+			}
+		],
+		'keyword': keywords,
+		'operator': /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/
+	});
+
+	Prism.languages.insertBefore('dart', 'string', {
+		'string-literal': {
+			pattern: /r?(?:("""|''')[\s\S]*?\1|(["'])(?:\\.|(?!\2)[^\\\r\n])*\2(?!\2))/,
+			greedy: true,
+			inside: {
+				'interpolation': {
+					pattern: /((?:^|[^\\])(?:\\{2})*)\$(?:\w+|\{(?:[^{}]|\{[^{}]*\})*\})/,
+					lookbehind: true,
+					inside: {
+						'punctuation': /^\$\{?|\}$/,
+						'expression': {
+							pattern: /[\s\S]+/,
+							inside: Prism.languages.dart
+						}
+					}
+				},
+				'string': /[\s\S]+/
+			}
+		},
+		'string': undefined
+	});
+
+	Prism.languages.insertBefore('dart', 'class-name', {
+		'metadata': {
+			pattern: /@\w+/,
+			alias: 'function'
+		}
+	});
+
+	Prism.languages.insertBefore('dart', 'class-name', {
+		'generics': {
+			pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,
+			inside: {
+				'class-name': className,
+				'keyword': keywords,
+				'punctuation': /[<>(),.:]/,
+				'operator': /[?&|]/
+			}
+		},
+	});
+}(Prism));
 
 (function (Prism) {
-  Prism.languages.diff = {
-    coord: [
-      // Match all kinds of coord lines (prefixed by "+++", "---" or "***").
-      /^(?:\*{3}|-{3}|\+{3}).*$/m,
-      // Match "@@ ... @@" coord lines in unified diff.
-      /^@@.*@@$/m,
-      // Match coord lines in normal diff (starts with a number).
-      /^\d.*$/m,
-    ],
-
-    // deleted, inserted, unchanged, diff
-  };
-
-  /**
-   * A map from the name of a block to its line prefix.
-   *
-   * @type {Object<string, string>}
-   */
-  var PREFIXES = {
-    "deleted-sign": "-",
-    "deleted-arrow": "<",
-    "inserted-sign": "+",
-    "inserted-arrow": ">",
-    unchanged: " ",
-    diff: "!",
-  };
-
-  // add a token for each prefix
-  Object.keys(PREFIXES).forEach(function (name) {
-    var prefix = PREFIXES[name];
-
-    var alias = [];
-    if (!/^\w+$/.test(name)) {
-      // "deleted-sign" -> "deleted"
-      alias.push(/\w+/.exec(name)[0]);
-    }
-    if (name === "diff") {
-      alias.push("bold");
-    }
-
-    Prism.languages.diff[name] = {
-      pattern: RegExp("^(?:[" + prefix + "].*(?:\r\n?|\n|(?![\\s\\S])))+", "m"),
-      alias: alias,
-      inside: {
-        line: {
-          pattern: /(.)(?=[\s\S]).*(?:\r\n?|\n)?/,
-          lookbehind: true,
-        },
-        prefix: {
-          pattern: /[\s\S]/,
-          alias: /\w+/.exec(name)[0],
-        },
-      },
-    };
-  });
-
-  // make prefixes available to Diff plugin
-  Object.defineProperty(Prism.languages.diff, "PREFIXES", {
-    value: PREFIXES,
-  });
-})(Prism);
+
+	Prism.languages.diff = {
+		'coord': [
+			// Match all kinds of coord lines (prefixed by "+++", "---" or "***").
+			/^(?:\*{3}|-{3}|\+{3}).*$/m,
+			// Match "@@ ... @@" coord lines in unified diff.
+			/^@@.*@@$/m,
+			// Match coord lines in normal diff (starts with a number).
+			/^\d.*$/m
+		]
+
+		// deleted, inserted, unchanged, diff
+	};
+
+	/**
+	 * A map from the name of a block to its line prefix.
+	 *
+	 * @type {Object<string, string>}
+	 */
+	var PREFIXES = {
+		'deleted-sign': '-',
+		'deleted-arrow': '<',
+		'inserted-sign': '+',
+		'inserted-arrow': '>',
+		'unchanged': ' ',
+		'diff': '!',
+	};
+
+	// add a token for each prefix
+	Object.keys(PREFIXES).forEach(function (name) {
+		var prefix = PREFIXES[name];
+
+		var alias = [];
+		if (!/^\w+$/.test(name)) { // "deleted-sign" -> "deleted"
+			alias.push(/\w+/.exec(name)[0]);
+		}
+		if (name === 'diff') {
+			alias.push('bold');
+		}
+
+		Prism.languages.diff[name] = {
+			pattern: RegExp('^(?:[' + prefix + '].*(?:\r\n?|\n|(?![\\s\\S])))+', 'm'),
+			alias: alias,
+			inside: {
+				'line': {
+					pattern: /(.)(?=[\s\S]).*(?:\r\n?|\n)?/,
+					lookbehind: true
+				},
+				'prefix': {
+					pattern: /[\s\S]/,
+					alias: /\w+/.exec(name)[0]
+				}
+			}
+		};
+
+	});
+
+	// make prefixes available to Diff plugin
+	Object.defineProperty(Prism.languages.diff, 'PREFIXES', {
+		value: PREFIXES
+	});
+
+}(Prism));
 
 (function (Prism) {
-  /**
-   * Returns the placeholder for the given language id and index.
-   *
-   * @param {string} language
-   * @param {string|number} index
-   * @returns {string}
-   */
-  function getPlaceholder(language, index) {
-    return "___" + language.toUpperCase() + index + "___";
-  }
-
-  Object.defineProperties((Prism.languages["markup-templating"] = {}), {
-    buildPlaceholders: {
-      /**
-       * Tokenize all inline templating expressions matching `placeholderPattern`.
-       *
-       * If `replaceFilter` is provided, only matches of `placeholderPattern` for which `replaceFilter` returns
-       * `true` will be replaced.
-       *
-       * @param {object} env The environment of the `before-tokenize` hook.
-       * @param {string} language The language id.
-       * @param {RegExp} placeholderPattern The matches of this pattern will be replaced by placeholders.
-       * @param {(match: string) => boolean} [replaceFilter]
-       */
-      value: function (env, language, placeholderPattern, replaceFilter) {
-        if (env.language !== language) {
-          return;
-        }
-
-        var tokenStack = (env.tokenStack = []);
-
-        env.code = env.code.replace(placeholderPattern, function (match) {
-          if (typeof replaceFilter === "function" && !replaceFilter(match)) {
-            return match;
-          }
-          var i = tokenStack.length;
-          var placeholder;
-
-          // Check for existing strings
-          while (
-            env.code.indexOf((placeholder = getPlaceholder(language, i))) !== -1
-          ) {
-            ++i;
-          }
-
-          // Create a sparse array
-          tokenStack[i] = match;
-
-          return placeholder;
-        });
-
-        // Switch the grammar to markup
-        env.grammar = Prism.languages.markup;
-      },
-    },
-    tokenizePlaceholders: {
-      /**
-       * Replace placeholders with proper tokens after tokenizing.
-       *
-       * @param {object} env The environment of the `after-tokenize` hook.
-       * @param {string} language The language id.
-       */
-      value: function (env, language) {
-        if (env.language !== language || !env.tokenStack) {
-          return;
-        }
-
-        // Switch the grammar back
-        env.grammar = Prism.languages[language];
-
-        var j = 0;
-        var keys = Object.keys(env.tokenStack);
-
-        function walkTokens(tokens) {
-          for (var i = 0; i < tokens.length; i++) {
-            // all placeholders are replaced already
-            if (j >= keys.length) {
-              break;
-            }
-
-            var token = tokens[i];
-            if (
-              typeof token === "string" ||
-              (token.content && typeof token.content === "string")
-            ) {
-              var k = keys[j];
-              var t = env.tokenStack[k];
-              var s = typeof token === "string" ? token : token.content;
-              var placeholder = getPlaceholder(language, k);
-
-              var index = s.indexOf(placeholder);
-              if (index > -1) {
-                ++j;
-
-                var before = s.substring(0, index);
-                var middle = new Prism.Token(
-                  language,
-                  Prism.tokenize(t, env.grammar),
-                  "language-" + language,
-                  t,
-                );
-                var after = s.substring(index + placeholder.length);
-
-                var replacement = [];
-                if (before) {
-                  replacement.push.apply(replacement, walkTokens([before]));
-                }
-                replacement.push(middle);
-                if (after) {
-                  replacement.push.apply(replacement, walkTokens([after]));
-                }
-
-                if (typeof token === "string") {
-                  tokens.splice.apply(tokens, [i, 1].concat(replacement));
-                } else {
-                  token.content = replacement;
-                }
-              }
-            } else if (
-              token.content /* && typeof token.content !== 'string' */
-            ) {
-              walkTokens(token.content);
-            }
-          }
-
-          return tokens;
-        }
-
-        walkTokens(env.tokens);
-      },
-    },
-  });
-})(Prism);
+
+	/**
+	 * Returns the placeholder for the given language id and index.
+	 *
+	 * @param {string} language
+	 * @param {string|number} index
+	 * @returns {string}
+	 */
+	function getPlaceholder(language, index) {
+		return '___' + language.toUpperCase() + index + '___';
+	}
+
+	Object.defineProperties(Prism.languages['markup-templating'] = {}, {
+		buildPlaceholders: {
+			/**
+			 * Tokenize all inline templating expressions matching `placeholderPattern`.
+			 *
+			 * If `replaceFilter` is provided, only matches of `placeholderPattern` for which `replaceFilter` returns
+			 * `true` will be replaced.
+			 *
+			 * @param {object} env The environment of the `before-tokenize` hook.
+			 * @param {string} language The language id.
+			 * @param {RegExp} placeholderPattern The matches of this pattern will be replaced by placeholders.
+			 * @param {(match: string) => boolean} [replaceFilter]
+			 */
+			value: function (env, language, placeholderPattern, replaceFilter) {
+				if (env.language !== language) {
+					return;
+				}
+
+				var tokenStack = env.tokenStack = [];
+
+				env.code = env.code.replace(placeholderPattern, function (match) {
+					if (typeof replaceFilter === 'function' && !replaceFilter(match)) {
+						return match;
+					}
+					var i = tokenStack.length;
+					var placeholder;
+
+					// Check for existing strings
+					while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1) {
+						++i;
+					}
+
+					// Create a sparse array
+					tokenStack[i] = match;
+
+					return placeholder;
+				});
+
+				// Switch the grammar to markup
+				env.grammar = Prism.languages.markup;
+			}
+		},
+		tokenizePlaceholders: {
+			/**
+			 * Replace placeholders with proper tokens after tokenizing.
+			 *
+			 * @param {object} env The environment of the `after-tokenize` hook.
+			 * @param {string} language The language id.
+			 */
+			value: function (env, language) {
+				if (env.language !== language || !env.tokenStack) {
+					return;
+				}
+
+				// Switch the grammar back
+				env.grammar = Prism.languages[language];
+
+				var j = 0;
+				var keys = Object.keys(env.tokenStack);
+
+				function walkTokens(tokens) {
+					for (var i = 0; i < tokens.length; i++) {
+						// all placeholders are replaced already
+						if (j >= keys.length) {
+							break;
+						}
+
+						var token = tokens[i];
+						if (typeof token === 'string' || (token.content && typeof token.content === 'string')) {
+							var k = keys[j];
+							var t = env.tokenStack[k];
+							var s = typeof token === 'string' ? token : token.content;
+							var placeholder = getPlaceholder(language, k);
+
+							var index = s.indexOf(placeholder);
+							if (index > -1) {
+								++j;
+
+								var before = s.substring(0, index);
+								var middle = new Prism.Token(language, Prism.tokenize(t, env.grammar), 'language-' + language, t);
+								var after = s.substring(index + placeholder.length);
+
+								var replacement = [];
+								if (before) {
+									replacement.push.apply(replacement, walkTokens([before]));
+								}
+								replacement.push(middle);
+								if (after) {
+									replacement.push.apply(replacement, walkTokens([after]));
+								}
+
+								if (typeof token === 'string') {
+									tokens.splice.apply(tokens, [i, 1].concat(replacement));
+								} else {
+									token.content = replacement;
+								}
+							}
+						} else if (token.content /* && typeof token.content !== 'string' */) {
+							walkTokens(token.content);
+						}
+					}
+
+					return tokens;
+				}
+
+				walkTokens(env.tokens);
+			}
+		}
+	});
+
+}(Prism));
 
 // Django/Jinja2 syntax definition for Prism.js <http://prismjs.com> syntax highlighter.
 // Mostly it works OK but can paint code incorrectly on complex html/template tag combinations.
 
 (function (Prism) {
-  Prism.languages.django = {
-    comment: /^\{#[\s\S]*?#\}$/,
-    tag: {
-      pattern: /(^\{%[+-]?\s*)\w+/,
-      lookbehind: true,
-      alias: "keyword",
-    },
-    delimiter: {
-      pattern: /^\{[{%][+-]?|[+-]?[}%]\}$/,
-      alias: "punctuation",
-    },
-    string: {
-      pattern: /("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,
-      greedy: true,
-    },
-    filter: {
-      pattern: /(\|)\w+/,
-      lookbehind: true,
-      alias: "function",
-    },
-    test: {
-      pattern: /(\bis\s+(?:not\s+)?)(?!not\b)\w+/,
-      lookbehind: true,
-      alias: "function",
-    },
-    function: /\b[a-z_]\w+(?=\s*\()/i,
-    keyword:
-      /\b(?:and|as|by|else|for|if|import|in|is|loop|not|or|recursive|with|without)\b/,
-    operator: /[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,
-    number: /\b\d+(?:\.\d+)?\b/,
-    boolean: /[Ff]alse|[Nn]one|[Tt]rue/,
-    variable: /\b\w+\b/,
-    punctuation: /[{}[\](),.:;]/,
-  };
-
-  var pattern = /\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}|\{#[\s\S]*?#\}/g;
-  var markupTemplating = Prism.languages["markup-templating"];
-
-  Prism.hooks.add("before-tokenize", function (env) {
-    markupTemplating.buildPlaceholders(env, "django", pattern);
-  });
-  Prism.hooks.add("after-tokenize", function (env) {
-    markupTemplating.tokenizePlaceholders(env, "django");
-  });
-
-  // Add an Jinja2 alias
-  Prism.languages.jinja2 = Prism.languages.django;
-  Prism.hooks.add("before-tokenize", function (env) {
-    markupTemplating.buildPlaceholders(env, "jinja2", pattern);
-  });
-  Prism.hooks.add("after-tokenize", function (env) {
-    markupTemplating.tokenizePlaceholders(env, "jinja2");
-  });
-})(Prism);
+
+	Prism.languages.django = {
+		'comment': /^\{#[\s\S]*?#\}$/,
+		'tag': {
+			pattern: /(^\{%[+-]?\s*)\w+/,
+			lookbehind: true,
+			alias: 'keyword'
+		},
+		'delimiter': {
+			pattern: /^\{[{%][+-]?|[+-]?[}%]\}$/,
+			alias: 'punctuation'
+		},
+		'string': {
+			pattern: /("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,
+			greedy: true
+		},
+		'filter': {
+			pattern: /(\|)\w+/,
+			lookbehind: true,
+			alias: 'function'
+		},
+		'test': {
+			pattern: /(\bis\s+(?:not\s+)?)(?!not\b)\w+/,
+			lookbehind: true,
+			alias: 'function'
+		},
+		'function': /\b[a-z_]\w+(?=\s*\()/i,
+		'keyword': /\b(?:and|as|by|else|for|if|import|in|is|loop|not|or|recursive|with|without)\b/,
+		'operator': /[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,
+		'number': /\b\d+(?:\.\d+)?\b/,
+		'boolean': /[Ff]alse|[Nn]one|[Tt]rue/,
+		'variable': /\b\w+\b/,
+		'punctuation': /[{}[\](),.:;]/
+	};
+
+
+	var pattern = /\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}|\{#[\s\S]*?#\}/g;
+	var markupTemplating = Prism.languages['markup-templating'];
+
+	Prism.hooks.add('before-tokenize', function (env) {
+		markupTemplating.buildPlaceholders(env, 'django', pattern);
+	});
+	Prism.hooks.add('after-tokenize', function (env) {
+		markupTemplating.tokenizePlaceholders(env, 'django');
+	});
+
+	// Add an Jinja2 alias
+	Prism.languages.jinja2 = Prism.languages.django;
+	Prism.hooks.add('before-tokenize', function (env) {
+		markupTemplating.buildPlaceholders(env, 'jinja2', pattern);
+	});
+	Prism.hooks.add('after-tokenize', function (env) {
+		markupTemplating.tokenizePlaceholders(env, 'jinja2');
+	});
+
+}(Prism));
 
 Prism.languages.elixir = {
-  doc: {
-    pattern:
-      /@(?:doc|moduledoc)\s+(?:("""|''')[\s\S]*?\1|("|')(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2)/,
-    inside: {
-      attribute: /^@\w+/,
-      string: /['"][\s\S]+/,
-    },
-  },
-  comment: {
-    pattern: /#.*/,
-    greedy: true,
-  },
-  // ~r"""foo""" (multi-line), ~r'''foo''' (multi-line), ~r/foo/, ~r|foo|, ~r"foo", ~r'foo', ~r(foo), ~r[foo], ~r{foo}, ~r<foo>
-  regex: {
-    pattern:
-      /~[rR](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|[^\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[uismxfr]*/,
-    greedy: true,
-  },
-  string: [
-    {
-      // ~s"""foo""" (multi-line), ~s'''foo''' (multi-line), ~s/foo/, ~s|foo|, ~s"foo", ~s'foo', ~s(foo), ~s[foo], ~s{foo} (with interpolation care), ~s<foo>
-      pattern:
-        /~[cCsSwW](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|#\{[^}]+\}|#(?!\{)|[^#\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[csa]?/,
-      greedy: true,
-      inside: {
-        // See interpolation below
-      },
-    },
-    {
-      pattern: /("""|''')[\s\S]*?\1/,
-      greedy: true,
-      inside: {
-        // See interpolation below
-      },
-    },
-    {
-      // Multi-line strings are allowed
-      pattern: /("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
-      greedy: true,
-      inside: {
-        // See interpolation below
-      },
-    },
-  ],
-  atom: {
-    // Look-behind prevents bad highlighting of the :: operator
-    pattern: /(^|[^:]):\w+/,
-    lookbehind: true,
-    alias: "symbol",
-  },
-  module: {
-    pattern: /\b[A-Z]\w*\b/,
-    alias: "class-name",
-  },
-  // Look-ahead prevents bad highlighting of the :: operator
-  "attr-name": /\b\w+\??:(?!:)/,
-  argument: {
-    // Look-behind prevents bad highlighting of the && operator
-    pattern: /(^|[^&])&\d+/,
-    lookbehind: true,
-    alias: "variable",
-  },
-  attribute: {
-    pattern: /@\w+/,
-    alias: "variable",
-  },
-  function: /\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d))/,
-  number: /\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,
-  keyword:
-    /\b(?:after|alias|and|case|catch|cond|def(?:callback|delegate|exception|impl|macro|module|n|np|p|protocol|struct)?|do|else|end|fn|for|if|import|not|or|quote|raise|require|rescue|try|unless|unquote|use|when)\b/,
-  boolean: /\b(?:false|nil|true)\b/,
-  operator: [
-    /\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,
-    {
-      // We don't want to match <<
-      pattern: /([^<])<(?!<)/,
-      lookbehind: true,
-    },
-    {
-      // We don't want to match >>
-      pattern: /([^>])>(?!>)/,
-      lookbehind: true,
-    },
-  ],
-  punctuation: /<<|>>|[.,%\[\]{}()]/,
+	'doc': {
+		pattern: /@(?:doc|moduledoc)\s+(?:("""|''')[\s\S]*?\1|("|')(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2)/,
+		inside: {
+			'attribute': /^@\w+/,
+			'string': /['"][\s\S]+/
+		}
+	},
+	'comment': {
+		pattern: /#.*/,
+		greedy: true
+	},
+	// ~r"""foo""" (multi-line), ~r'''foo''' (multi-line), ~r/foo/, ~r|foo|, ~r"foo", ~r'foo', ~r(foo), ~r[foo], ~r{foo}, ~r<foo>
+	'regex': {
+		pattern: /~[rR](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|[^\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[uismxfr]*/,
+		greedy: true
+	},
+	'string': [
+		{
+			// ~s"""foo""" (multi-line), ~s'''foo''' (multi-line), ~s/foo/, ~s|foo|, ~s"foo", ~s'foo', ~s(foo), ~s[foo], ~s{foo} (with interpolation care), ~s<foo>
+			pattern: /~[cCsSwW](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|#\{[^}]+\}|#(?!\{)|[^#\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[csa]?/,
+			greedy: true,
+			inside: {
+				// See interpolation below
+			}
+		},
+		{
+			pattern: /("""|''')[\s\S]*?\1/,
+			greedy: true,
+			inside: {
+				// See interpolation below
+			}
+		},
+		{
+			// Multi-line strings are allowed
+			pattern: /("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
+			greedy: true,
+			inside: {
+				// See interpolation below
+			}
+		}
+	],
+	'atom': {
+		// Look-behind prevents bad highlighting of the :: operator
+		pattern: /(^|[^:]):\w+/,
+		lookbehind: true,
+		alias: 'symbol'
+	},
+	'module': {
+		pattern: /\b[A-Z]\w*\b/,
+		alias: 'class-name'
+	},
+	// Look-ahead prevents bad highlighting of the :: operator
+	'attr-name': /\b\w+\??:(?!:)/,
+	'argument': {
+		// Look-behind prevents bad highlighting of the && operator
+		pattern: /(^|[^&])&\d+/,
+		lookbehind: true,
+		alias: 'variable'
+	},
+	'attribute': {
+		pattern: /@\w+/,
+		alias: 'variable'
+	},
+	'function': /\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d))/,
+	'number': /\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,
+	'keyword': /\b(?:after|alias|and|case|catch|cond|def(?:callback|delegate|exception|impl|macro|module|n|np|p|protocol|struct)?|do|else|end|fn|for|if|import|not|or|quote|raise|require|rescue|try|unless|unquote|use|when)\b/,
+	'boolean': /\b(?:false|nil|true)\b/,
+	'operator': [
+		/\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,
+		{
+			// We don't want to match <<
+			pattern: /([^<])<(?!<)/,
+			lookbehind: true
+		},
+		{
+			// We don't want to match >>
+			pattern: /([^>])>(?!>)/,
+			lookbehind: true
+		}
+	],
+	'punctuation': /<<|>>|[.,%\[\]{}()]/
 };
 
 Prism.languages.elixir.string.forEach(function (o) {
-  o.inside = {
-    interpolation: {
-      pattern: /#\{[^}]+\}/,
-      inside: {
-        delimiter: {
-          pattern: /^#\{|\}$/,
-          alias: "punctuation",
-        },
-        rest: Prism.languages.elixir,
-      },
-    },
-  };
+	o.inside = {
+		'interpolation': {
+			pattern: /#\{[^}]+\}/,
+			inside: {
+				'delimiter': {
+					pattern: /^#\{|\}$/,
+					alias: 'punctuation'
+				},
+				rest: Prism.languages.elixir
+			}
+		}
+	};
 });
 
 Prism.languages.erlang = {
-  comment: /%.+/,
-  string: {
-    pattern: /"(?:\\.|[^\\"\r\n])*"/,
-    greedy: true,
-  },
-  "quoted-function": {
-    pattern: /'(?:\\.|[^\\'\r\n])+'(?=\()/,
-    alias: "function",
-  },
-  "quoted-atom": {
-    pattern: /'(?:\\.|[^\\'\r\n])+'/,
-    alias: "atom",
-  },
-  boolean: /\b(?:false|true)\b/,
-  keyword: /\b(?:after|begin|case|catch|end|fun|if|of|receive|try|when)\b/,
-  number: [
-    /\$\\?./,
-    /\b\d+#[a-z0-9]+/i,
-    /(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
-  ],
-  function: /\b[a-z][\w@]*(?=\()/,
-  variable: {
-    // Look-behind is used to prevent wrong highlighting of atoms containing "@"
-    pattern: /(^|[^@])(?:\b|\?)[A-Z_][\w@]*/,
-    lookbehind: true,
-  },
-  operator: [
-    /[=\/<>:]=|=[:\/]=|\+\+?|--?|[=*\/!]|\b(?:and|andalso|band|bnot|bor|bsl|bsr|bxor|div|not|or|orelse|rem|xor)\b/,
-    {
-      // We don't want to match <<
-      pattern: /(^|[^<])<(?!<)/,
-      lookbehind: true,
-    },
-    {
-      // We don't want to match >>
-      pattern: /(^|[^>])>(?!>)/,
-      lookbehind: true,
-    },
-  ],
-  atom: /\b[a-z][\w@]*/,
-  punctuation: /[()[\]{}:;,.#|]|<<|>>/,
+	'comment': /%.+/,
+	'string': {
+		pattern: /"(?:\\.|[^\\"\r\n])*"/,
+		greedy: true
+	},
+	'quoted-function': {
+		pattern: /'(?:\\.|[^\\'\r\n])+'(?=\()/,
+		alias: 'function'
+	},
+	'quoted-atom': {
+		pattern: /'(?:\\.|[^\\'\r\n])+'/,
+		alias: 'atom'
+	},
+	'boolean': /\b(?:false|true)\b/,
+	'keyword': /\b(?:after|begin|case|catch|end|fun|if|of|receive|try|when)\b/,
+	'number': [
+		/\$\\?./,
+		/\b\d+#[a-z0-9]+/i,
+		/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i
+	],
+	'function': /\b[a-z][\w@]*(?=\()/,
+	'variable': {
+		// Look-behind is used to prevent wrong highlighting of atoms containing "@"
+		pattern: /(^|[^@])(?:\b|\?)[A-Z_][\w@]*/,
+		lookbehind: true
+	},
+	'operator': [
+		/[=\/<>:]=|=[:\/]=|\+\+?|--?|[=*\/!]|\b(?:and|andalso|band|bnot|bor|bsl|bsr|bxor|div|not|or|orelse|rem|xor)\b/,
+		{
+			// We don't want to match <<
+			pattern: /(^|[^<])<(?!<)/,
+			lookbehind: true
+		},
+		{
+			// We don't want to match >>
+			pattern: /(^|[^>])>(?!>)/,
+			lookbehind: true
+		}
+	],
+	'atom': /\b[a-z][\w@]*/,
+	'punctuation': /[()[\]{}:;,.#|]|<<|>>/
+
 };
 
-Prism.languages.go = Prism.languages.extend("clike", {
-  string: {
-    pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,
-    lookbehind: true,
-    greedy: true,
-  },
-  keyword:
-    /\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,
-  boolean: /\b(?:_|false|iota|nil|true)\b/,
-  number: [
-    // binary and octal integers
-    /\b0(?:b[01_]+|o[0-7_]+)i?\b/i,
-    // hexadecimal integers and floats
-    /\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,
-    // decimal integers and floats
-    /(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i,
-  ],
-  operator:
-    /[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,
-  builtin:
-    /\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/,
+Prism.languages.go = Prism.languages.extend('clike', {
+	'string': {
+		pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,
+		lookbehind: true,
+		greedy: true
+	},
+	'keyword': /\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,
+	'boolean': /\b(?:_|false|iota|nil|true)\b/,
+	'number': [
+		// binary and octal integers
+		/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,
+		// hexadecimal integers and floats
+		/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,
+		// decimal integers and floats
+		/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i
+	],
+	'operator': /[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,
+	'builtin': /\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/
 });
 
-Prism.languages.insertBefore("go", "string", {
-  char: {
-    pattern: /'(?:\\.|[^'\\\r\n]){0,10}'/,
-    greedy: true,
-  },
+Prism.languages.insertBefore('go', 'string', {
+	'char': {
+		pattern: /'(?:\\.|[^'\\\r\n]){0,10}'/,
+		greedy: true
+	}
 });
 
-delete Prism.languages.go["class-name"];
+delete Prism.languages.go['class-name'];
 
 (function (Prism) {
-  var interpolation = {
-    pattern: /((?:^|[^\\$])(?:\\{2})*)\$(?:\w+|\{[^{}]*\})/,
-    lookbehind: true,
-    inside: {
-      "interpolation-punctuation": {
-        pattern: /^\$\{?|\}$/,
-        alias: "punctuation",
-      },
-      expression: {
-        pattern: /[\s\S]+/,
-        inside: null, // see below
-      },
-    },
-  };
-
-  Prism.languages.groovy = Prism.languages.extend("clike", {
-    string: {
-      // https://groovy-lang.org/syntax.html#_dollar_slashy_string
-      pattern: /'''(?:[^\\]|\\[\s\S])*?'''|'(?:\\.|[^\\'\r\n])*'/,
-      greedy: true,
-    },
-    keyword:
-      /\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,
-    number:
-      /\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,
-    operator: {
-      pattern:
-        /(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,
-      lookbehind: true,
-    },
-    punctuation: /\.+|[{}[\];(),:$]/,
-  });
-
-  Prism.languages.insertBefore("groovy", "string", {
-    shebang: {
-      pattern: /#!.+/,
-      alias: "comment",
-      greedy: true,
-    },
-    "interpolation-string": {
-      // TODO: Slash strings (e.g. /foo/) can contain line breaks but this will cause a lot of trouble with
-      // simple division (see JS regex), so find a fix maybe?
-      pattern:
-        /"""(?:[^\\]|\\[\s\S])*?"""|(["/])(?:\\.|(?!\1)[^\\\r\n])*\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,
-      greedy: true,
-      inside: {
-        interpolation: interpolation,
-        string: /[\s\S]+/,
-      },
-    },
-  });
-
-  Prism.languages.insertBefore("groovy", "punctuation", {
-    "spock-block": /\b(?:and|cleanup|expect|given|setup|then|when|where):/,
-  });
-
-  Prism.languages.insertBefore("groovy", "function", {
-    annotation: {
-      pattern: /(^|[^.])@\w+/,
-      lookbehind: true,
-      alias: "punctuation",
-    },
-  });
-
-  interpolation.inside.expression.inside = Prism.languages.groovy;
-})(Prism);
+
+	var interpolation = {
+		pattern: /((?:^|[^\\$])(?:\\{2})*)\$(?:\w+|\{[^{}]*\})/,
+		lookbehind: true,
+		inside: {
+			'interpolation-punctuation': {
+				pattern: /^\$\{?|\}$/,
+				alias: 'punctuation'
+			},
+			'expression': {
+				pattern: /[\s\S]+/,
+				inside: null // see below
+			}
+		}
+	};
+
+	Prism.languages.groovy = Prism.languages.extend('clike', {
+		'string': {
+			// https://groovy-lang.org/syntax.html#_dollar_slashy_string
+			pattern: /'''(?:[^\\]|\\[\s\S])*?'''|'(?:\\.|[^\\'\r\n])*'/,
+			greedy: true
+		},
+		'keyword': /\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,
+		'number': /\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,
+		'operator': {
+			pattern: /(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,
+			lookbehind: true
+		},
+		'punctuation': /\.+|[{}[\];(),:$]/
+	});
+
+	Prism.languages.insertBefore('groovy', 'string', {
+		'shebang': {
+			pattern: /#!.+/,
+			alias: 'comment',
+			greedy: true
+		},
+		'interpolation-string': {
+			// TODO: Slash strings (e.g. /foo/) can contain line breaks but this will cause a lot of trouble with
+			// simple division (see JS regex), so find a fix maybe?
+			pattern: /"""(?:[^\\]|\\[\s\S])*?"""|(["/])(?:\\.|(?!\1)[^\\\r\n])*\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,
+			greedy: true,
+			inside: {
+				'interpolation': interpolation,
+				'string': /[\s\S]+/
+			}
+		}
+	});
+
+	Prism.languages.insertBefore('groovy', 'punctuation', {
+		'spock-block': /\b(?:and|cleanup|expect|given|setup|then|when|where):/
+	});
+
+	Prism.languages.insertBefore('groovy', 'function', {
+		'annotation': {
+			pattern: /(^|[^.])@\w+/,
+			lookbehind: true,
+			alias: 'punctuation'
+		}
+	});
+
+	interpolation.inside.expression.inside = Prism.languages.groovy;
+
+}(Prism));
 
 (function (Prism) {
-  var keywords =
-    /\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/;
-
-  // full package (optional) + parent classes (optional)
-  var classNamePrefix = /(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source;
-
-  // based on the java naming conventions
-  var className = {
-    pattern: RegExp(
-      /(^|[^\w.])/.source +
-        classNamePrefix +
-        /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source,
-    ),
-    lookbehind: true,
-    inside: {
-      namespace: {
-        pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,
-        inside: {
-          punctuation: /\./,
-        },
-      },
-      punctuation: /\./,
-    },
-  };
-
-  Prism.languages.java = Prism.languages.extend("clike", {
-    string: {
-      pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,
-      lookbehind: true,
-      greedy: true,
-    },
-    "class-name": [
-      className,
-      {
-        // variables, parameters, and constructor references
-        // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods)
-        pattern: RegExp(
-          /(^|[^\w.])/.source +
-            classNamePrefix +
-            /[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/
-              .source,
-        ),
-        lookbehind: true,
-        inside: className.inside,
-      },
-      {
-        // class names based on keyword
-        // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods)
-        pattern: RegExp(
-          /(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/
-            .source +
-            classNamePrefix +
-            /[A-Z]\w*\b/.source,
-        ),
-        lookbehind: true,
-        inside: className.inside,
-      },
-    ],
-    keyword: keywords,
-    function: [
-      Prism.languages.clike.function,
-      {
-        pattern: /(::\s*)[a-z_]\w*/,
-        lookbehind: true,
-      },
-    ],
-    number:
-      /\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,
-    operator: {
-      pattern:
-        /(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,
-      lookbehind: true,
-    },
-    constant: /\b[A-Z][A-Z_\d]+\b/,
-  });
-
-  Prism.languages.insertBefore("java", "string", {
-    "triple-quoted-string": {
-      // http://openjdk.java.net/jeps/355#Description
-      pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,
-      greedy: true,
-      alias: "string",
-    },
-    char: {
-      pattern: /'(?:\\.|[^'\\\r\n]){1,6}'/,
-      greedy: true,
-    },
-  });
-
-  Prism.languages.insertBefore("java", "class-name", {
-    annotation: {
-      pattern: /(^|[^.])@\w+(?:\s*\.\s*\w+)*/,
-      lookbehind: true,
-      alias: "punctuation",
-    },
-    generics: {
-      pattern:
-        /<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,
-      inside: {
-        "class-name": className,
-        keyword: keywords,
-        punctuation: /[<>(),.:]/,
-        operator: /[?&|]/,
-      },
-    },
-    import: [
-      {
-        pattern: RegExp(
-          /(\bimport\s+)/.source +
-            classNamePrefix +
-            /(?:[A-Z]\w*|\*)(?=\s*;)/.source,
-        ),
-        lookbehind: true,
-        inside: {
-          namespace: className.inside.namespace,
-          punctuation: /\./,
-          operator: /\*/,
-          "class-name": /\w+/,
-        },
-      },
-      {
-        pattern: RegExp(
-          /(\bimport\s+static\s+)/.source +
-            classNamePrefix +
-            /(?:\w+|\*)(?=\s*;)/.source,
-        ),
-        lookbehind: true,
-        alias: "static",
-        inside: {
-          namespace: className.inside.namespace,
-          static: /\b\w+$/,
-          punctuation: /\./,
-          operator: /\*/,
-          "class-name": /\w+/,
-        },
-      },
-    ],
-    namespace: {
-      pattern: RegExp(
-        /(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!<keyword>)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(
-          /<keyword>/g,
-          function () {
-            return keywords.source;
-          },
-        ),
-      ),
-      lookbehind: true,
-      inside: {
-        punctuation: /\./,
-      },
-    },
-  });
-})(Prism);
+
+	var keywords = /\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/;
+
+	// full package (optional) + parent classes (optional)
+	var classNamePrefix = /(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source;
+
+	// based on the java naming conventions
+	var className = {
+		pattern: RegExp(/(^|[^\w.])/.source + classNamePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),
+		lookbehind: true,
+		inside: {
+			'namespace': {
+				pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,
+				inside: {
+					'punctuation': /\./
+				}
+			},
+			'punctuation': /\./
+		}
+	};
+
+	Prism.languages.java = Prism.languages.extend('clike', {
+		'string': {
+			pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,
+			lookbehind: true,
+			greedy: true
+		},
+		'class-name': [
+			className,
+			{
+				// variables, parameters, and constructor references
+				// this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods)
+				pattern: RegExp(/(^|[^\w.])/.source + classNamePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),
+				lookbehind: true,
+				inside: className.inside
+			},
+			{
+				// class names based on keyword
+				// this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods)
+				pattern: RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source + classNamePrefix + /[A-Z]\w*\b/.source),
+				lookbehind: true,
+				inside: className.inside
+			}
+		],
+		'keyword': keywords,
+		'function': [
+			Prism.languages.clike.function,
+			{
+				pattern: /(::\s*)[a-z_]\w*/,
+				lookbehind: true
+			}
+		],
+		'number': /\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,
+		'operator': {
+			pattern: /(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,
+			lookbehind: true
+		},
+		'constant': /\b[A-Z][A-Z_\d]+\b/
+	});
+
+	Prism.languages.insertBefore('java', 'string', {
+		'triple-quoted-string': {
+			// http://openjdk.java.net/jeps/355#Description
+			pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,
+			greedy: true,
+			alias: 'string'
+		},
+		'char': {
+			pattern: /'(?:\\.|[^'\\\r\n]){1,6}'/,
+			greedy: true
+		}
+	});
+
+	Prism.languages.insertBefore('java', 'class-name', {
+		'annotation': {
+			pattern: /(^|[^.])@\w+(?:\s*\.\s*\w+)*/,
+			lookbehind: true,
+			alias: 'punctuation'
+		},
+		'generics': {
+			pattern: /<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,
+			inside: {
+				'class-name': className,
+				'keyword': keywords,
+				'punctuation': /[<>(),.:]/,
+				'operator': /[?&|]/
+			}
+		},
+		'import': [
+			{
+				pattern: RegExp(/(\bimport\s+)/.source + classNamePrefix + /(?:[A-Z]\w*|\*)(?=\s*;)/.source),
+				lookbehind: true,
+				inside: {
+					'namespace': className.inside.namespace,
+					'punctuation': /\./,
+					'operator': /\*/,
+					'class-name': /\w+/
+				}
+			},
+			{
+				pattern: RegExp(/(\bimport\s+static\s+)/.source + classNamePrefix + /(?:\w+|\*)(?=\s*;)/.source),
+				lookbehind: true,
+				alias: 'static',
+				inside: {
+					'namespace': className.inside.namespace,
+					'static': /\b\w+$/,
+					'punctuation': /\./,
+					'operator': /\*/,
+					'class-name': /\w+/
+				}
+			}
+		],
+		'namespace': {
+			pattern: RegExp(
+				/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!<keyword>)[a-z]\w*(?:\.[a-z]\w*)*\.?/
+					.source.replace(/<keyword>/g, function () { return keywords.source; })),
+			lookbehind: true,
+			inside: {
+				'punctuation': /\./,
+			}
+		}
+	});
+}(Prism));
 
 // https://www.json.org/json-en.html
 Prism.languages.json = {
-  property: {
-    pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,
-    lookbehind: true,
-    greedy: true,
-  },
-  string: {
-    pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,
-    lookbehind: true,
-    greedy: true,
-  },
-  comment: {
-    pattern: /\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,
-    greedy: true,
-  },
-  number: /-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,
-  punctuation: /[{}[\],]/,
-  operator: /:/,
-  boolean: /\b(?:false|true)\b/,
-  null: {
-    pattern: /\bnull\b/,
-    alias: "keyword",
-  },
+	'property': {
+		pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,
+		lookbehind: true,
+		greedy: true
+	},
+	'string': {
+		pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,
+		lookbehind: true,
+		greedy: true
+	},
+	'comment': {
+		pattern: /\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,
+		greedy: true
+	},
+	'number': /-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,
+	'punctuation': /[{}[\],]/,
+	'operator': /:/,
+	'boolean': /\b(?:false|true)\b/,
+	'null': {
+		pattern: /\bnull\b/,
+		alias: 'keyword'
+	}
 };
 
 Prism.languages.webmanifest = Prism.languages.json;
 
 Prism.languages.julia = {
-  comment: {
-    // support one level of nested comments
-    // https://github.com/JuliaLang/julia/pull/6128
-    pattern:
-      /(^|[^\\])(?:#=(?:[^#=]|=(?!#)|#(?!=)|#=(?:[^#=]|=(?!#)|#(?!=))*=#)*=#|#.*)/,
-    lookbehind: true,
-  },
-  regex: {
-    // https://docs.julialang.org/en/v1/manual/strings/#Regular-Expressions-1
-    pattern: /r"(?:\\.|[^"\\\r\n])*"[imsx]{0,4}/,
-    greedy: true,
-  },
-  string: {
-    // https://docs.julialang.org/en/v1/manual/strings/#String-Basics-1
-    // https://docs.julialang.org/en/v1/manual/strings/#non-standard-string-literals-1
-    // https://docs.julialang.org/en/v1/manual/running-external-programs/#Running-External-Programs-1
-    pattern:
-      /"""[\s\S]+?"""|(?:\b\w+)?"(?:\\.|[^"\\\r\n])*"|`(?:[^\\`\r\n]|\\.)*`/,
-    greedy: true,
-  },
-  char: {
-    // https://docs.julialang.org/en/v1/manual/strings/#man-characters-1
-    pattern: /(^|[^\w'])'(?:\\[^\r\n][^'\r\n]*|[^\\\r\n])'/,
-    lookbehind: true,
-    greedy: true,
-  },
-  keyword:
-    /\b(?:abstract|baremodule|begin|bitstype|break|catch|ccall|const|continue|do|else|elseif|end|export|finally|for|function|global|if|immutable|import|importall|in|let|local|macro|module|print|println|quote|return|struct|try|type|typealias|using|while)\b/,
-  boolean: /\b(?:false|true)\b/,
-  number:
-    /(?:\b(?=\d)|\B(?=\.))(?:0[box])?(?:[\da-f]+(?:_[\da-f]+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[efp][+-]?\d+(?:_\d+)*)?j?/i,
-  // https://docs.julialang.org/en/v1/manual/mathematical-operations/
-  // https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity-1
-  operator:
-    /&&|\|\||[-+*^%÷⊻&$\\]=?|\/[\/=]?|!=?=?|\|[=>]?|<(?:<=?|[=:|])?|>(?:=|>>?=?)?|==?=?|[~≠≤≥'√∛]/,
-  punctuation: /::?|[{}[\]();,.?]/,
-  // https://docs.julialang.org/en/v1/base/numbers/#Base.im
-  constant: /\b(?:(?:Inf|NaN)(?:16|32|64)?|im|pi)\b|[πℯ]/,
+	'comment': {
+		// support one level of nested comments
+		// https://github.com/JuliaLang/julia/pull/6128
+		pattern: /(^|[^\\])(?:#=(?:[^#=]|=(?!#)|#(?!=)|#=(?:[^#=]|=(?!#)|#(?!=))*=#)*=#|#.*)/,
+		lookbehind: true
+	},
+	'regex': {
+		// https://docs.julialang.org/en/v1/manual/strings/#Regular-Expressions-1
+		pattern: /r"(?:\\.|[^"\\\r\n])*"[imsx]{0,4}/,
+		greedy: true
+	},
+	'string': {
+		// https://docs.julialang.org/en/v1/manual/strings/#String-Basics-1
+		// https://docs.julialang.org/en/v1/manual/strings/#non-standard-string-literals-1
+		// https://docs.julialang.org/en/v1/manual/running-external-programs/#Running-External-Programs-1
+		pattern: /"""[\s\S]+?"""|(?:\b\w+)?"(?:\\.|[^"\\\r\n])*"|`(?:[^\\`\r\n]|\\.)*`/,
+		greedy: true
+	},
+	'char': {
+		// https://docs.julialang.org/en/v1/manual/strings/#man-characters-1
+		pattern: /(^|[^\w'])'(?:\\[^\r\n][^'\r\n]*|[^\\\r\n])'/,
+		lookbehind: true,
+		greedy: true
+	},
+	'keyword': /\b(?:abstract|baremodule|begin|bitstype|break|catch|ccall|const|continue|do|else|elseif|end|export|finally|for|function|global|if|immutable|import|importall|in|let|local|macro|module|print|println|quote|return|struct|try|type|typealias|using|while)\b/,
+	'boolean': /\b(?:false|true)\b/,
+	'number': /(?:\b(?=\d)|\B(?=\.))(?:0[box])?(?:[\da-f]+(?:_[\da-f]+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[efp][+-]?\d+(?:_\d+)*)?j?/i,
+	// https://docs.julialang.org/en/v1/manual/mathematical-operations/
+	// https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity-1
+	'operator': /&&|\|\||[-+*^%÷⊻&$\\]=?|\/[\/=]?|!=?=?|\|[=>]?|<(?:<=?|[=:|])?|>(?:=|>>?=?)?|==?=?|[~≠≤≥'√∛]/,
+	'punctuation': /::?|[{}[\]();,.?]/,
+	// https://docs.julialang.org/en/v1/base/numbers/#Base.im
+	'constant': /\b(?:(?:Inf|NaN)(?:16|32|64)?|im|pi)\b|[πℯ]/
 };
 
 (function (Prism) {
-  Prism.languages.kotlin = Prism.languages.extend("clike", {
-    keyword: {
-      // The lookbehind prevents wrong highlighting of e.g. kotlin.properties.get
-      pattern:
-        /(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,
-      lookbehind: true,
-    },
-    function: [
-      {
-        pattern: /(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,
-        greedy: true,
-      },
-      {
-        pattern: /(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,
-        lookbehind: true,
-        greedy: true,
-      },
-    ],
-    number:
-      /\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,
-    operator:
-      /\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/,
-  });
-
-  delete Prism.languages.kotlin["class-name"];
-
-  var interpolationInside = {
-    "interpolation-punctuation": {
-      pattern: /^\$\{?|\}$/,
-      alias: "punctuation",
-    },
-    expression: {
-      pattern: /[\s\S]+/,
-      inside: Prism.languages.kotlin,
-    },
-  };
-
-  Prism.languages.insertBefore("kotlin", "string", {
-    // https://kotlinlang.org/spec/expressions.html#string-interpolation-expressions
-    "string-literal": [
-      {
-        pattern: /"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,
-        alias: "multiline",
-        inside: {
-          interpolation: {
-            pattern: /\$(?:[a-z_]\w*|\{[^{}]*\})/i,
-            inside: interpolationInside,
-          },
-          string: /[\s\S]+/,
-        },
-      },
-      {
-        pattern: /"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,
-        alias: "singleline",
-        inside: {
-          interpolation: {
-            pattern: /((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,
-            lookbehind: true,
-            inside: interpolationInside,
-          },
-          string: /[\s\S]+/,
-        },
-      },
-    ],
-    char: {
-      // https://kotlinlang.org/spec/expressions.html#character-literals
-      pattern: /'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,
-      greedy: true,
-    },
-  });
-
-  delete Prism.languages.kotlin["string"];
-
-  Prism.languages.insertBefore("kotlin", "keyword", {
-    annotation: {
-      pattern: /\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,
-      alias: "builtin",
-    },
-  });
-
-  Prism.languages.insertBefore("kotlin", "function", {
-    label: {
-      pattern: /\b\w+@|@\w+\b/,
-      alias: "symbol",
-    },
-  });
-
-  Prism.languages.kt = Prism.languages.kotlin;
-  Prism.languages.kts = Prism.languages.kotlin;
-})(Prism);
+	Prism.languages.kotlin = Prism.languages.extend('clike', {
+		'keyword': {
+			// The lookbehind prevents wrong highlighting of e.g. kotlin.properties.get
+			pattern: /(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,
+			lookbehind: true
+		},
+		'function': [
+			{
+				pattern: /(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,
+				greedy: true
+			},
+			{
+				pattern: /(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,
+				lookbehind: true,
+				greedy: true
+			}
+		],
+		'number': /\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,
+		'operator': /\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/
+	});
+
+	delete Prism.languages.kotlin['class-name'];
+
+	var interpolationInside = {
+		'interpolation-punctuation': {
+			pattern: /^\$\{?|\}$/,
+			alias: 'punctuation'
+		},
+		'expression': {
+			pattern: /[\s\S]+/,
+			inside: Prism.languages.kotlin
+		}
+	};
+
+	Prism.languages.insertBefore('kotlin', 'string', {
+		// https://kotlinlang.org/spec/expressions.html#string-interpolation-expressions
+		'string-literal': [
+			{
+				pattern: /"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,
+				alias: 'multiline',
+				inside: {
+					'interpolation': {
+						pattern: /\$(?:[a-z_]\w*|\{[^{}]*\})/i,
+						inside: interpolationInside
+					},
+					'string': /[\s\S]+/
+				}
+			},
+			{
+				pattern: /"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,
+				alias: 'singleline',
+				inside: {
+					'interpolation': {
+						pattern: /((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,
+						lookbehind: true,
+						inside: interpolationInside
+					},
+					'string': /[\s\S]+/
+				}
+			}
+		],
+		'char': {
+			// https://kotlinlang.org/spec/expressions.html#character-literals
+			pattern: /'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,
+			greedy: true
+		}
+	});
+
+	delete Prism.languages.kotlin['string'];
+
+	Prism.languages.insertBefore('kotlin', 'keyword', {
+		'annotation': {
+			pattern: /\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,
+			alias: 'builtin'
+		}
+	});
+
+	Prism.languages.insertBefore('kotlin', 'function', {
+		'label': {
+			pattern: /\b\w+@|@\w+\b/,
+			alias: 'symbol'
+		}
+	});
+
+	Prism.languages.kt = Prism.languages.kotlin;
+	Prism.languages.kts = Prism.languages.kotlin;
+}(Prism));
 
 (function (Prism) {
-  var funcPattern = /\\(?:[^a-z()[\]]|[a-z*]+)/i;
-  var insideEqu = {
-    "equation-command": {
-      pattern: funcPattern,
-      alias: "regex",
-    },
-  };
-
-  Prism.languages.latex = {
-    comment: /%.*/,
-    // the verbatim environment prints whitespace to the document
-    cdata: {
-      pattern:
-        /(\\begin\{((?:lstlisting|verbatim)\*?)\})[\s\S]*?(?=\\end\{\2\})/,
-      lookbehind: true,
-    },
-    /*
-     * equations can be between $$ $$ or $ $ or \( \) or \[ \]
-     * (all are multiline)
-     */
-    equation: [
-      {
-        pattern:
-          /\$\$(?:\\[\s\S]|[^\\$])+\$\$|\$(?:\\[\s\S]|[^\\$])+\$|\\\([\s\S]*?\\\)|\\\[[\s\S]*?\\\]/,
-        inside: insideEqu,
-        alias: "string",
-      },
-      {
-        pattern:
-          /(\\begin\{((?:align|eqnarray|equation|gather|math|multline)\*?)\})[\s\S]*?(?=\\end\{\2\})/,
-        lookbehind: true,
-        inside: insideEqu,
-        alias: "string",
-      },
-    ],
-    /*
-     * arguments which are keywords or references are highlighted
-     * as keywords
-     */
-    keyword: {
-      pattern:
-        /(\\(?:begin|cite|documentclass|end|label|ref|usepackage)(?:\[[^\]]+\])?\{)[^}]+(?=\})/,
-      lookbehind: true,
-    },
-    url: {
-      pattern: /(\\url\{)[^}]+(?=\})/,
-      lookbehind: true,
-    },
-    /*
-     * section or chapter headlines are highlighted as bold so that
-     * they stand out more
-     */
-    headline: {
-      pattern:
-        /(\\(?:chapter|frametitle|paragraph|part|section|subparagraph|subsection|subsubparagraph|subsubsection|subsubsubparagraph)\*?(?:\[[^\]]+\])?\{)[^}]+(?=\})/,
-      lookbehind: true,
-      alias: "class-name",
-    },
-    function: {
-      pattern: funcPattern,
-      alias: "selector",
-    },
-    punctuation: /[[\]{}&]/,
-  };
-
-  Prism.languages.tex = Prism.languages.latex;
-  Prism.languages.context = Prism.languages.latex;
-})(Prism);
+	var funcPattern = /\\(?:[^a-z()[\]]|[a-z*]+)/i;
+	var insideEqu = {
+		'equation-command': {
+			pattern: funcPattern,
+			alias: 'regex'
+		}
+	};
+
+	Prism.languages.latex = {
+		'comment': /%.*/,
+		// the verbatim environment prints whitespace to the document
+		'cdata': {
+			pattern: /(\\begin\{((?:lstlisting|verbatim)\*?)\})[\s\S]*?(?=\\end\{\2\})/,
+			lookbehind: true
+		},
+		/*
+		 * equations can be between $$ $$ or $ $ or \( \) or \[ \]
+		 * (all are multiline)
+		 */
+		'equation': [
+			{
+				pattern: /\$\$(?:\\[\s\S]|[^\\$])+\$\$|\$(?:\\[\s\S]|[^\\$])+\$|\\\([\s\S]*?\\\)|\\\[[\s\S]*?\\\]/,
+				inside: insideEqu,
+				alias: 'string'
+			},
+			{
+				pattern: /(\\begin\{((?:align|eqnarray|equation|gather|math|multline)\*?)\})[\s\S]*?(?=\\end\{\2\})/,
+				lookbehind: true,
+				inside: insideEqu,
+				alias: 'string'
+			}
+		],
+		/*
+		 * arguments which are keywords or references are highlighted
+		 * as keywords
+		 */
+		'keyword': {
+			pattern: /(\\(?:begin|cite|documentclass|end|label|ref|usepackage)(?:\[[^\]]+\])?\{)[^}]+(?=\})/,
+			lookbehind: true
+		},
+		'url': {
+			pattern: /(\\url\{)[^}]+(?=\})/,
+			lookbehind: true
+		},
+		/*
+		 * section or chapter headlines are highlighted as bold so that
+		 * they stand out more
+		 */
+		'headline': {
+			pattern: /(\\(?:chapter|frametitle|paragraph|part|section|subparagraph|subsection|subsubparagraph|subsubsection|subsubsubparagraph)\*?(?:\[[^\]]+\])?\{)[^}]+(?=\})/,
+			lookbehind: true,
+			alias: 'class-name'
+		},
+		'function': {
+			pattern: funcPattern,
+			alias: 'selector'
+		},
+		'punctuation': /[[\]{}&]/
+	};
+
+	Prism.languages.tex = Prism.languages.latex;
+	Prism.languages.context = Prism.languages.latex;
+}(Prism));
 
 Prism.languages.lua = {
-  comment: /^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,
-  // \z may be used to skip the following space
-  string: {
-    pattern:
-      /(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,
-    greedy: true,
-  },
-  number:
-    /\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,
-  keyword:
-    /\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,
-  function: /(?!\d)\w+(?=\s*(?:[({]))/,
-  operator: [
-    /[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,
-    {
-      // Match ".." but don't break "..."
-      pattern: /(^|[^.])\.\.(?!\.)/,
-      lookbehind: true,
-    },
-  ],
-  punctuation: /[\[\](){},;]|\.+|:+/,
+	'comment': /^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,
+	// \z may be used to skip the following space
+	'string': {
+		pattern: /(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,
+		greedy: true
+	},
+	'number': /\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,
+	'keyword': /\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,
+	'function': /(?!\d)\w+(?=\s*(?:[({]))/,
+	'operator': [
+		/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,
+		{
+			// Match ".." but don't break "..."
+			pattern: /(^|[^.])\.\.(?!\.)/,
+			lookbehind: true
+		}
+	],
+	'punctuation': /[\[\](){},;]|\.+|:+/
 };
 
 (function (Prism) {
-  // Allow only one line break
-  var inner = /(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;
-
-  /**
-   * This function is intended for the creation of the bold or italic pattern.
-   *
-   * This also adds a lookbehind group to the given pattern to ensure that the pattern is not backslash-escaped.
-   *
-   * _Note:_ Keep in mind that this adds a capturing group.
-   *
-   * @param {string} pattern
-   * @returns {RegExp}
-   */
-  function createInline(pattern) {
-    pattern = pattern.replace(/<inner>/g, function () {
-      return inner;
-    });
-    return RegExp(/((?:^|[^\\])(?:\\{2})*)/.source + "(?:" + pattern + ")");
-  }
-
-  var tableCell = /(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/
-    .source;
-  var tableRow = /\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(
-    /__/g,
-    function () {
-      return tableCell;
-    },
-  );
-  var tableLine =
-    /\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/
-      .source;
-
-  Prism.languages.markdown = Prism.languages.extend("markup", {});
-  Prism.languages.insertBefore("markdown", "prolog", {
-    "front-matter-block": {
-      pattern: /(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,
-      lookbehind: true,
-      greedy: true,
-      inside: {
-        punctuation: /^---|---$/,
-        "front-matter": {
-          pattern: /\S+(?:\s+\S+)*/,
-          alias: ["yaml", "language-yaml"],
-          inside: Prism.languages.yaml,
-        },
-      },
-    },
-    blockquote: {
-      // > ...
-      pattern: /^>(?:[\t ]*>)*/m,
-      alias: "punctuation",
-    },
-    table: {
-      pattern: RegExp(
-        "^" + tableRow + tableLine + "(?:" + tableRow + ")*",
-        "m",
-      ),
-      inside: {
-        "table-data-rows": {
-          pattern: RegExp(
-            "^(" + tableRow + tableLine + ")(?:" + tableRow + ")*$",
-          ),
-          lookbehind: true,
-          inside: {
-            "table-data": {
-              pattern: RegExp(tableCell),
-              inside: Prism.languages.markdown,
-            },
-            punctuation: /\|/,
-          },
-        },
-        "table-line": {
-          pattern: RegExp("^(" + tableRow + ")" + tableLine + "$"),
-          lookbehind: true,
-          inside: {
-            punctuation: /\||:?-{3,}:?/,
-          },
-        },
-        "table-header-row": {
-          pattern: RegExp("^" + tableRow + "$"),
-          inside: {
-            "table-header": {
-              pattern: RegExp(tableCell),
-              alias: "important",
-              inside: Prism.languages.markdown,
-            },
-            punctuation: /\|/,
-          },
-        },
-      },
-    },
-    code: [
-      {
-        // Prefixed by 4 spaces or 1 tab and preceded by an empty line
-        pattern:
-          /((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,
-        lookbehind: true,
-        alias: "keyword",
-      },
-      {
-        // ```optional language
-        // code block
-        // ```
-        pattern: /^```[\s\S]*?^```$/m,
-        greedy: true,
-        inside: {
-          "code-block": {
-            pattern: /^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,
-            lookbehind: true,
-          },
-          "code-language": {
-            pattern: /^(```).+/,
-            lookbehind: true,
-          },
-          punctuation: /```/,
-        },
-      },
-    ],
-    title: [
-      {
-        // title 1
-        // =======
-
-        // title 2
-        // -------
-        pattern: /\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,
-        alias: "important",
-        inside: {
-          punctuation: /==+$|--+$/,
-        },
-      },
-      {
-        // # title 1
-        // ###### title 6
-        pattern: /(^\s*)#.+/m,
-        lookbehind: true,
-        alias: "important",
-        inside: {
-          punctuation: /^#+|#+$/,
-        },
-      },
-    ],
-    hr: {
-      // ***
-      // ---
-      // * * *
-      // -----------
-      pattern: /(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,
-      lookbehind: true,
-      alias: "punctuation",
-    },
-    list: {
-      // * item
-      // + item
-      // - item
-      // 1. item
-      pattern: /(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,
-      lookbehind: true,
-      alias: "punctuation",
-    },
-    "url-reference": {
-      // [id]: http://example.com "Optional title"
-      // [id]: http://example.com 'Optional title'
-      // [id]: http://example.com (Optional title)
-      // [id]: <http://example.com> "Optional title"
-      pattern:
-        /!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,
-      inside: {
-        variable: {
-          pattern: /^(!?\[)[^\]]+/,
-          lookbehind: true,
-        },
-        string: /(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,
-        punctuation: /^[\[\]!:]|[<>]/,
-      },
-      alias: "url",
-    },
-    bold: {
-      // **strong**
-      // __strong__
-
-      // allow one nested instance of italic text using the same delimiter
-      pattern: createInline(
-        /\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/
-          .source,
-      ),
-      lookbehind: true,
-      greedy: true,
-      inside: {
-        content: {
-          pattern: /(^..)[\s\S]+(?=..$)/,
-          lookbehind: true,
-          inside: {}, // see below
-        },
-        punctuation: /\*\*|__/,
-      },
-    },
-    italic: {
-      // *em*
-      // _em_
-
-      // allow one nested instance of bold text using the same delimiter
-      pattern: createInline(
-        /\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/
-          .source,
-      ),
-      lookbehind: true,
-      greedy: true,
-      inside: {
-        content: {
-          pattern: /(^.)[\s\S]+(?=.$)/,
-          lookbehind: true,
-          inside: {}, // see below
-        },
-        punctuation: /[*_]/,
-      },
-    },
-    strike: {
-      // ~~strike through~~
-      // ~strike~
-      // eslint-disable-next-line regexp/strict
-      pattern: createInline(/(~~?)(?:(?!~)<inner>)+\2/.source),
-      lookbehind: true,
-      greedy: true,
-      inside: {
-        content: {
-          pattern: /(^~~?)[\s\S]+(?=\1$)/,
-          lookbehind: true,
-          inside: {}, // see below
-        },
-        punctuation: /~~?/,
-      },
-    },
-    "code-snippet": {
-      // `code`
-      // ``code``
-      pattern:
-        /(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,
-      lookbehind: true,
-      greedy: true,
-      alias: ["code", "keyword"],
-    },
-    url: {
-      // [example](http://example.com "Optional title")
-      // [example][id]
-      // [example] [id]
-      pattern: createInline(
-        /!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/
-          .source,
-      ),
-      lookbehind: true,
-      greedy: true,
-      inside: {
-        operator: /^!/,
-        content: {
-          pattern: /(^\[)[^\]]+(?=\])/,
-          lookbehind: true,
-          inside: {}, // see below
-        },
-        variable: {
-          pattern: /(^\][ \t]?\[)[^\]]+(?=\]$)/,
-          lookbehind: true,
-        },
-        url: {
-          pattern: /(^\]\()[^\s)]+/,
-          lookbehind: true,
-        },
-        string: {
-          pattern: /(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,
-          lookbehind: true,
-        },
-      },
-    },
-  });
-
-  ["url", "bold", "italic", "strike"].forEach(function (token) {
-    ["url", "bold", "italic", "strike", "code-snippet"].forEach(
-      function (inside) {
-        if (token !== inside) {
-          Prism.languages.markdown[token].inside.content.inside[inside] =
-            Prism.languages.markdown[inside];
-        }
-      },
-    );
-  });
-
-  Prism.hooks.add("after-tokenize", function (env) {
-    if (env.language !== "markdown" && env.language !== "md") {
-      return;
-    }
-
-    function walkTokens(tokens) {
-      if (!tokens || typeof tokens === "string") {
-        return;
-      }
-
-      for (var i = 0, l = tokens.length; i < l; i++) {
-        var token = tokens[i];
-
-        if (token.type !== "code") {
-          walkTokens(token.content);
-          continue;
-        }
-
-        /*
-         * Add the correct `language-xxxx` class to this code block. Keep in mind that the `code-language` token
-         * is optional. But the grammar is defined so that there is only one case we have to handle:
-         *
-         * token.content = [
-         *     <span class="punctuation">```</span>,
-         *     <span class="code-language">xxxx</span>,
-         *     '\n', // exactly one new lines (\r or \n or \r\n)
-         *     <span class="code-block">...</span>,
-         *     '\n', // exactly one new lines again
-         *     <span class="punctuation">```</span>
-         * ];
-         */
-
-        var codeLang = token.content[1];
-        var codeBlock = token.content[3];
-
-        if (
-          codeLang &&
-          codeBlock &&
-          codeLang.type === "code-language" &&
-          codeBlock.type === "code-block" &&
-          typeof codeLang.content === "string"
-        ) {
-          // this might be a language that Prism does not support
-
-          // do some replacements to support C++, C#, and F#
-          var lang = codeLang.content
-            .replace(/\b#/g, "sharp")
-            .replace(/\b\+\+/g, "pp");
-          // only use the first word
-          lang = (/[a-z][\w-]*/i.exec(lang) || [""])[0].toLowerCase();
-          var alias = "language-" + lang;
-
-          // add alias
-          if (!codeBlock.alias) {
-            codeBlock.alias = [alias];
-          } else if (typeof codeBlock.alias === "string") {
-            codeBlock.alias = [codeBlock.alias, alias];
-          } else {
-            codeBlock.alias.push(alias);
-          }
-        }
-      }
-    }
-
-    walkTokens(env.tokens);
-  });
-
-  Prism.hooks.add("wrap", function (env) {
-    if (env.type !== "code-block") {
-      return;
-    }
-
-    var codeLang = "";
-    for (var i = 0, l = env.classes.length; i < l; i++) {
-      var cls = env.classes[i];
-      var match = /language-(.+)/.exec(cls);
-      if (match) {
-        codeLang = match[1];
-        break;
-      }
-    }
-
-    var grammar = Prism.languages[codeLang];
-
-    if (!grammar) {
-      if (codeLang && codeLang !== "none" && Prism.plugins.autoloader) {
-        var id =
-          "md-" + new Date().valueOf() + "-" + Math.floor(Math.random() * 1e16);
-        env.attributes["id"] = id;
-
-        Prism.plugins.autoloader.loadLanguages(codeLang, function () {
-          var ele = document.getElementById(id);
-          if (ele) {
-            ele.innerHTML = Prism.highlight(
-              ele.textContent,
-              Prism.languages[codeLang],
-              codeLang,
-            );
-          }
-        });
-      }
-    } else {
-      env.content = Prism.highlight(
-        textContent(env.content),
-        grammar,
-        codeLang,
-      );
-    }
-  });
-
-  var tagPattern = RegExp(Prism.languages.markup.tag.pattern.source, "gi");
-
-  /**
-   * A list of known entity names.
-   *
-   * This will always be incomplete to save space. The current list is the one used by lowdash's unescape function.
-   *
-   * @see {@link https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/unescape.js#L2}
-   */
-  var KNOWN_ENTITY_NAMES = {
-    amp: "&",
-    lt: "<",
-    gt: ">",
-    quot: '"',
-  };
-
-  // IE 11 doesn't support `String.fromCodePoint`
-  var fromCodePoint = String.fromCodePoint || String.fromCharCode;
-
-  /**
-   * Returns the text content of a given HTML source code string.
-   *
-   * @param {string} html
-   * @returns {string}
-   */
-  function textContent(html) {
-    // remove all tags
-    var text = html.replace(tagPattern, "");
-
-    // decode known entities
-    text = text.replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi, function (m, code) {
-      code = code.toLowerCase();
-
-      if (code[0] === "#") {
-        var value;
-        if (code[1] === "x") {
-          value = parseInt(code.slice(2), 16);
-        } else {
-          value = Number(code.slice(1));
-        }
-
-        return fromCodePoint(value);
-      } else {
-        var known = KNOWN_ENTITY_NAMES[code];
-        if (known) {
-          return known;
-        }
-
-        // unable to decode
-        return m;
-      }
-    });
-
-    return text;
-  }
-
-  Prism.languages.md = Prism.languages.markdown;
-})(Prism);
+
+	// Allow only one line break
+	var inner = /(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;
+
+	/**
+	 * This function is intended for the creation of the bold or italic pattern.
+	 *
+	 * This also adds a lookbehind group to the given pattern to ensure that the pattern is not backslash-escaped.
+	 *
+	 * _Note:_ Keep in mind that this adds a capturing group.
+	 *
+	 * @param {string} pattern
+	 * @returns {RegExp}
+	 */
+	function createInline(pattern) {
+		pattern = pattern.replace(/<inner>/g, function () { return inner; });
+		return RegExp(/((?:^|[^\\])(?:\\{2})*)/.source + '(?:' + pattern + ')');
+	}
+
+
+	var tableCell = /(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source;
+	var tableRow = /\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g, function () { return tableCell; });
+	var tableLine = /\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;
+
+
+	Prism.languages.markdown = Prism.languages.extend('markup', {});
+	Prism.languages.insertBefore('markdown', 'prolog', {
+		'front-matter-block': {
+			pattern: /(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,
+			lookbehind: true,
+			greedy: true,
+			inside: {
+				'punctuation': /^---|---$/,
+				'front-matter': {
+					pattern: /\S+(?:\s+\S+)*/,
+					alias: ['yaml', 'language-yaml'],
+					inside: Prism.languages.yaml
+				}
+			}
+		},
+		'blockquote': {
+			// > ...
+			pattern: /^>(?:[\t ]*>)*/m,
+			alias: 'punctuation'
+		},
+		'table': {
+			pattern: RegExp('^' + tableRow + tableLine + '(?:' + tableRow + ')*', 'm'),
+			inside: {
+				'table-data-rows': {
+					pattern: RegExp('^(' + tableRow + tableLine + ')(?:' + tableRow + ')*$'),
+					lookbehind: true,
+					inside: {
+						'table-data': {
+							pattern: RegExp(tableCell),
+							inside: Prism.languages.markdown
+						},
+						'punctuation': /\|/
+					}
+				},
+				'table-line': {
+					pattern: RegExp('^(' + tableRow + ')' + tableLine + '$'),
+					lookbehind: true,
+					inside: {
+						'punctuation': /\||:?-{3,}:?/
+					}
+				},
+				'table-header-row': {
+					pattern: RegExp('^' + tableRow + '$'),
+					inside: {
+						'table-header': {
+							pattern: RegExp(tableCell),
+							alias: 'important',
+							inside: Prism.languages.markdown
+						},
+						'punctuation': /\|/
+					}
+				}
+			}
+		},
+		'code': [
+			{
+				// Prefixed by 4 spaces or 1 tab and preceded by an empty line
+				pattern: /((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,
+				lookbehind: true,
+				alias: 'keyword'
+			},
+			{
+				// ```optional language
+				// code block
+				// ```
+				pattern: /^```[\s\S]*?^```$/m,
+				greedy: true,
+				inside: {
+					'code-block': {
+						pattern: /^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,
+						lookbehind: true
+					},
+					'code-language': {
+						pattern: /^(```).+/,
+						lookbehind: true
+					},
+					'punctuation': /```/
+				}
+			}
+		],
+		'title': [
+			{
+				// title 1
+				// =======
+
+				// title 2
+				// -------
+				pattern: /\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,
+				alias: 'important',
+				inside: {
+					punctuation: /==+$|--+$/
+				}
+			},
+			{
+				// # title 1
+				// ###### title 6
+				pattern: /(^\s*)#.+/m,
+				lookbehind: true,
+				alias: 'important',
+				inside: {
+					punctuation: /^#+|#+$/
+				}
+			}
+		],
+		'hr': {
+			// ***
+			// ---
+			// * * *
+			// -----------
+			pattern: /(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,
+			lookbehind: true,
+			alias: 'punctuation'
+		},
+		'list': {
+			// * item
+			// + item
+			// - item
+			// 1. item
+			pattern: /(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,
+			lookbehind: true,
+			alias: 'punctuation'
+		},
+		'url-reference': {
+			// [id]: http://example.com "Optional title"
+			// [id]: http://example.com 'Optional title'
+			// [id]: http://example.com (Optional title)
+			// [id]: <http://example.com> "Optional title"
+			pattern: /!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,
+			inside: {
+				'variable': {
+					pattern: /^(!?\[)[^\]]+/,
+					lookbehind: true
+				},
+				'string': /(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,
+				'punctuation': /^[\[\]!:]|[<>]/
+			},
+			alias: 'url'
+		},
+		'bold': {
+			// **strong**
+			// __strong__
+
+			// allow one nested instance of italic text using the same delimiter
+			pattern: createInline(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),
+			lookbehind: true,
+			greedy: true,
+			inside: {
+				'content': {
+					pattern: /(^..)[\s\S]+(?=..$)/,
+					lookbehind: true,
+					inside: {} // see below
+				},
+				'punctuation': /\*\*|__/
+			}
+		},
+		'italic': {
+			// *em*
+			// _em_
+
+			// allow one nested instance of bold text using the same delimiter
+			pattern: createInline(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),
+			lookbehind: true,
+			greedy: true,
+			inside: {
+				'content': {
+					pattern: /(^.)[\s\S]+(?=.$)/,
+					lookbehind: true,
+					inside: {} // see below
+				},
+				'punctuation': /[*_]/
+			}
+		},
+		'strike': {
+			// ~~strike through~~
+			// ~strike~
+			// eslint-disable-next-line regexp/strict
+			pattern: createInline(/(~~?)(?:(?!~)<inner>)+\2/.source),
+			lookbehind: true,
+			greedy: true,
+			inside: {
+				'content': {
+					pattern: /(^~~?)[\s\S]+(?=\1$)/,
+					lookbehind: true,
+					inside: {} // see below
+				},
+				'punctuation': /~~?/
+			}
+		},
+		'code-snippet': {
+			// `code`
+			// ``code``
+			pattern: /(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,
+			lookbehind: true,
+			greedy: true,
+			alias: ['code', 'keyword']
+		},
+		'url': {
+			// [example](http://example.com "Optional title")
+			// [example][id]
+			// [example] [id]
+			pattern: createInline(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),
+			lookbehind: true,
+			greedy: true,
+			inside: {
+				'operator': /^!/,
+				'content': {
+					pattern: /(^\[)[^\]]+(?=\])/,
+					lookbehind: true,
+					inside: {} // see below
+				},
+				'variable': {
+					pattern: /(^\][ \t]?\[)[^\]]+(?=\]$)/,
+					lookbehind: true
+				},
+				'url': {
+					pattern: /(^\]\()[^\s)]+/,
+					lookbehind: true
+				},
+				'string': {
+					pattern: /(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,
+					lookbehind: true
+				}
+			}
+		}
+	});
+
+	['url', 'bold', 'italic', 'strike'].forEach(function (token) {
+		['url', 'bold', 'italic', 'strike', 'code-snippet'].forEach(function (inside) {
+			if (token !== inside) {
+				Prism.languages.markdown[token].inside.content.inside[inside] = Prism.languages.markdown[inside];
+			}
+		});
+	});
+
+	Prism.hooks.add('after-tokenize', function (env) {
+		if (env.language !== 'markdown' && env.language !== 'md') {
+			return;
+		}
+
+		function walkTokens(tokens) {
+			if (!tokens || typeof tokens === 'string') {
+				return;
+			}
+
+			for (var i = 0, l = tokens.length; i < l; i++) {
+				var token = tokens[i];
+
+				if (token.type !== 'code') {
+					walkTokens(token.content);
+					continue;
+				}
+
+				/*
+				 * Add the correct `language-xxxx` class to this code block. Keep in mind that the `code-language` token
+				 * is optional. But the grammar is defined so that there is only one case we have to handle:
+				 *
+				 * token.content = [
+				 *     <span class="punctuation">```</span>,
+				 *     <span class="code-language">xxxx</span>,
+				 *     '\n', // exactly one new lines (\r or \n or \r\n)
+				 *     <span class="code-block">...</span>,
+				 *     '\n', // exactly one new lines again
+				 *     <span class="punctuation">```</span>
+				 * ];
+				 */
+
+				var codeLang = token.content[1];
+				var codeBlock = token.content[3];
+
+				if (codeLang && codeBlock &&
+					codeLang.type === 'code-language' && codeBlock.type === 'code-block' &&
+					typeof codeLang.content === 'string') {
+
+					// this might be a language that Prism does not support
+
+					// do some replacements to support C++, C#, and F#
+					var lang = codeLang.content.replace(/\b#/g, 'sharp').replace(/\b\+\+/g, 'pp');
+					// only use the first word
+					lang = (/[a-z][\w-]*/i.exec(lang) || [''])[0].toLowerCase();
+					var alias = 'language-' + lang;
+
+					// add alias
+					if (!codeBlock.alias) {
+						codeBlock.alias = [alias];
+					} else if (typeof codeBlock.alias === 'string') {
+						codeBlock.alias = [codeBlock.alias, alias];
+					} else {
+						codeBlock.alias.push(alias);
+					}
+				}
+			}
+		}
+
+		walkTokens(env.tokens);
+	});
+
+	Prism.hooks.add('wrap', function (env) {
+		if (env.type !== 'code-block') {
+			return;
+		}
+
+		var codeLang = '';
+		for (var i = 0, l = env.classes.length; i < l; i++) {
+			var cls = env.classes[i];
+			var match = /language-(.+)/.exec(cls);
+			if (match) {
+				codeLang = match[1];
+				break;
+			}
+		}
+
+		var grammar = Prism.languages[codeLang];
+
+		if (!grammar) {
+			if (codeLang && codeLang !== 'none' && Prism.plugins.autoloader) {
+				var id = 'md-' + new Date().valueOf() + '-' + Math.floor(Math.random() * 1e16);
+				env.attributes['id'] = id;
+
+				Prism.plugins.autoloader.loadLanguages(codeLang, function () {
+					var ele = document.getElementById(id);
+					if (ele) {
+						ele.innerHTML = Prism.highlight(ele.textContent, Prism.languages[codeLang], codeLang);
+					}
+				});
+			}
+		} else {
+			env.content = Prism.highlight(textContent(env.content), grammar, codeLang);
+		}
+	});
+
+	var tagPattern = RegExp(Prism.languages.markup.tag.pattern.source, 'gi');
+
+	/**
+	 * A list of known entity names.
+	 *
+	 * This will always be incomplete to save space. The current list is the one used by lowdash's unescape function.
+	 *
+	 * @see {@link https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/unescape.js#L2}
+	 */
+	var KNOWN_ENTITY_NAMES = {
+		'amp': '&',
+		'lt': '<',
+		'gt': '>',
+		'quot': '"',
+	};
+
+	// IE 11 doesn't support `String.fromCodePoint`
+	var fromCodePoint = String.fromCodePoint || String.fromCharCode;
+
+	/**
+	 * Returns the text content of a given HTML source code string.
+	 *
+	 * @param {string} html
+	 * @returns {string}
+	 */
+	function textContent(html) {
+		// remove all tags
+		var text = html.replace(tagPattern, '');
+
+		// decode known entities
+		text = text.replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi, function (m, code) {
+			code = code.toLowerCase();
+
+			if (code[0] === '#') {
+				var value;
+				if (code[1] === 'x') {
+					value = parseInt(code.slice(2), 16);
+				} else {
+					value = Number(code.slice(1));
+				}
+
+				return fromCodePoint(value);
+			} else {
+				var known = KNOWN_ENTITY_NAMES[code];
+				if (known) {
+					return known;
+				}
+
+				// unable to decode
+				return m;
+			}
+		});
+
+		return text;
+	}
+
+	Prism.languages.md = Prism.languages.markdown;
+
+}(Prism));
 
 Prism.languages.matlab = {
-  comment: [/%\{[\s\S]*?\}%/, /%.+/],
-  string: {
-    pattern: /\B'(?:''|[^'\r\n])*'/,
-    greedy: true,
-  },
-  // FIXME We could handle imaginary numbers as a whole
-  number: /(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[eE][+-]?\d+)?(?:[ij])?|\b[ij]\b/,
-  keyword:
-    /\b(?:NaN|break|case|catch|continue|else|elseif|end|for|function|if|inf|otherwise|parfor|pause|pi|return|switch|try|while)\b/,
-  function: /\b(?!\d)\w+(?=\s*\()/,
-  operator: /\.?[*^\/\\']|[+\-:@]|[<>=~]=?|&&?|\|\|?/,
-  punctuation: /\.{3}|[.,;\[\](){}!]/,
+	'comment': [
+		/%\{[\s\S]*?\}%/,
+		/%.+/
+	],
+	'string': {
+		pattern: /\B'(?:''|[^'\r\n])*'/,
+		greedy: true
+	},
+	// FIXME We could handle imaginary numbers as a whole
+	'number': /(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[eE][+-]?\d+)?(?:[ij])?|\b[ij]\b/,
+	'keyword': /\b(?:NaN|break|case|catch|continue|else|elseif|end|for|function|if|inf|otherwise|parfor|pause|pi|return|switch|try|while)\b/,
+	'function': /\b(?!\d)\w+(?=\s*\()/,
+	'operator': /\.?[*^\/\\']|[+\-:@]|[<>=~]=?|&&?|\|\|?/,
+	'punctuation': /\.{3}|[.,;\[\](){}!]/
 };
 
 (function (Prism) {
-  var variable =
-    /\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i;
-
-  Prism.languages.nginx = {
-    comment: {
-      pattern: /(^|[\s{};])#.*/,
-      lookbehind: true,
-      greedy: true,
-    },
-    directive: {
-      pattern:
-        /(^|\s)\w(?:[^;{}"'\\\s]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\s+(?:#.*(?!.)|(?![#\s])))*?(?=\s*[;{])/,
-      lookbehind: true,
-      greedy: true,
-      inside: {
-        string: {
-          pattern:
-            /((?:^|[^\\])(?:\\\\)*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,
-          lookbehind: true,
-          greedy: true,
-          inside: {
-            escape: {
-              pattern: /\\["'\\nrt]/,
-              alias: "entity",
-            },
-            variable: variable,
-          },
-        },
-        comment: {
-          pattern: /(\s)#.*/,
-          lookbehind: true,
-          greedy: true,
-        },
-        keyword: {
-          pattern: /^\S+/,
-          greedy: true,
-        },
-
-        // other patterns
-
-        boolean: {
-          pattern: /(\s)(?:off|on)(?!\S)/,
-          lookbehind: true,
-        },
-        number: {
-          pattern: /(\s)\d+[a-z]*(?!\S)/i,
-          lookbehind: true,
-        },
-        variable: variable,
-      },
-    },
-    punctuation: /[{};]/,
-  };
-})(Prism);
+
+	var variable = /\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i;
+
+	Prism.languages.nginx = {
+		'comment': {
+			pattern: /(^|[\s{};])#.*/,
+			lookbehind: true,
+			greedy: true
+		},
+		'directive': {
+			pattern: /(^|\s)\w(?:[^;{}"'\\\s]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\s+(?:#.*(?!.)|(?![#\s])))*?(?=\s*[;{])/,
+			lookbehind: true,
+			greedy: true,
+			inside: {
+				'string': {
+					pattern: /((?:^|[^\\])(?:\\\\)*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,
+					lookbehind: true,
+					greedy: true,
+					inside: {
+						'escape': {
+							pattern: /\\["'\\nrt]/,
+							alias: 'entity'
+						},
+						'variable': variable
+					}
+				},
+				'comment': {
+					pattern: /(\s)#.*/,
+					lookbehind: true,
+					greedy: true
+				},
+				'keyword': {
+					pattern: /^\S+/,
+					greedy: true
+				},
+
+				// other patterns
+
+				'boolean': {
+					pattern: /(\s)(?:off|on)(?!\S)/,
+					lookbehind: true
+				},
+				'number': {
+					pattern: /(\s)\d+[a-z]*(?!\S)/i,
+					lookbehind: true
+				},
+				'variable': variable
+			}
+		},
+		'punctuation': /[{};]/
+	};
+
+}(Prism));
 
 Prism.languages.nim = {
-  comment: {
-    pattern: /#.*/,
-    greedy: true,
-  },
-  string: {
-    // Double-quoted strings can be prefixed by an identifier (Generalized raw string literals)
-    pattern:
-      /(?:\b(?!\d)(?:\w|\\x[89a-fA-F][0-9a-fA-F])+)?(?:"""[\s\S]*?"""(?!")|"(?:\\[\s\S]|""|[^"\\])*")/,
-    greedy: true,
-  },
-  char: {
-    // Character literals are handled specifically to prevent issues with numeric type suffixes
-    pattern: /'(?:\\(?:\d+|x[\da-fA-F]{0,2}|.)|[^'])'/,
-    greedy: true,
-  },
-
-  function: {
-    pattern:
-      /(?:(?!\d)(?:\w|\\x[89a-fA-F][0-9a-fA-F])+|`[^`\r\n]+`)\*?(?:\[[^\]]+\])?(?=\s*\()/,
-    greedy: true,
-    inside: {
-      operator: /\*$/,
-    },
-  },
-  // We don't want to highlight operators (and anything really) inside backticks
-  identifier: {
-    pattern: /`[^`\r\n]+`/,
-    greedy: true,
-    inside: {
-      punctuation: /`/,
-    },
-  },
-
-  // The negative look ahead prevents wrong highlighting of the .. operator
-  number:
-    /\b(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)(?:'?[iuf]\d*)?/,
-  keyword:
-    /\b(?:addr|as|asm|atomic|bind|block|break|case|cast|concept|const|continue|converter|defer|discard|distinct|do|elif|else|end|enum|except|export|finally|for|from|func|generic|if|import|include|interface|iterator|let|macro|method|mixin|nil|object|out|proc|ptr|raise|ref|return|static|template|try|tuple|type|using|var|when|while|with|without|yield)\b/,
-  operator: {
-    // Look behind and look ahead prevent wrong highlighting of punctuations [. .] {. .} (. .)
-    // but allow the slice operator .. to take precedence over them
-    // One can define his own operators in Nim so all combination of operators might be an operator.
-    pattern:
-      /(^|[({\[](?=\.\.)|(?![({\[]\.).)(?:(?:[=+\-*\/<>@$~&%|!?^:\\]|\.\.|\.(?![)}\]]))+|\b(?:and|div|in|is|isnot|mod|not|notin|of|or|shl|shr|xor)\b)/m,
-    lookbehind: true,
-  },
-  punctuation: /[({\[]\.|\.[)}\]]|[`(){}\[\],:]/,
+	'comment': {
+		pattern: /#.*/,
+		greedy: true
+	},
+	'string': {
+		// Double-quoted strings can be prefixed by an identifier (Generalized raw string literals)
+		pattern: /(?:\b(?!\d)(?:\w|\\x[89a-fA-F][0-9a-fA-F])+)?(?:"""[\s\S]*?"""(?!")|"(?:\\[\s\S]|""|[^"\\])*")/,
+		greedy: true
+	},
+	'char': {
+		// Character literals are handled specifically to prevent issues with numeric type suffixes
+		pattern: /'(?:\\(?:\d+|x[\da-fA-F]{0,2}|.)|[^'])'/,
+		greedy: true
+	},
+
+	'function': {
+		pattern: /(?:(?!\d)(?:\w|\\x[89a-fA-F][0-9a-fA-F])+|`[^`\r\n]+`)\*?(?:\[[^\]]+\])?(?=\s*\()/,
+		greedy: true,
+		inside: {
+			'operator': /\*$/
+		}
+	},
+	// We don't want to highlight operators (and anything really) inside backticks
+	'identifier': {
+		pattern: /`[^`\r\n]+`/,
+		greedy: true,
+		inside: {
+			'punctuation': /`/
+		}
+	},
+
+	// The negative look ahead prevents wrong highlighting of the .. operator
+	'number': /\b(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)(?:'?[iuf]\d*)?/,
+	'keyword': /\b(?:addr|as|asm|atomic|bind|block|break|case|cast|concept|const|continue|converter|defer|discard|distinct|do|elif|else|end|enum|except|export|finally|for|from|func|generic|if|import|include|interface|iterator|let|macro|method|mixin|nil|object|out|proc|ptr|raise|ref|return|static|template|try|tuple|type|using|var|when|while|with|without|yield)\b/,
+	'operator': {
+		// Look behind and look ahead prevent wrong highlighting of punctuations [. .] {. .} (. .)
+		// but allow the slice operator .. to take precedence over them
+		// One can define his own operators in Nim so all combination of operators might be an operator.
+		pattern: /(^|[({\[](?=\.\.)|(?![({\[]\.).)(?:(?:[=+\-*\/<>@$~&%|!?^:\\]|\.\.|\.(?![)}\]]))+|\b(?:and|div|in|is|isnot|mod|not|notin|of|or|shl|shr|xor)\b)/m,
+		lookbehind: true
+	},
+	'punctuation': /[({\[]\.|\.[)}\]]|[`(){}\[\],:]/
 };
 
 Prism.languages.nix = {
-  comment: {
-    pattern: /\/\*[\s\S]*?\*\/|#.*/,
-    greedy: true,
-  },
-  string: {
-    pattern: /"(?:[^"\\]|\\[\s\S])*"|''(?:(?!'')[\s\S]|''(?:'|\\|\$\{))*''/,
-    greedy: true,
-    inside: {
-      interpolation: {
-        // The lookbehind ensures the ${} is not preceded by \ or ''
-        pattern: /(^|(?:^|(?!'').)[^\\])\$\{(?:[^{}]|\{[^}]*\})*\}/,
-        lookbehind: true,
-        inside: null, // see below
-      },
-    },
-  },
-  url: [
-    /\b(?:[a-z]{3,7}:\/\/)[\w\-+%~\/.:#=?&]+/,
-    {
-      pattern:
-        /([^\/])(?:[\w\-+%~.:#=?&]*(?!\/\/)[\w\-+%~\/.:#=?&])?(?!\/\/)\/[\w\-+%~\/.:#=?&]*/,
-      lookbehind: true,
-    },
-  ],
-  antiquotation: {
-    pattern: /\$(?=\{)/,
-    alias: "important",
-  },
-  number: /\b\d+\b/,
-  keyword: /\b(?:assert|builtins|else|if|in|inherit|let|null|or|then|with)\b/,
-  function:
-    /\b(?:abort|add|all|any|attrNames|attrValues|baseNameOf|compareVersions|concatLists|currentSystem|deepSeq|derivation|dirOf|div|elem(?:At)?|fetch(?:Tarball|url)|filter(?:Source)?|fromJSON|genList|getAttr|getEnv|hasAttr|hashString|head|import|intersectAttrs|is(?:Attrs|Bool|Function|Int|List|Null|String)|length|lessThan|listToAttrs|map|mul|parseDrvName|pathExists|read(?:Dir|File)|removeAttrs|replaceStrings|seq|sort|stringLength|sub(?:string)?|tail|throw|to(?:File|JSON|Path|String|XML)|trace|typeOf)\b|\bfoldl'\B/,
-  boolean: /\b(?:false|true)\b/,
-  operator: /[=!<>]=?|\+\+?|\|\||&&|\/\/|->?|[?@]/,
-  punctuation: /[{}()[\].,:;]/,
+	'comment': {
+		pattern: /\/\*[\s\S]*?\*\/|#.*/,
+		greedy: true
+	},
+	'string': {
+		pattern: /"(?:[^"\\]|\\[\s\S])*"|''(?:(?!'')[\s\S]|''(?:'|\\|\$\{))*''/,
+		greedy: true,
+		inside: {
+			'interpolation': {
+				// The lookbehind ensures the ${} is not preceded by \ or ''
+				pattern: /(^|(?:^|(?!'').)[^\\])\$\{(?:[^{}]|\{[^}]*\})*\}/,
+				lookbehind: true,
+				inside: null // see below
+			}
+		}
+	},
+	'url': [
+		/\b(?:[a-z]{3,7}:\/\/)[\w\-+%~\/.:#=?&]+/,
+		{
+			pattern: /([^\/])(?:[\w\-+%~.:#=?&]*(?!\/\/)[\w\-+%~\/.:#=?&])?(?!\/\/)\/[\w\-+%~\/.:#=?&]*/,
+			lookbehind: true
+		}
+	],
+	'antiquotation': {
+		pattern: /\$(?=\{)/,
+		alias: 'important'
+	},
+	'number': /\b\d+\b/,
+	'keyword': /\b(?:assert|builtins|else|if|in|inherit|let|null|or|then|with)\b/,
+	'function': /\b(?:abort|add|all|any|attrNames|attrValues|baseNameOf|compareVersions|concatLists|currentSystem|deepSeq|derivation|dirOf|div|elem(?:At)?|fetch(?:Tarball|url)|filter(?:Source)?|fromJSON|genList|getAttr|getEnv|hasAttr|hashString|head|import|intersectAttrs|is(?:Attrs|Bool|Function|Int|List|Null|String)|length|lessThan|listToAttrs|map|mul|parseDrvName|pathExists|read(?:Dir|File)|removeAttrs|replaceStrings|seq|sort|stringLength|sub(?:string)?|tail|throw|to(?:File|JSON|Path|String|XML)|trace|typeOf)\b|\bfoldl'\B/,
+	'boolean': /\b(?:false|true)\b/,
+	'operator': /[=!<>]=?|\+\+?|\|\||&&|\/\/|->?|[?@]/,
+	'punctuation': /[{}()[\].,:;]/
 };
 
 Prism.languages.nix.string.inside.interpolation.inside = Prism.languages.nix;
@@ -4390,226 +4106,218 @@ Prism.languages.nix.string.inside.interpolation.inside = Prism.languages.nix;
 // https://ocaml.org/manual/lex.html
 
 Prism.languages.ocaml = {
-  comment: {
-    pattern: /\(\*[\s\S]*?\*\)/,
-    greedy: true,
-  },
-  char: {
-    pattern: /'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,
-    greedy: true,
-  },
-  string: [
-    {
-      pattern: /"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,
-      greedy: true,
-    },
-    {
-      pattern: /\{([a-z_]*)\|[\s\S]*?\|\1\}/,
-      greedy: true,
-    },
-  ],
-  number: [
-    // binary and octal
-    /\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,
-    // hexadecimal
-    /\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,
-    // decimal
-    /\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i,
-  ],
-  directive: {
-    pattern: /\B#\w+/,
-    alias: "property",
-  },
-  label: {
-    pattern: /\B~\w+/,
-    alias: "property",
-  },
-  "type-variable": {
-    pattern: /\B'\w+/,
-    alias: "function",
-  },
-  variant: {
-    pattern: /`\w+/,
-    alias: "symbol",
-  },
-  // For the list of keywords and operators,
-  // see: http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#sec84
-  keyword:
-    /\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,
-  boolean: /\b(?:false|true)\b/,
-
-  "operator-like-punctuation": {
-    pattern: /\[[<>|]|[>|]\]|\{<|>\}/,
-    alias: "punctuation",
-  },
-  // Custom operators are allowed
-  operator:
-    /\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,
-  punctuation: /;;|::|[(){}\[\].,:;#]|\b_\b/,
+	'comment': {
+		pattern: /\(\*[\s\S]*?\*\)/,
+		greedy: true
+	},
+	'char': {
+		pattern: /'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,
+		greedy: true
+	},
+	'string': [
+		{
+			pattern: /"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,
+			greedy: true
+		},
+		{
+			pattern: /\{([a-z_]*)\|[\s\S]*?\|\1\}/,
+			greedy: true
+		}
+	],
+	'number': [
+		// binary and octal
+		/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,
+		// hexadecimal
+		/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,
+		// decimal
+		/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i,
+	],
+	'directive': {
+		pattern: /\B#\w+/,
+		alias: 'property'
+	},
+	'label': {
+		pattern: /\B~\w+/,
+		alias: 'property'
+	},
+	'type-variable': {
+		pattern: /\B'\w+/,
+		alias: 'function'
+	},
+	'variant': {
+		pattern: /`\w+/,
+		alias: 'symbol'
+	},
+	// For the list of keywords and operators,
+	// see: http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#sec84
+	'keyword': /\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,
+	'boolean': /\b(?:false|true)\b/,
+
+	'operator-like-punctuation': {
+		pattern: /\[[<>|]|[>|]\]|\{<|>\}/,
+		alias: 'punctuation'
+	},
+	// Custom operators are allowed
+	'operator': /\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,
+	'punctuation': /;;|::|[(){}\[\].,:;#]|\b_\b/
 };
 
 (function (Prism) {
-  var brackets =
-    /(?:\((?:[^()\\]|\\[\s\S])*\)|\{(?:[^{}\\]|\\[\s\S])*\}|\[(?:[^[\]\\]|\\[\s\S])*\]|<(?:[^<>\\]|\\[\s\S])*>)/
-      .source;
-
-  Prism.languages.perl = {
-    comment: [
-      {
-        // POD
-        pattern: /(^\s*)=\w[\s\S]*?=cut.*/m,
-        lookbehind: true,
-        greedy: true,
-      },
-      {
-        pattern: /(^|[^\\$])#.*/,
-        lookbehind: true,
-        greedy: true,
-      },
-    ],
-    // TODO Could be nice to handle Heredoc too.
-    string: [
-      {
-        pattern: RegExp(
-          /\b(?:q|qq|qw|qx)(?![a-zA-Z0-9])\s*/.source +
-            "(?:" +
-            [
-              // q/.../
-              /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
-
-              // q a...a
-              // eslint-disable-next-line regexp/strict
-              /([a-zA-Z0-9])(?:(?!\2)[^\\]|\\[\s\S])*\2/.source,
-
-              // q(...)
-              // q{...}
-              // q[...]
-              // q<...>
-              brackets,
-            ].join("|") +
-            ")",
-        ),
-        greedy: true,
-      },
-
-      // "...", `...`
-      {
-        pattern: /("|`)(?:(?!\1)[^\\]|\\[\s\S])*\1/,
-        greedy: true,
-      },
-
-      // '...'
-      // FIXME Multi-line single-quoted strings are not supported as they would break variables containing '
-      {
-        pattern: /'(?:[^'\\\r\n]|\\.)*'/,
-        greedy: true,
-      },
-    ],
-    regex: [
-      {
-        pattern: RegExp(
-          /\b(?:m|qr)(?![a-zA-Z0-9])\s*/.source +
-            "(?:" +
-            [
-              // m/.../
-              /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
-
-              // m a...a
-              // eslint-disable-next-line regexp/strict
-              /([a-zA-Z0-9])(?:(?!\2)[^\\]|\\[\s\S])*\2/.source,
-
-              // m(...)
-              // m{...}
-              // m[...]
-              // m<...>
-              brackets,
-            ].join("|") +
-            ")" +
-            /[msixpodualngc]*/.source,
-        ),
-        greedy: true,
-      },
-
-      // The lookbehinds prevent -s from breaking
-      {
-        pattern: RegExp(
-          /(^|[^-])\b(?:s|tr|y)(?![a-zA-Z0-9])\s*/.source +
-            "(?:" +
-            [
-              // s/.../.../
-              // eslint-disable-next-line regexp/strict
-              /([^a-zA-Z0-9\s{(\[<])(?:(?!\2)[^\\]|\\[\s\S])*\2(?:(?!\2)[^\\]|\\[\s\S])*\2/
-                .source,
-
-              // s a...a...a
-              // eslint-disable-next-line regexp/strict
-              /([a-zA-Z0-9])(?:(?!\3)[^\\]|\\[\s\S])*\3(?:(?!\3)[^\\]|\\[\s\S])*\3/
-                .source,
-
-              // s(...)(...)
-              // s{...}{...}
-              // s[...][...]
-              // s<...><...>
-              // s(...)[...]
-              brackets + /\s*/.source + brackets,
-            ].join("|") +
-            ")" +
-            /[msixpodualngcer]*/.source,
-        ),
-        lookbehind: true,
-        greedy: true,
-      },
-
-      // /.../
-      // The look-ahead tries to prevent two divisions on
-      // the same line from being highlighted as regex.
-      // This does not support multi-line regex.
-      {
-        pattern:
-          /\/(?:[^\/\\\r\n]|\\.)*\/[msixpodualngc]*(?=\s*(?:$|[\r\n,.;})&|\-+*~<>!?^]|(?:and|cmp|eq|ge|gt|le|lt|ne|not|or|x|xor)\b))/,
-        greedy: true,
-      },
-    ],
-
-    // FIXME Not sure about the handling of ::, ', and #
-    variable: [
-      // ${^POSTMATCH}
-      /[&*$@%]\{\^[A-Z]+\}/,
-      // $^V
-      /[&*$@%]\^[A-Z_]/,
-      // ${...}
-      /[&*$@%]#?(?=\{)/,
-      // $foo
-      /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+(?![\w$]))+(?:::)*/,
-      // $1
-      /[&*$@%]\d+/,
-      // $_, @_, %!
-      // The negative lookahead prevents from breaking the %= operator
-      /(?!%=)[$@%][!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/,
-    ],
-    filehandle: {
-      // <>, <FOO>, _
-      pattern: /<(?![<=])\S*?>|\b_\b/,
-      alias: "symbol",
-    },
-    "v-string": {
-      // v1.2, 1.2.3
-      pattern: /v\d+(?:\.\d+)*|\d+(?:\.\d+){2,}/,
-      alias: "string",
-    },
-    function: {
-      pattern: /(\bsub[ \t]+)\w+/,
-      lookbehind: true,
-    },
-    keyword:
-      /\b(?:any|break|continue|default|delete|die|do|else|elsif|eval|for|foreach|given|goto|if|last|local|my|next|our|package|print|redo|require|return|say|state|sub|switch|undef|unless|until|use|when|while)\b/,
-    number:
-      /\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)\b/,
-    operator:
-      /-[rwxoRWXOezsfdlpSbctugkTBMAC]\b|\+[+=]?|-[-=>]?|\*\*?=?|\/\/?=?|=[=~>]?|~[~=]?|\|\|?=?|&&?=?|<(?:=>?|<=?)?|>>?=?|![~=]?|[%^]=?|\.(?:=|\.\.?)?|[\\?]|\bx(?:=|\b)|\b(?:and|cmp|eq|ge|gt|le|lt|ne|not|or|xor)\b/,
-    punctuation: /[{}[\];(),:]/,
-  };
-})(Prism);
+
+	var brackets = /(?:\((?:[^()\\]|\\[\s\S])*\)|\{(?:[^{}\\]|\\[\s\S])*\}|\[(?:[^[\]\\]|\\[\s\S])*\]|<(?:[^<>\\]|\\[\s\S])*>)/.source;
+
+	Prism.languages.perl = {
+		'comment': [
+			{
+				// POD
+				pattern: /(^\s*)=\w[\s\S]*?=cut.*/m,
+				lookbehind: true,
+				greedy: true
+			},
+			{
+				pattern: /(^|[^\\$])#.*/,
+				lookbehind: true,
+				greedy: true
+			}
+		],
+		// TODO Could be nice to handle Heredoc too.
+		'string': [
+			{
+				pattern: RegExp(
+					/\b(?:q|qq|qw|qx)(?![a-zA-Z0-9])\s*/.source +
+					'(?:' +
+					[
+						// q/.../
+						/([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
+
+						// q a...a
+						// eslint-disable-next-line regexp/strict
+						/([a-zA-Z0-9])(?:(?!\2)[^\\]|\\[\s\S])*\2/.source,
+
+						// q(...)
+						// q{...}
+						// q[...]
+						// q<...>
+						brackets,
+					].join('|') +
+					')'
+				),
+				greedy: true
+			},
+
+			// "...", `...`
+			{
+				pattern: /("|`)(?:(?!\1)[^\\]|\\[\s\S])*\1/,
+				greedy: true
+			},
+
+			// '...'
+			// FIXME Multi-line single-quoted strings are not supported as they would break variables containing '
+			{
+				pattern: /'(?:[^'\\\r\n]|\\.)*'/,
+				greedy: true
+			}
+		],
+		'regex': [
+			{
+				pattern: RegExp(
+					/\b(?:m|qr)(?![a-zA-Z0-9])\s*/.source +
+					'(?:' +
+					[
+						// m/.../
+						/([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
+
+						// m a...a
+						// eslint-disable-next-line regexp/strict
+						/([a-zA-Z0-9])(?:(?!\2)[^\\]|\\[\s\S])*\2/.source,
+
+						// m(...)
+						// m{...}
+						// m[...]
+						// m<...>
+						brackets,
+					].join('|') +
+					')' +
+					/[msixpodualngc]*/.source
+				),
+				greedy: true
+			},
+
+			// The lookbehinds prevent -s from breaking
+			{
+				pattern: RegExp(
+					/(^|[^-])\b(?:s|tr|y)(?![a-zA-Z0-9])\s*/.source +
+					'(?:' +
+					[
+						// s/.../.../
+						// eslint-disable-next-line regexp/strict
+						/([^a-zA-Z0-9\s{(\[<])(?:(?!\2)[^\\]|\\[\s\S])*\2(?:(?!\2)[^\\]|\\[\s\S])*\2/.source,
+
+						// s a...a...a
+						// eslint-disable-next-line regexp/strict
+						/([a-zA-Z0-9])(?:(?!\3)[^\\]|\\[\s\S])*\3(?:(?!\3)[^\\]|\\[\s\S])*\3/.source,
+
+						// s(...)(...)
+						// s{...}{...}
+						// s[...][...]
+						// s<...><...>
+						// s(...)[...]
+						brackets + /\s*/.source + brackets,
+					].join('|') +
+					')' +
+					/[msixpodualngcer]*/.source
+				),
+				lookbehind: true,
+				greedy: true
+			},
+
+			// /.../
+			// The look-ahead tries to prevent two divisions on
+			// the same line from being highlighted as regex.
+			// This does not support multi-line regex.
+			{
+				pattern: /\/(?:[^\/\\\r\n]|\\.)*\/[msixpodualngc]*(?=\s*(?:$|[\r\n,.;})&|\-+*~<>!?^]|(?:and|cmp|eq|ge|gt|le|lt|ne|not|or|x|xor)\b))/,
+				greedy: true
+			}
+		],
+
+		// FIXME Not sure about the handling of ::, ', and #
+		'variable': [
+			// ${^POSTMATCH}
+			/[&*$@%]\{\^[A-Z]+\}/,
+			// $^V
+			/[&*$@%]\^[A-Z_]/,
+			// ${...}
+			/[&*$@%]#?(?=\{)/,
+			// $foo
+			/[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+(?![\w$]))+(?:::)*/,
+			// $1
+			/[&*$@%]\d+/,
+			// $_, @_, %!
+			// The negative lookahead prevents from breaking the %= operator
+			/(?!%=)[$@%][!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/
+		],
+		'filehandle': {
+			// <>, <FOO>, _
+			pattern: /<(?![<=])\S*?>|\b_\b/,
+			alias: 'symbol'
+		},
+		'v-string': {
+			// v1.2, 1.2.3
+			pattern: /v\d+(?:\.\d+)*|\d+(?:\.\d+){2,}/,
+			alias: 'string'
+		},
+		'function': {
+			pattern: /(\bsub[ \t]+)\w+/,
+			lookbehind: true
+		},
+		'keyword': /\b(?:any|break|continue|default|delete|die|do|else|elsif|eval|for|foreach|given|goto|if|last|local|my|next|our|package|print|redo|require|return|say|state|sub|switch|undef|unless|until|use|when|while)\b/,
+		'number': /\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)\b/,
+		'operator': /-[rwxoRWXOezsfdlpSbctugkTBMAC]\b|\+[+=]?|-[-=>]?|\*\*?=?|\/\/?=?|=[=~>]?|~[~=]?|\|\|?=?|&&?=?|<(?:=>?|<=?)?|>>?=?|![~=]?|[%^]=?|\.(?:=|\.\.?)?|[\\?]|\bx(?:=|\b)|\b(?:and|cmp|eq|ge|gt|le|lt|ne|not|or|xor)\b/,
+		'punctuation': /[{}[\];(),:]/
+	};
+
+}(Prism));
 
 /**
  * Original by Aaron Harun: http://aahacreative.com/2012/07/31/php-syntax-highlighting-prism/
@@ -4619,1409 +4327,1295 @@ Prism.languages.ocaml = {
  * Supports PHP 5.3 - 8.0
  */
 (function (Prism) {
-  var comment = /\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/;
-  var constant = [
-    {
-      pattern: /\b(?:false|true)\b/i,
-      alias: "boolean",
-    },
-    {
-      pattern: /(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,
-      greedy: true,
-      lookbehind: true,
-    },
-    {
-      pattern: /(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,
-      greedy: true,
-      lookbehind: true,
-    },
-    /\b(?:null)\b/i,
-    /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/,
-  ];
-  var number =
-    /\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i;
-  var operator =
-    /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/;
-  var punctuation = /[{}\[\](),:;]/;
-
-  Prism.languages.php = {
-    delimiter: {
-      pattern: /\?>$|^<\?(?:php(?=\s)|=)?/i,
-      alias: "important",
-    },
-    comment: comment,
-    variable: /\$+(?:\w+\b|(?=\{))/,
-    package: {
-      pattern:
-        /(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
-      lookbehind: true,
-      inside: {
-        punctuation: /\\/,
-      },
-    },
-    "class-name-definition": {
-      pattern: /(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,
-      lookbehind: true,
-      alias: "class-name",
-    },
-    "function-definition": {
-      pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,
-      lookbehind: true,
-      alias: "function",
-    },
-    keyword: [
-      {
-        pattern:
-          /(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,
-        alias: "type-casting",
-        greedy: true,
-        lookbehind: true,
-      },
-      {
-        pattern:
-          /([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,
-        alias: "type-hint",
-        greedy: true,
-        lookbehind: true,
-      },
-      {
-        pattern:
-          /(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,
-        alias: "return-type",
-        greedy: true,
-        lookbehind: true,
-      },
-      {
-        pattern:
-          /\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,
-        alias: "type-declaration",
-        greedy: true,
-      },
-      {
-        pattern: /(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,
-        alias: "type-declaration",
-        greedy: true,
-        lookbehind: true,
-      },
-      {
-        pattern: /\b(?:parent|self|static)(?=\s*::)/i,
-        alias: "static-context",
-        greedy: true,
-      },
-      {
-        // yield from
-        pattern: /(\byield\s+)from\b/i,
-        lookbehind: true,
-      },
-      // `class` is always a keyword unlike other keywords
-      /\bclass\b/i,
-      {
-        // https://www.php.net/manual/en/reserved.keywords.php
-        //
-        // keywords cannot be preceded by "->"
-        // the complex lookbehind means `(?<!(?:->|::)\s*)`
-        pattern:
-          /((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,
-        lookbehind: true,
-      },
-    ],
-    "argument-name": {
-      pattern: /([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,
-      lookbehind: true,
-    },
-    "class-name": [
-      {
-        pattern:
-          /(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,
-        greedy: true,
-        lookbehind: true,
-      },
-      {
-        pattern: /(\|\s*)\b[a-z_]\w*(?!\\)\b/i,
-        greedy: true,
-        lookbehind: true,
-      },
-      {
-        pattern: /\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,
-        greedy: true,
-      },
-      {
-        pattern: /(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,
-        alias: "class-name-fully-qualified",
-        greedy: true,
-        lookbehind: true,
-        inside: {
-          punctuation: /\\/,
-        },
-      },
-      {
-        pattern: /(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,
-        alias: "class-name-fully-qualified",
-        greedy: true,
-        inside: {
-          punctuation: /\\/,
-        },
-      },
-      {
-        pattern:
-          /(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
-        alias: "class-name-fully-qualified",
-        greedy: true,
-        lookbehind: true,
-        inside: {
-          punctuation: /\\/,
-        },
-      },
-      {
-        pattern: /\b[a-z_]\w*(?=\s*\$)/i,
-        alias: "type-declaration",
-        greedy: true,
-      },
-      {
-        pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,
-        alias: ["class-name-fully-qualified", "type-declaration"],
-        greedy: true,
-        inside: {
-          punctuation: /\\/,
-        },
-      },
-      {
-        pattern: /\b[a-z_]\w*(?=\s*::)/i,
-        alias: "static-context",
-        greedy: true,
-      },
-      {
-        pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,
-        alias: ["class-name-fully-qualified", "static-context"],
-        greedy: true,
-        inside: {
-          punctuation: /\\/,
-        },
-      },
-      {
-        pattern: /([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,
-        alias: "type-hint",
-        greedy: true,
-        lookbehind: true,
-      },
-      {
-        pattern: /([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,
-        alias: ["class-name-fully-qualified", "type-hint"],
-        greedy: true,
-        lookbehind: true,
-        inside: {
-          punctuation: /\\/,
-        },
-      },
-      {
-        pattern: /(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,
-        alias: "return-type",
-        greedy: true,
-        lookbehind: true,
-      },
-      {
-        pattern: /(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
-        alias: ["class-name-fully-qualified", "return-type"],
-        greedy: true,
-        lookbehind: true,
-        inside: {
-          punctuation: /\\/,
-        },
-      },
-    ],
-    constant: constant,
-    function: {
-      pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,
-      lookbehind: true,
-      inside: {
-        punctuation: /\\/,
-      },
-    },
-    property: {
-      pattern: /(->\s*)\w+/,
-      lookbehind: true,
-    },
-    number: number,
-    operator: operator,
-    punctuation: punctuation,
-  };
-
-  var string_interpolation = {
-    pattern:
-      /\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,
-    lookbehind: true,
-    inside: Prism.languages.php,
-  };
-
-  var string = [
-    {
-      pattern: /<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,
-      alias: "nowdoc-string",
-      greedy: true,
-      inside: {
-        delimiter: {
-          pattern: /^<<<'[^']+'|[a-z_]\w*;$/i,
-          alias: "symbol",
-          inside: {
-            punctuation: /^<<<'?|[';]$/,
-          },
-        },
-      },
-    },
-    {
-      pattern:
-        /<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,
-      alias: "heredoc-string",
-      greedy: true,
-      inside: {
-        delimiter: {
-          pattern: /^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,
-          alias: "symbol",
-          inside: {
-            punctuation: /^<<<"?|[";]$/,
-          },
-        },
-        interpolation: string_interpolation,
-      },
-    },
-    {
-      pattern: /`(?:\\[\s\S]|[^\\`])*`/,
-      alias: "backtick-quoted-string",
-      greedy: true,
-    },
-    {
-      pattern: /'(?:\\[\s\S]|[^\\'])*'/,
-      alias: "single-quoted-string",
-      greedy: true,
-    },
-    {
-      pattern: /"(?:\\[\s\S]|[^\\"])*"/,
-      alias: "double-quoted-string",
-      greedy: true,
-      inside: {
-        interpolation: string_interpolation,
-      },
-    },
-  ];
-
-  Prism.languages.insertBefore("php", "variable", {
-    string: string,
-    attribute: {
-      pattern:
-        /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,
-      greedy: true,
-      inside: {
-        "attribute-content": {
-          pattern: /^(#\[)[\s\S]+(?=\]$)/,
-          lookbehind: true,
-          // inside can appear subset of php
-          inside: {
-            comment: comment,
-            string: string,
-            "attribute-class-name": [
-              {
-                pattern: /([^:]|^)\b[a-z_]\w*(?!\\)\b/i,
-                alias: "class-name",
-                greedy: true,
-                lookbehind: true,
-              },
-              {
-                pattern: /([^:]|^)(?:\\?\b[a-z_]\w*)+/i,
-                alias: ["class-name", "class-name-fully-qualified"],
-                greedy: true,
-                lookbehind: true,
-                inside: {
-                  punctuation: /\\/,
-                },
-              },
-            ],
-            constant: constant,
-            number: number,
-            operator: operator,
-            punctuation: punctuation,
-          },
-        },
-        delimiter: {
-          pattern: /^#\[|\]$/,
-          alias: "punctuation",
-        },
-      },
-    },
-  });
-
-  Prism.hooks.add("before-tokenize", function (env) {
-    if (!/<\?/.test(env.code)) {
-      return;
-    }
-
-    var phpPattern =
-      /<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g;
-    Prism.languages["markup-templating"].buildPlaceholders(
-      env,
-      "php",
-      phpPattern,
-    );
-  });
-
-  Prism.hooks.add("after-tokenize", function (env) {
-    Prism.languages["markup-templating"].tokenizePlaceholders(env, "php");
-  });
-})(Prism);
+	var comment = /\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/;
+	var constant = [
+		{
+			pattern: /\b(?:false|true)\b/i,
+			alias: 'boolean'
+		},
+		{
+			pattern: /(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,
+			greedy: true,
+			lookbehind: true,
+		},
+		{
+			pattern: /(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,
+			greedy: true,
+			lookbehind: true,
+		},
+		/\b(?:null)\b/i,
+		/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/,
+	];
+	var number = /\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i;
+	var operator = /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/;
+	var punctuation = /[{}\[\](),:;]/;
+
+	Prism.languages.php = {
+		'delimiter': {
+			pattern: /\?>$|^<\?(?:php(?=\s)|=)?/i,
+			alias: 'important'
+		},
+		'comment': comment,
+		'variable': /\$+(?:\w+\b|(?=\{))/,
+		'package': {
+			pattern: /(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
+			lookbehind: true,
+			inside: {
+				'punctuation': /\\/
+			}
+		},
+		'class-name-definition': {
+			pattern: /(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,
+			lookbehind: true,
+			alias: 'class-name'
+		},
+		'function-definition': {
+			pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,
+			lookbehind: true,
+			alias: 'function'
+		},
+		'keyword': [
+			{
+				pattern: /(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,
+				alias: 'type-casting',
+				greedy: true,
+				lookbehind: true
+			},
+			{
+				pattern: /([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,
+				alias: 'type-hint',
+				greedy: true,
+				lookbehind: true
+			},
+			{
+				pattern: /(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,
+				alias: 'return-type',
+				greedy: true,
+				lookbehind: true
+			},
+			{
+				pattern: /\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,
+				alias: 'type-declaration',
+				greedy: true
+			},
+			{
+				pattern: /(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,
+				alias: 'type-declaration',
+				greedy: true,
+				lookbehind: true
+			},
+			{
+				pattern: /\b(?:parent|self|static)(?=\s*::)/i,
+				alias: 'static-context',
+				greedy: true
+			},
+			{
+				// yield from
+				pattern: /(\byield\s+)from\b/i,
+				lookbehind: true
+			},
+			// `class` is always a keyword unlike other keywords
+			/\bclass\b/i,
+			{
+				// https://www.php.net/manual/en/reserved.keywords.php
+				//
+				// keywords cannot be preceded by "->"
+				// the complex lookbehind means `(?<!(?:->|::)\s*)`
+				pattern: /((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,
+				lookbehind: true
+			}
+		],
+		'argument-name': {
+			pattern: /([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,
+			lookbehind: true
+		},
+		'class-name': [
+			{
+				pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,
+				greedy: true,
+				lookbehind: true
+			},
+			{
+				pattern: /(\|\s*)\b[a-z_]\w*(?!\\)\b/i,
+				greedy: true,
+				lookbehind: true
+			},
+			{
+				pattern: /\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,
+				greedy: true
+			},
+			{
+				pattern: /(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,
+				alias: 'class-name-fully-qualified',
+				greedy: true,
+				lookbehind: true,
+				inside: {
+					'punctuation': /\\/
+				}
+			},
+			{
+				pattern: /(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,
+				alias: 'class-name-fully-qualified',
+				greedy: true,
+				inside: {
+					'punctuation': /\\/
+				}
+			},
+			{
+				pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
+				alias: 'class-name-fully-qualified',
+				greedy: true,
+				lookbehind: true,
+				inside: {
+					'punctuation': /\\/
+				}
+			},
+			{
+				pattern: /\b[a-z_]\w*(?=\s*\$)/i,
+				alias: 'type-declaration',
+				greedy: true
+			},
+			{
+				pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,
+				alias: ['class-name-fully-qualified', 'type-declaration'],
+				greedy: true,
+				inside: {
+					'punctuation': /\\/
+				}
+			},
+			{
+				pattern: /\b[a-z_]\w*(?=\s*::)/i,
+				alias: 'static-context',
+				greedy: true
+			},
+			{
+				pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,
+				alias: ['class-name-fully-qualified', 'static-context'],
+				greedy: true,
+				inside: {
+					'punctuation': /\\/
+				}
+			},
+			{
+				pattern: /([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,
+				alias: 'type-hint',
+				greedy: true,
+				lookbehind: true
+			},
+			{
+				pattern: /([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,
+				alias: ['class-name-fully-qualified', 'type-hint'],
+				greedy: true,
+				lookbehind: true,
+				inside: {
+					'punctuation': /\\/
+				}
+			},
+			{
+				pattern: /(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,
+				alias: 'return-type',
+				greedy: true,
+				lookbehind: true
+			},
+			{
+				pattern: /(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
+				alias: ['class-name-fully-qualified', 'return-type'],
+				greedy: true,
+				lookbehind: true,
+				inside: {
+					'punctuation': /\\/
+				}
+			}
+		],
+		'constant': constant,
+		'function': {
+			pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,
+			lookbehind: true,
+			inside: {
+				'punctuation': /\\/
+			}
+		},
+		'property': {
+			pattern: /(->\s*)\w+/,
+			lookbehind: true
+		},
+		'number': number,
+		'operator': operator,
+		'punctuation': punctuation
+	};
+
+	var string_interpolation = {
+		pattern: /\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,
+		lookbehind: true,
+		inside: Prism.languages.php
+	};
+
+	var string = [
+		{
+			pattern: /<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,
+			alias: 'nowdoc-string',
+			greedy: true,
+			inside: {
+				'delimiter': {
+					pattern: /^<<<'[^']+'|[a-z_]\w*;$/i,
+					alias: 'symbol',
+					inside: {
+						'punctuation': /^<<<'?|[';]$/
+					}
+				}
+			}
+		},
+		{
+			pattern: /<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,
+			alias: 'heredoc-string',
+			greedy: true,
+			inside: {
+				'delimiter': {
+					pattern: /^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,
+					alias: 'symbol',
+					inside: {
+						'punctuation': /^<<<"?|[";]$/
+					}
+				},
+				'interpolation': string_interpolation
+			}
+		},
+		{
+			pattern: /`(?:\\[\s\S]|[^\\`])*`/,
+			alias: 'backtick-quoted-string',
+			greedy: true
+		},
+		{
+			pattern: /'(?:\\[\s\S]|[^\\'])*'/,
+			alias: 'single-quoted-string',
+			greedy: true
+		},
+		{
+			pattern: /"(?:\\[\s\S]|[^\\"])*"/,
+			alias: 'double-quoted-string',
+			greedy: true,
+			inside: {
+				'interpolation': string_interpolation
+			}
+		}
+	];
+
+	Prism.languages.insertBefore('php', 'variable', {
+		'string': string,
+		'attribute': {
+			pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,
+			greedy: true,
+			inside: {
+				'attribute-content': {
+					pattern: /^(#\[)[\s\S]+(?=\]$)/,
+					lookbehind: true,
+					// inside can appear subset of php
+					inside: {
+						'comment': comment,
+						'string': string,
+						'attribute-class-name': [
+							{
+								pattern: /([^:]|^)\b[a-z_]\w*(?!\\)\b/i,
+								alias: 'class-name',
+								greedy: true,
+								lookbehind: true
+							},
+							{
+								pattern: /([^:]|^)(?:\\?\b[a-z_]\w*)+/i,
+								alias: [
+									'class-name',
+									'class-name-fully-qualified'
+								],
+								greedy: true,
+								lookbehind: true,
+								inside: {
+									'punctuation': /\\/
+								}
+							}
+						],
+						'constant': constant,
+						'number': number,
+						'operator': operator,
+						'punctuation': punctuation
+					}
+				},
+				'delimiter': {
+					pattern: /^#\[|\]$/,
+					alias: 'punctuation'
+				}
+			}
+		},
+	});
+
+	Prism.hooks.add('before-tokenize', function (env) {
+		if (!/<\?/.test(env.code)) {
+			return;
+		}
+
+		var phpPattern = /<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g;
+		Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern);
+	});
+
+	Prism.hooks.add('after-tokenize', function (env) {
+		Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php');
+	});
+
+}(Prism));
 
 Prism.languages.python = {
-  comment: {
-    pattern: /(^|[^\\])#.*/,
-    lookbehind: true,
-    greedy: true,
-  },
-  "string-interpolation": {
-    pattern:
-      /(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,
-    greedy: true,
-    inside: {
-      interpolation: {
-        // "{" <expression> <optional "!s", "!r", or "!a"> <optional ":" format specifier> "}"
-        pattern:
-          /((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,
-        lookbehind: true,
-        inside: {
-          "format-spec": {
-            pattern: /(:)[^:(){}]+(?=\}$)/,
-            lookbehind: true,
-          },
-          "conversion-option": {
-            pattern: /![sra](?=[:}]$)/,
-            alias: "punctuation",
-          },
-          rest: null,
-        },
-      },
-      string: /[\s\S]+/,
-    },
-  },
-  "triple-quoted-string": {
-    pattern: /(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,
-    greedy: true,
-    alias: "string",
-  },
-  string: {
-    pattern: /(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,
-    greedy: true,
-  },
-  function: {
-    pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,
-    lookbehind: true,
-  },
-  "class-name": {
-    pattern: /(\bclass\s+)\w+/i,
-    lookbehind: true,
-  },
-  decorator: {
-    pattern: /(^[\t ]*)@\w+(?:\.\w+)*/m,
-    lookbehind: true,
-    alias: ["annotation", "punctuation"],
-    inside: {
-      punctuation: /\./,
-    },
-  },
-  keyword:
-    /\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,
-  builtin:
-    /\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,
-  boolean: /\b(?:False|None|True)\b/,
-  number:
-    /\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,
-  operator: /[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,
-  punctuation: /[{}[\];(),.:]/,
+	'comment': {
+		pattern: /(^|[^\\])#.*/,
+		lookbehind: true,
+		greedy: true
+	},
+	'string-interpolation': {
+		pattern: /(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,
+		greedy: true,
+		inside: {
+			'interpolation': {
+				// "{" <expression> <optional "!s", "!r", or "!a"> <optional ":" format specifier> "}"
+				pattern: /((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,
+				lookbehind: true,
+				inside: {
+					'format-spec': {
+						pattern: /(:)[^:(){}]+(?=\}$)/,
+						lookbehind: true
+					},
+					'conversion-option': {
+						pattern: /![sra](?=[:}]$)/,
+						alias: 'punctuation'
+					},
+					rest: null
+				}
+			},
+			'string': /[\s\S]+/
+		}
+	},
+	'triple-quoted-string': {
+		pattern: /(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,
+		greedy: true,
+		alias: 'string'
+	},
+	'string': {
+		pattern: /(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,
+		greedy: true
+	},
+	'function': {
+		pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,
+		lookbehind: true
+	},
+	'class-name': {
+		pattern: /(\bclass\s+)\w+/i,
+		lookbehind: true
+	},
+	'decorator': {
+		pattern: /(^[\t ]*)@\w+(?:\.\w+)*/m,
+		lookbehind: true,
+		alias: ['annotation', 'punctuation'],
+		inside: {
+			'punctuation': /\./
+		}
+	},
+	'keyword': /\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,
+	'builtin': /\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,
+	'boolean': /\b(?:False|None|True)\b/,
+	'number': /\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,
+	'operator': /[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,
+	'punctuation': /[{}[\];(),.:]/
 };
 
-Prism.languages.python["string-interpolation"].inside[
-  "interpolation"
-].inside.rest = Prism.languages.python;
+Prism.languages.python['string-interpolation'].inside['interpolation'].inside.rest = Prism.languages.python;
 
 Prism.languages.py = Prism.languages.python;
 
 (function (Prism) {
-  var jsString = /"(?:\\.|[^\\"\r\n])*"|'(?:\\.|[^\\'\r\n])*'/.source;
-  var jsComment = /\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))*\*\//.source;
-
-  var jsExpr =
-    /(?:[^\\()[\]{}"'/]|<string>|\/(?![*/])|<comment>|\(<expr>*\)|\[<expr>*\]|\{<expr>*\}|\\[\s\S])/.source
-      .replace(/<string>/g, function () {
-        return jsString;
-      })
-      .replace(/<comment>/g, function () {
-        return jsComment;
-      });
-
-  // the pattern will blow up, so only a few iterations
-  for (var i = 0; i < 2; i++) {
-    jsExpr = jsExpr.replace(/<expr>/g, function () {
-      return jsExpr;
-    });
-  }
-  jsExpr = jsExpr.replace(/<expr>/g, "[^\\s\\S]");
-
-  Prism.languages.qml = {
-    comment: {
-      pattern: /\/\/.*|\/\*[\s\S]*?\*\//,
-      greedy: true,
-    },
-    "javascript-function": {
-      pattern: RegExp(
-        /((?:^|;)[ \t]*)function\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*\(<js>*\)\s*\{<js>*\}/.source.replace(
-          /<js>/g,
-          function () {
-            return jsExpr;
-          },
-        ),
-        "m",
-      ),
-      lookbehind: true,
-      greedy: true,
-      alias: "language-javascript",
-      inside: Prism.languages.javascript,
-    },
-    "class-name": {
-      pattern: /((?:^|[:;])[ \t]*)(?!\d)\w+(?=[ \t]*\{|[ \t]+on\b)/m,
-      lookbehind: true,
-    },
-    property: [
-      {
-        pattern: /((?:^|[;{])[ \t]*)(?!\d)\w+(?:\.\w+)*(?=[ \t]*:)/m,
-        lookbehind: true,
-      },
-      {
-        pattern:
-          /((?:^|[;{])[ \t]*)property[ \t]+(?!\d)\w+(?:\.\w+)*[ \t]+(?!\d)\w+(?:\.\w+)*(?=[ \t]*:)/m,
-        lookbehind: true,
-        inside: {
-          keyword: /^property/,
-          property: /\w+(?:\.\w+)*/,
-        },
-      },
-    ],
-    "javascript-expression": {
-      pattern: RegExp(
-        /(:[ \t]*)(?![\s;}[])(?:(?!$|[;}])<js>)+/.source.replace(
-          /<js>/g,
-          function () {
-            return jsExpr;
-          },
-        ),
-        "m",
-      ),
-      lookbehind: true,
-      greedy: true,
-      alias: "language-javascript",
-      inside: Prism.languages.javascript,
-    },
-    string: {
-      pattern: /"(?:\\.|[^\\"\r\n])*"/,
-      greedy: true,
-    },
-    keyword: /\b(?:as|import|on)\b/,
-    punctuation: /[{}[\]:;,]/,
-  };
-})(Prism);
+
+	var jsString = /"(?:\\.|[^\\"\r\n])*"|'(?:\\.|[^\\'\r\n])*'/.source;
+	var jsComment = /\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))*\*\//.source;
+
+	var jsExpr = /(?:[^\\()[\]{}"'/]|<string>|\/(?![*/])|<comment>|\(<expr>*\)|\[<expr>*\]|\{<expr>*\}|\\[\s\S])/
+		.source.replace(/<string>/g, function () { return jsString; }).replace(/<comment>/g, function () { return jsComment; });
+
+	// the pattern will blow up, so only a few iterations
+	for (var i = 0; i < 2; i++) {
+		jsExpr = jsExpr.replace(/<expr>/g, function () { return jsExpr; });
+	}
+	jsExpr = jsExpr.replace(/<expr>/g, '[^\\s\\S]');
+
+
+	Prism.languages.qml = {
+		'comment': {
+			pattern: /\/\/.*|\/\*[\s\S]*?\*\//,
+			greedy: true
+		},
+		'javascript-function': {
+			pattern: RegExp(/((?:^|;)[ \t]*)function\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*\(<js>*\)\s*\{<js>*\}/.source.replace(/<js>/g, function () { return jsExpr; }), 'm'),
+			lookbehind: true,
+			greedy: true,
+			alias: 'language-javascript',
+			inside: Prism.languages.javascript
+		},
+		'class-name': {
+			pattern: /((?:^|[:;])[ \t]*)(?!\d)\w+(?=[ \t]*\{|[ \t]+on\b)/m,
+			lookbehind: true
+		},
+		'property': [
+			{
+				pattern: /((?:^|[;{])[ \t]*)(?!\d)\w+(?:\.\w+)*(?=[ \t]*:)/m,
+				lookbehind: true
+			},
+			{
+				pattern: /((?:^|[;{])[ \t]*)property[ \t]+(?!\d)\w+(?:\.\w+)*[ \t]+(?!\d)\w+(?:\.\w+)*(?=[ \t]*:)/m,
+				lookbehind: true,
+				inside: {
+					'keyword': /^property/,
+					'property': /\w+(?:\.\w+)*/
+				}
+			}
+		],
+		'javascript-expression': {
+			pattern: RegExp(/(:[ \t]*)(?![\s;}[])(?:(?!$|[;}])<js>)+/.source.replace(/<js>/g, function () { return jsExpr; }), 'm'),
+			lookbehind: true,
+			greedy: true,
+			alias: 'language-javascript',
+			inside: Prism.languages.javascript
+		},
+		'string': {
+			pattern: /"(?:\\.|[^\\"\r\n])*"/,
+			greedy: true
+		},
+		'keyword': /\b(?:as|import|on)\b/,
+		'punctuation': /[{}[\]:;,]/
+	};
+
+}(Prism));
 
 Prism.languages.r = {
-  comment: /#.*/,
-  string: {
-    pattern: /(['"])(?:\\.|(?!\1)[^\\\r\n])*\1/,
-    greedy: true,
-  },
-  "percent-operator": {
-    // Includes user-defined operators
-    // and %%, %*%, %/%, %in%, %o%, %x%
-    pattern: /%[^%\s]*%/,
-    alias: "operator",
-  },
-  boolean: /\b(?:FALSE|TRUE)\b/,
-  ellipsis: /\.\.(?:\.|\d+)/,
-  number: [
-    /\b(?:Inf|NaN)\b/,
-    /(?:\b0x[\dA-Fa-f]+(?:\.\d*)?|\b\d+(?:\.\d*)?|\B\.\d+)(?:[EePp][+-]?\d+)?[iL]?/,
-  ],
-  keyword:
-    /\b(?:NA|NA_character_|NA_complex_|NA_integer_|NA_real_|NULL|break|else|for|function|if|in|next|repeat|while)\b/,
-  operator: /->?>?|<(?:=|<?-)?|[>=!]=?|::?|&&?|\|\|?|[+*\/^$@~]/,
-  punctuation: /[(){}\[\],;]/,
+	'comment': /#.*/,
+	'string': {
+		pattern: /(['"])(?:\\.|(?!\1)[^\\\r\n])*\1/,
+		greedy: true
+	},
+	'percent-operator': {
+		// Includes user-defined operators
+		// and %%, %*%, %/%, %in%, %o%, %x%
+		pattern: /%[^%\s]*%/,
+		alias: 'operator'
+	},
+	'boolean': /\b(?:FALSE|TRUE)\b/,
+	'ellipsis': /\.\.(?:\.|\d+)/,
+	'number': [
+		/\b(?:Inf|NaN)\b/,
+		/(?:\b0x[\dA-Fa-f]+(?:\.\d*)?|\b\d+(?:\.\d*)?|\B\.\d+)(?:[EePp][+-]?\d+)?[iL]?/
+	],
+	'keyword': /\b(?:NA|NA_character_|NA_complex_|NA_integer_|NA_real_|NULL|break|else|for|function|if|in|next|repeat|while)\b/,
+	'operator': /->?>?|<(?:=|<?-)?|[>=!]=?|::?|&&?|\|\|?|[+*\/^$@~]/,
+	'punctuation': /[(){}\[\],;]/
 };
 
 (function (Prism) {
-  var javascript = Prism.util.clone(Prism.languages.javascript);
-
-  var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
-  var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
-  var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
-
-  /**
-   * @param {string} source
-   * @param {string} [flags]
-   */
-  function re(source, flags) {
-    source = source
-      .replace(/<S>/g, function () {
-        return space;
-      })
-      .replace(/<BRACES>/g, function () {
-        return braces;
-      })
-      .replace(/<SPREAD>/g, function () {
-        return spread;
-      });
-    return RegExp(source, flags);
-  }
-
-  spread = re(spread).source;
-
-  Prism.languages.jsx = Prism.languages.extend("markup", javascript);
-  Prism.languages.jsx.tag.pattern = re(
-    /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/
-      .source,
-  );
-
-  Prism.languages.jsx.tag.inside["tag"].pattern = /^<\/?[^\s>\/]*/;
-  Prism.languages.jsx.tag.inside["attr-value"].pattern =
-    /=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/;
-  Prism.languages.jsx.tag.inside["tag"].inside["class-name"] =
-    /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
-  Prism.languages.jsx.tag.inside["comment"] = javascript["comment"];
-
-  Prism.languages.insertBefore(
-    "inside",
-    "attr-name",
-    {
-      spread: {
-        pattern: re(/<SPREAD>/.source),
-        inside: Prism.languages.jsx,
-      },
-    },
-    Prism.languages.jsx.tag,
-  );
-
-  Prism.languages.insertBefore(
-    "inside",
-    "special-attr",
-    {
-      script: {
-        // Allow for two levels of nesting
-        pattern: re(/=<BRACES>/.source),
-        alias: "language-javascript",
-        inside: {
-          "script-punctuation": {
-            pattern: /^=(?=\{)/,
-            alias: "punctuation",
-          },
-          rest: Prism.languages.jsx,
-        },
-      },
-    },
-    Prism.languages.jsx.tag,
-  );
-
-  // The following will handle plain text inside tags
-  var stringifyToken = function (token) {
-    if (!token) {
-      return "";
-    }
-    if (typeof token === "string") {
-      return token;
-    }
-    if (typeof token.content === "string") {
-      return token.content;
-    }
-    return token.content.map(stringifyToken).join("");
-  };
-
-  var walkTokens = function (tokens) {
-    var openedTags = [];
-    for (var i = 0; i < tokens.length; i++) {
-      var token = tokens[i];
-      var notTagNorBrace = false;
-
-      if (typeof token !== "string") {
-        if (
-          token.type === "tag" &&
-          token.content[0] &&
-          token.content[0].type === "tag"
-        ) {
-          // We found a tag, now find its kind
-
-          if (token.content[0].content[0].content === "</") {
-            // Closing tag
-            if (
-              openedTags.length > 0 &&
-              openedTags[openedTags.length - 1].tagName ===
-                stringifyToken(token.content[0].content[1])
-            ) {
-              // Pop matching opening tag
-              openedTags.pop();
-            }
-          } else {
-            if (token.content[token.content.length - 1].content === "/>") {
-              // Autoclosed tag, ignore
-            } else {
-              // Opening tag
-              openedTags.push({
-                tagName: stringifyToken(token.content[0].content[1]),
-                openedBraces: 0,
-              });
-            }
-          }
-        } else if (
-          openedTags.length > 0 &&
-          token.type === "punctuation" &&
-          token.content === "{"
-        ) {
-          // Here we might have entered a JSX context inside a tag
-          openedTags[openedTags.length - 1].openedBraces++;
-        } else if (
-          openedTags.length > 0 &&
-          openedTags[openedTags.length - 1].openedBraces > 0 &&
-          token.type === "punctuation" &&
-          token.content === "}"
-        ) {
-          // Here we might have left a JSX context inside a tag
-          openedTags[openedTags.length - 1].openedBraces--;
-        } else {
-          notTagNorBrace = true;
-        }
-      }
-      if (notTagNorBrace || typeof token === "string") {
-        if (
-          openedTags.length > 0 &&
-          openedTags[openedTags.length - 1].openedBraces === 0
-        ) {
-          // Here we are inside a tag, and not inside a JSX context.
-          // That's plain text: drop any tokens matched.
-          var plainText = stringifyToken(token);
-
-          // And merge text with adjacent text
-          if (
-            i < tokens.length - 1 &&
-            (typeof tokens[i + 1] === "string" ||
-              tokens[i + 1].type === "plain-text")
-          ) {
-            plainText += stringifyToken(tokens[i + 1]);
-            tokens.splice(i + 1, 1);
-          }
-          if (
-            i > 0 &&
-            (typeof tokens[i - 1] === "string" ||
-              tokens[i - 1].type === "plain-text")
-          ) {
-            plainText = stringifyToken(tokens[i - 1]) + plainText;
-            tokens.splice(i - 1, 1);
-            i--;
-          }
-
-          tokens[i] = new Prism.Token("plain-text", plainText, null, plainText);
-        }
-      }
-
-      if (token.content && typeof token.content !== "string") {
-        walkTokens(token.content);
-      }
-    }
-  };
-
-  Prism.hooks.add("after-tokenize", function (env) {
-    if (env.language !== "jsx" && env.language !== "tsx") {
-      return;
-    }
-    walkTokens(env.tokens);
-  });
-})(Prism);
+
+	var javascript = Prism.util.clone(Prism.languages.javascript);
+
+	var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
+	var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
+	var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
+
+	/**
+	 * @param {string} source
+	 * @param {string} [flags]
+	 */
+	function re(source, flags) {
+		source = source
+			.replace(/<S>/g, function () { return space; })
+			.replace(/<BRACES>/g, function () { return braces; })
+			.replace(/<SPREAD>/g, function () { return spread; });
+		return RegExp(source, flags);
+	}
+
+	spread = re(spread).source;
+
+
+	Prism.languages.jsx = Prism.languages.extend('markup', javascript);
+	Prism.languages.jsx.tag.pattern = re(
+		/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source
+	);
+
+	Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/;
+	Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/;
+	Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
+	Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];
+
+	Prism.languages.insertBefore('inside', 'attr-name', {
+		'spread': {
+			pattern: re(/<SPREAD>/.source),
+			inside: Prism.languages.jsx
+		}
+	}, Prism.languages.jsx.tag);
+
+	Prism.languages.insertBefore('inside', 'special-attr', {
+		'script': {
+			// Allow for two levels of nesting
+			pattern: re(/=<BRACES>/.source),
+			alias: 'language-javascript',
+			inside: {
+				'script-punctuation': {
+					pattern: /^=(?=\{)/,
+					alias: 'punctuation'
+				},
+				rest: Prism.languages.jsx
+			},
+		}
+	}, Prism.languages.jsx.tag);
+
+	// The following will handle plain text inside tags
+	var stringifyToken = function (token) {
+		if (!token) {
+			return '';
+		}
+		if (typeof token === 'string') {
+			return token;
+		}
+		if (typeof token.content === 'string') {
+			return token.content;
+		}
+		return token.content.map(stringifyToken).join('');
+	};
+
+	var walkTokens = function (tokens) {
+		var openedTags = [];
+		for (var i = 0; i < tokens.length; i++) {
+			var token = tokens[i];
+			var notTagNorBrace = false;
+
+			if (typeof token !== 'string') {
+				if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
+					// We found a tag, now find its kind
+
+					if (token.content[0].content[0].content === '</') {
+						// Closing tag
+						if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
+							// Pop matching opening tag
+							openedTags.pop();
+						}
+					} else {
+						if (token.content[token.content.length - 1].content === '/>') {
+							// Autoclosed tag, ignore
+						} else {
+							// Opening tag
+							openedTags.push({
+								tagName: stringifyToken(token.content[0].content[1]),
+								openedBraces: 0
+							});
+						}
+					}
+				} else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
+
+					// Here we might have entered a JSX context inside a tag
+					openedTags[openedTags.length - 1].openedBraces++;
+
+				} else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
+
+					// Here we might have left a JSX context inside a tag
+					openedTags[openedTags.length - 1].openedBraces--;
+
+				} else {
+					notTagNorBrace = true;
+				}
+			}
+			if (notTagNorBrace || typeof token === 'string') {
+				if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
+					// Here we are inside a tag, and not inside a JSX context.
+					// That's plain text: drop any tokens matched.
+					var plainText = stringifyToken(token);
+
+					// And merge text with adjacent text
+					if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
+						plainText += stringifyToken(tokens[i + 1]);
+						tokens.splice(i + 1, 1);
+					}
+					if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
+						plainText = stringifyToken(tokens[i - 1]) + plainText;
+						tokens.splice(i - 1, 1);
+						i--;
+					}
+
+					tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
+				}
+			}
+
+			if (token.content && typeof token.content !== 'string') {
+				walkTokens(token.content);
+			}
+		}
+	};
+
+	Prism.hooks.add('after-tokenize', function (env) {
+		if (env.language !== 'jsx' && env.language !== 'tsx') {
+			return;
+		}
+		walkTokens(env.tokens);
+	});
+
+}(Prism));
 
 (function (Prism) {
-  var multilineComment = /\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source;
-  for (var i = 0; i < 2; i++) {
-    // support 4 levels of nested comments
-    multilineComment = multilineComment.replace(/<self>/g, function () {
-      return multilineComment;
-    });
-  }
-  multilineComment = multilineComment.replace(/<self>/g, function () {
-    return /[^\s\S]/.source;
-  });
-
-  Prism.languages.rust = {
-    comment: [
-      {
-        pattern: RegExp(/(^|[^\\])/.source + multilineComment),
-        lookbehind: true,
-        greedy: true,
-      },
-      {
-        pattern: /(^|[^\\:])\/\/.*/,
-        lookbehind: true,
-        greedy: true,
-      },
-    ],
-    string: {
-      pattern: /b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,
-      greedy: true,
-    },
-    char: {
-      pattern:
-        /b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,
-      greedy: true,
-    },
-    attribute: {
-      pattern: /#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,
-      greedy: true,
-      alias: "attr-name",
-      inside: {
-        string: null, // see below
-      },
-    },
-
-    // Closure params should not be confused with bitwise OR |
-    "closure-params": {
-      pattern: /([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,
-      lookbehind: true,
-      greedy: true,
-      inside: {
-        "closure-punctuation": {
-          pattern: /^\||\|$/,
-          alias: "punctuation",
-        },
-        rest: null, // see below
-      },
-    },
-
-    "lifetime-annotation": {
-      pattern: /'\w+/,
-      alias: "symbol",
-    },
-
-    "fragment-specifier": {
-      pattern: /(\$\w+:)[a-z]+/,
-      lookbehind: true,
-      alias: "punctuation",
-    },
-    variable: /\$\w+/,
-
-    "function-definition": {
-      pattern: /(\bfn\s+)\w+/,
-      lookbehind: true,
-      alias: "function",
-    },
-    "type-definition": {
-      pattern: /(\b(?:enum|struct|trait|type|union)\s+)\w+/,
-      lookbehind: true,
-      alias: "class-name",
-    },
-    "module-declaration": [
-      {
-        pattern: /(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,
-        lookbehind: true,
-        alias: "namespace",
-      },
-      {
-        pattern:
-          /(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,
-        lookbehind: true,
-        alias: "namespace",
-        inside: {
-          punctuation: /::/,
-        },
-      },
-    ],
-    keyword: [
-      // https://github.com/rust-lang/reference/blob/master/src/keywords.md
-      /\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,
-      // primitives and str
-      // https://doc.rust-lang.org/stable/rust-by-example/primitives.html
-      /\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/,
-    ],
-
-    // functions can technically start with an upper-case letter, but this will introduce a lot of false positives
-    // and Rust's naming conventions recommend snake_case anyway.
-    // https://doc.rust-lang.org/1.0.0/style/style/naming/README.html
-    function: /\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,
-    macro: {
-      pattern: /\b\w+!/,
-      alias: "property",
-    },
-    constant: /\b[A-Z_][A-Z_\d]+\b/,
-    "class-name": /\b[A-Z]\w*\b/,
-
-    namespace: {
-      pattern: /(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,
-      inside: {
-        punctuation: /::/,
-      },
-    },
-
-    // Hex, oct, bin, dec numbers with visual separators and type suffix
-    number:
-      /\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,
-    boolean: /\b(?:false|true)\b/,
-    punctuation: /->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,
-    operator: /[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/,
-  };
-
-  Prism.languages.rust["closure-params"].inside.rest = Prism.languages.rust;
-  Prism.languages.rust["attribute"].inside["string"] =
-    Prism.languages.rust["string"];
-})(Prism);
-
-Prism.languages.scss = Prism.languages.extend("css", {
-  comment: {
-    pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,
-    lookbehind: true,
-  },
-  atrule: {
-    pattern: /@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,
-    inside: {
-      rule: /@[\w-]+/,
-      // See rest below
-    },
-  },
-  // url, compassified
-  url: /(?:[-a-z]+-)?url(?=\()/i,
-  // CSS selector regex is not appropriate for Sass
-  // since there can be lot more things (var, @ directive, nesting..)
-  // a selector must start at the end of a property or after a brace (end of other rules or nesting)
-  // it can contain some characters that aren't used for defining rules or end of selector, & (parent selector), or interpolated variable
-  // the end of a selector is found when there is no rules in it ( {} or {\s}) or if there is a property (because an interpolated var
-  // can "pass" as a selector- e.g: proper#{$erty})
-  // this one was hard to do, so please be careful if you edit this one :)
-  selector: {
-    // Initial look-ahead is used to prevent matching of blank selectors
-    pattern:
-      /(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,
-    inside: {
-      parent: {
-        pattern: /&/,
-        alias: "important",
-      },
-      placeholder: /%[-\w]+/,
-      variable: /\$[-\w]+|#\{\$[-\w]+\}/,
-    },
-  },
-  property: {
-    pattern: /(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,
-    inside: {
-      variable: /\$[-\w]+|#\{\$[-\w]+\}/,
-    },
-  },
+
+	var multilineComment = /\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source;
+	for (var i = 0; i < 2; i++) {
+		// support 4 levels of nested comments
+		multilineComment = multilineComment.replace(/<self>/g, function () { return multilineComment; });
+	}
+	multilineComment = multilineComment.replace(/<self>/g, function () { return /[^\s\S]/.source; });
+
+
+	Prism.languages.rust = {
+		'comment': [
+			{
+				pattern: RegExp(/(^|[^\\])/.source + multilineComment),
+				lookbehind: true,
+				greedy: true
+			},
+			{
+				pattern: /(^|[^\\:])\/\/.*/,
+				lookbehind: true,
+				greedy: true
+			}
+		],
+		'string': {
+			pattern: /b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,
+			greedy: true
+		},
+		'char': {
+			pattern: /b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,
+			greedy: true
+		},
+		'attribute': {
+			pattern: /#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,
+			greedy: true,
+			alias: 'attr-name',
+			inside: {
+				'string': null // see below
+			}
+		},
+
+		// Closure params should not be confused with bitwise OR |
+		'closure-params': {
+			pattern: /([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,
+			lookbehind: true,
+			greedy: true,
+			inside: {
+				'closure-punctuation': {
+					pattern: /^\||\|$/,
+					alias: 'punctuation'
+				},
+				rest: null // see below
+			}
+		},
+
+		'lifetime-annotation': {
+			pattern: /'\w+/,
+			alias: 'symbol'
+		},
+
+		'fragment-specifier': {
+			pattern: /(\$\w+:)[a-z]+/,
+			lookbehind: true,
+			alias: 'punctuation'
+		},
+		'variable': /\$\w+/,
+
+		'function-definition': {
+			pattern: /(\bfn\s+)\w+/,
+			lookbehind: true,
+			alias: 'function'
+		},
+		'type-definition': {
+			pattern: /(\b(?:enum|struct|trait|type|union)\s+)\w+/,
+			lookbehind: true,
+			alias: 'class-name'
+		},
+		'module-declaration': [
+			{
+				pattern: /(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,
+				lookbehind: true,
+				alias: 'namespace'
+			},
+			{
+				pattern: /(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,
+				lookbehind: true,
+				alias: 'namespace',
+				inside: {
+					'punctuation': /::/
+				}
+			}
+		],
+		'keyword': [
+			// https://github.com/rust-lang/reference/blob/master/src/keywords.md
+			/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,
+			// primitives and str
+			// https://doc.rust-lang.org/stable/rust-by-example/primitives.html
+			/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/
+		],
+
+		// functions can technically start with an upper-case letter, but this will introduce a lot of false positives
+		// and Rust's naming conventions recommend snake_case anyway.
+		// https://doc.rust-lang.org/1.0.0/style/style/naming/README.html
+		'function': /\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,
+		'macro': {
+			pattern: /\b\w+!/,
+			alias: 'property'
+		},
+		'constant': /\b[A-Z_][A-Z_\d]+\b/,
+		'class-name': /\b[A-Z]\w*\b/,
+
+		'namespace': {
+			pattern: /(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,
+			inside: {
+				'punctuation': /::/
+			}
+		},
+
+		// Hex, oct, bin, dec numbers with visual separators and type suffix
+		'number': /\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,
+		'boolean': /\b(?:false|true)\b/,
+		'punctuation': /->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,
+		'operator': /[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/
+	};
+
+	Prism.languages.rust['closure-params'].inside.rest = Prism.languages.rust;
+	Prism.languages.rust['attribute'].inside['string'] = Prism.languages.rust['string'];
+
+}(Prism));
+
+Prism.languages.scss = Prism.languages.extend('css', {
+	'comment': {
+		pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,
+		lookbehind: true
+	},
+	'atrule': {
+		pattern: /@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,
+		inside: {
+			'rule': /@[\w-]+/
+			// See rest below
+		}
+	},
+	// url, compassified
+	'url': /(?:[-a-z]+-)?url(?=\()/i,
+	// CSS selector regex is not appropriate for Sass
+	// since there can be lot more things (var, @ directive, nesting..)
+	// a selector must start at the end of a property or after a brace (end of other rules or nesting)
+	// it can contain some characters that aren't used for defining rules or end of selector, & (parent selector), or interpolated variable
+	// the end of a selector is found when there is no rules in it ( {} or {\s}) or if there is a property (because an interpolated var
+	// can "pass" as a selector- e.g: proper#{$erty})
+	// this one was hard to do, so please be careful if you edit this one :)
+	'selector': {
+		// Initial look-ahead is used to prevent matching of blank selectors
+		pattern: /(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,
+		inside: {
+			'parent': {
+				pattern: /&/,
+				alias: 'important'
+			},
+			'placeholder': /%[-\w]+/,
+			'variable': /\$[-\w]+|#\{\$[-\w]+\}/
+		}
+	},
+	'property': {
+		pattern: /(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,
+		inside: {
+			'variable': /\$[-\w]+|#\{\$[-\w]+\}/
+		}
+	}
 });
 
-Prism.languages.insertBefore("scss", "atrule", {
-  keyword: [
-    /@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,
-    {
-      pattern: /( )(?:from|through)(?= )/,
-      lookbehind: true,
-    },
-  ],
+Prism.languages.insertBefore('scss', 'atrule', {
+	'keyword': [
+		/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,
+		{
+			pattern: /( )(?:from|through)(?= )/,
+			lookbehind: true
+		}
+	]
 });
 
-Prism.languages.insertBefore("scss", "important", {
-  // var and interpolated vars
-  variable: /\$[-\w]+|#\{\$[-\w]+\}/,
+Prism.languages.insertBefore('scss', 'important', {
+	// var and interpolated vars
+	'variable': /\$[-\w]+|#\{\$[-\w]+\}/
 });
 
-Prism.languages.insertBefore("scss", "function", {
-  "module-modifier": {
-    pattern: /\b(?:as|hide|show|with)\b/i,
-    alias: "keyword",
-  },
-  placeholder: {
-    pattern: /%[-\w]+/,
-    alias: "selector",
-  },
-  statement: {
-    pattern: /\B!(?:default|optional)\b/i,
-    alias: "keyword",
-  },
-  boolean: /\b(?:false|true)\b/,
-  null: {
-    pattern: /\bnull\b/,
-    alias: "keyword",
-  },
-  operator: {
-    pattern: /(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,
-    lookbehind: true,
-  },
+Prism.languages.insertBefore('scss', 'function', {
+	'module-modifier': {
+		pattern: /\b(?:as|hide|show|with)\b/i,
+		alias: 'keyword'
+	},
+	'placeholder': {
+		pattern: /%[-\w]+/,
+		alias: 'selector'
+	},
+	'statement': {
+		pattern: /\B!(?:default|optional)\b/i,
+		alias: 'keyword'
+	},
+	'boolean': /\b(?:false|true)\b/,
+	'null': {
+		pattern: /\bnull\b/,
+		alias: 'keyword'
+	},
+	'operator': {
+		pattern: /(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,
+		lookbehind: true
+	}
 });
 
-Prism.languages.scss["atrule"].inside.rest = Prism.languages.scss;
-
-Prism.languages.scala = Prism.languages.extend("java", {
-  "triple-quoted-string": {
-    pattern: /"""[\s\S]*?"""/,
-    greedy: true,
-    alias: "string",
-  },
-  string: {
-    pattern: /("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,
-    greedy: true,
-  },
-  keyword:
-    /<-|=>|\b(?:abstract|case|catch|class|def|derives|do|else|enum|extends|extension|final|finally|for|forSome|given|if|implicit|import|infix|inline|lazy|match|new|null|object|opaque|open|override|package|private|protected|return|sealed|self|super|this|throw|trait|transparent|try|type|using|val|var|while|with|yield)\b/,
-  number:
-    /\b0x(?:[\da-f]*\.)?[\da-f]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e\d+)?[dfl]?/i,
-  builtin:
-    /\b(?:Any|AnyRef|AnyVal|Boolean|Byte|Char|Double|Float|Int|Long|Nothing|Short|String|Unit)\b/,
-  symbol: /'[^\d\s\\]\w*/,
+Prism.languages.scss['atrule'].inside.rest = Prism.languages.scss;
+
+Prism.languages.scala = Prism.languages.extend('java', {
+	'triple-quoted-string': {
+		pattern: /"""[\s\S]*?"""/,
+		greedy: true,
+		alias: 'string'
+	},
+	'string': {
+		pattern: /("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,
+		greedy: true
+	},
+	'keyword': /<-|=>|\b(?:abstract|case|catch|class|def|derives|do|else|enum|extends|extension|final|finally|for|forSome|given|if|implicit|import|infix|inline|lazy|match|new|null|object|opaque|open|override|package|private|protected|return|sealed|self|super|this|throw|trait|transparent|try|type|using|val|var|while|with|yield)\b/,
+	'number': /\b0x(?:[\da-f]*\.)?[\da-f]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e\d+)?[dfl]?/i,
+	'builtin': /\b(?:Any|AnyRef|AnyVal|Boolean|Byte|Char|Double|Float|Int|Long|Nothing|Short|String|Unit)\b/,
+	'symbol': /'[^\d\s\\]\w*/
 });
 
-Prism.languages.insertBefore("scala", "triple-quoted-string", {
-  "string-interpolation": {
-    pattern:
-      /\b[a-z]\w*(?:"""(?:[^$]|\$(?:[^{]|\{(?:[^{}]|\{[^{}]*\})*\}))*?"""|"(?:[^$"\r\n]|\$(?:[^{]|\{(?:[^{}]|\{[^{}]*\})*\}))*")/i,
-    greedy: true,
-    inside: {
-      id: {
-        pattern: /^\w+/,
-        greedy: true,
-        alias: "function",
-      },
-      escape: {
-        pattern: /\\\$"|\$[$"]/,
-        greedy: true,
-        alias: "symbol",
-      },
-      interpolation: {
-        pattern: /\$(?:\w+|\{(?:[^{}]|\{[^{}]*\})*\})/,
-        greedy: true,
-        inside: {
-          punctuation: /^\$\{?|\}$/,
-          expression: {
-            pattern: /[\s\S]+/,
-            inside: Prism.languages.scala,
-          },
-        },
-      },
-      string: /[\s\S]+/,
-    },
-  },
+Prism.languages.insertBefore('scala', 'triple-quoted-string', {
+	'string-interpolation': {
+		pattern: /\b[a-z]\w*(?:"""(?:[^$]|\$(?:[^{]|\{(?:[^{}]|\{[^{}]*\})*\}))*?"""|"(?:[^$"\r\n]|\$(?:[^{]|\{(?:[^{}]|\{[^{}]*\})*\}))*")/i,
+		greedy: true,
+		inside: {
+			'id': {
+				pattern: /^\w+/,
+				greedy: true,
+				alias: 'function'
+			},
+			'escape': {
+				pattern: /\\\$"|\$[$"]/,
+				greedy: true,
+				alias: 'symbol'
+			},
+			'interpolation': {
+				pattern: /\$(?:\w+|\{(?:[^{}]|\{[^{}]*\})*\})/,
+				greedy: true,
+				inside: {
+					'punctuation': /^\$\{?|\}$/,
+					'expression': {
+						pattern: /[\s\S]+/,
+						inside: Prism.languages.scala
+					}
+				}
+			},
+			'string': /[\s\S]+/
+		}
+	}
 });
 
-delete Prism.languages.scala["class-name"];
-delete Prism.languages.scala["function"];
-delete Prism.languages.scala["constant"];
+delete Prism.languages.scala['class-name'];
+delete Prism.languages.scala['function'];
+delete Prism.languages.scala['constant'];
 
 (function (Prism) {
-  // CAREFUL!
-  // The following patterns are concatenated, so the group referenced by a back reference is non-obvious!
-
-  var strings = [
-    // normal string
-    /"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/.source,
-    /'[^']*'/.source,
-    /\$'(?:[^'\\]|\\[\s\S])*'/.source,
-
-    // here doc
-    // 2 capturing groups
-    /<<-?\s*(["']?)(\w+)\1\s[\s\S]*?[\r\n]\2/.source,
-  ].join("|");
-
-  Prism.languages["shell-session"] = {
-    command: {
-      pattern: RegExp(
-        // user info
-        /^/.source +
-          "(?:" +
-          // <user> ":" ( <path> )?
-          (/[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+(?::[^\0-\x1F$#%*?"<>:;|]+)?/
-            .source +
-            "|" +
-            // <path>
-            // Since the path pattern is quite general, we will require it to start with a special character to
-            // prevent false positives.
-            /[/~.][^\0-\x1F$#%*?"<>@:;|]*/.source) +
-          ")?" +
-          // shell symbol
-          /[$#%](?=\s)/.source +
-          // bash command
-          /(?:[^\\\r\n \t'"<$]|[ \t](?:(?!#)|#.*$)|\\(?:[^\r]|\r\n?)|\$(?!')|<(?!<)|<<str>>)+/.source.replace(
-            /<<str>>/g,
-            function () {
-              return strings;
-            },
-          ),
-        "m",
-      ),
-      greedy: true,
-      inside: {
-        info: {
-          // foo@bar:~/files$ exit
-          // foo@bar$ exit
-          // ~/files$ exit
-          pattern: /^[^#$%]+/,
-          alias: "punctuation",
-          inside: {
-            user: /^[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+/,
-            punctuation: /:/,
-            path: /[\s\S]+/,
-          },
-        },
-        bash: {
-          pattern: /(^[$#%]\s*)\S[\s\S]*/,
-          lookbehind: true,
-          alias: "language-bash",
-          inside: Prism.languages.bash,
-        },
-        "shell-symbol": {
-          pattern: /^[$#%]/,
-          alias: "important",
-        },
-      },
-    },
-    output: /.(?:.*(?:[\r\n]|.$))*/,
-  };
-
-  Prism.languages["sh-session"] = Prism.languages["shellsession"] =
-    Prism.languages["shell-session"];
-})(Prism);
+
+	// CAREFUL!
+	// The following patterns are concatenated, so the group referenced by a back reference is non-obvious!
+
+	var strings = [
+		// normal string
+		/"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/.source,
+		/'[^']*'/.source,
+		/\$'(?:[^'\\]|\\[\s\S])*'/.source,
+
+		// here doc
+		// 2 capturing groups
+		/<<-?\s*(["']?)(\w+)\1\s[\s\S]*?[\r\n]\2/.source
+	].join('|');
+
+	Prism.languages['shell-session'] = {
+		'command': {
+			pattern: RegExp(
+				// user info
+				/^/.source +
+				'(?:' +
+				(
+					// <user> ":" ( <path> )?
+					/[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+(?::[^\0-\x1F$#%*?"<>:;|]+)?/.source +
+					'|' +
+					// <path>
+					// Since the path pattern is quite general, we will require it to start with a special character to
+					// prevent false positives.
+					/[/~.][^\0-\x1F$#%*?"<>@:;|]*/.source
+				) +
+				')?' +
+				// shell symbol
+				/[$#%](?=\s)/.source +
+				// bash command
+				/(?:[^\\\r\n \t'"<$]|[ \t](?:(?!#)|#.*$)|\\(?:[^\r]|\r\n?)|\$(?!')|<(?!<)|<<str>>)+/.source.replace(/<<str>>/g, function () { return strings; }),
+				'm'
+			),
+			greedy: true,
+			inside: {
+				'info': {
+					// foo@bar:~/files$ exit
+					// foo@bar$ exit
+					// ~/files$ exit
+					pattern: /^[^#$%]+/,
+					alias: 'punctuation',
+					inside: {
+						'user': /^[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+/,
+						'punctuation': /:/,
+						'path': /[\s\S]+/
+					}
+				},
+				'bash': {
+					pattern: /(^[$#%]\s*)\S[\s\S]*/,
+					lookbehind: true,
+					alias: 'language-bash',
+					inside: Prism.languages.bash
+				},
+				'shell-symbol': {
+					pattern: /^[$#%]/,
+					alias: 'important'
+				}
+			}
+		},
+		'output': /.(?:.*(?:[\r\n]|.$))*/
+	};
+
+	Prism.languages['sh-session'] = Prism.languages['shellsession'] = Prism.languages['shell-session'];
+
+}(Prism));
 
 Prism.languages.sql = {
-  comment: {
-    pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,
-    lookbehind: true,
-  },
-  variable: [
-    {
-      pattern: /@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,
-      greedy: true,
-    },
-    /@[\w.$]+/,
-  ],
-  string: {
-    pattern: /(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,
-    greedy: true,
-    lookbehind: true,
-  },
-  identifier: {
-    pattern: /(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,
-    greedy: true,
-    lookbehind: true,
-    inside: {
-      punctuation: /^`|`$/,
-    },
-  },
-  function:
-    /\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i, // Should we highlight user defined functions too?
-  keyword:
-    /\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,
-  boolean: /\b(?:FALSE|NULL|TRUE)\b/i,
-  number: /\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,
-  operator:
-    /[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,
-  punctuation: /[;[\]()`,.]/,
+	'comment': {
+		pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,
+		lookbehind: true
+	},
+	'variable': [
+		{
+			pattern: /@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,
+			greedy: true
+		},
+		/@[\w.$]+/
+	],
+	'string': {
+		pattern: /(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,
+		greedy: true,
+		lookbehind: true
+	},
+	'identifier': {
+		pattern: /(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,
+		greedy: true,
+		lookbehind: true,
+		inside: {
+			'punctuation': /^`|`$/
+		}
+	},
+	'function': /\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i, // Should we highlight user defined functions too?
+	'keyword': /\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,
+	'boolean': /\b(?:FALSE|NULL|TRUE)\b/i,
+	'number': /\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,
+	'operator': /[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,
+	'punctuation': /[;[\]()`,.]/
+};
+
+Prism.languages.tcl = {
+	'comment': {
+		pattern: /(^|[^\\])#.*/,
+		lookbehind: true
+	},
+	'string': {
+		pattern: /"(?:[^"\\\r\n]|\\(?:\r\n|[\s\S]))*"/,
+		greedy: true
+	},
+	'variable': [
+		{
+			pattern: /(\$)(?:::)?(?:[a-zA-Z0-9]+::)*\w+/,
+			lookbehind: true
+		},
+		{
+			pattern: /(\$)\{[^}]+\}/,
+			lookbehind: true
+		},
+		{
+			pattern: /(^[\t ]*set[ \t]+)(?:::)?(?:[a-zA-Z0-9]+::)*\w+/m,
+			lookbehind: true
+		}
+	],
+	'function': {
+		pattern: /(^[\t ]*proc[ \t]+)\S+/m,
+		lookbehind: true
+	},
+	'builtin': [
+		{
+			pattern: /(^[\t ]*)(?:break|class|continue|error|eval|exit|for|foreach|if|proc|return|switch|while)\b/m,
+			lookbehind: true
+		},
+		/\b(?:else|elseif)\b/
+	],
+	'scope': {
+		pattern: /(^[\t ]*)(?:global|upvar|variable)\b/m,
+		lookbehind: true,
+		alias: 'constant'
+	},
+	'keyword': {
+		pattern: /(^[\t ]*|\[)(?:Safe_Base|Tcl|after|append|apply|array|auto_(?:execok|import|load|mkindex|qualify|reset)|automkindex_old|bgerror|binary|catch|cd|chan|clock|close|concat|dde|dict|encoding|eof|exec|expr|fblocked|fconfigure|fcopy|file(?:event|name)?|flush|gets|glob|history|http|incr|info|interp|join|lappend|lassign|lindex|linsert|list|llength|load|lrange|lrepeat|lreplace|lreverse|lsearch|lset|lsort|math(?:func|op)|memory|msgcat|namespace|open|package|parray|pid|pkg_mkIndex|platform|puts|pwd|re_syntax|read|refchan|regexp|registry|regsub|rename|scan|seek|set|socket|source|split|string|subst|tcl(?:_endOfWord|_findLibrary|startOf(?:Next|Previous)Word|test|vars|wordBreak(?:After|Before))|tell|time|tm|trace|unknown|unload|unset|update|uplevel|vwait)\b/m,
+		lookbehind: true
+	},
+	'operator': /!=?|\*\*?|==|&&?|\|\|?|<[=<]?|>[=>]?|[-+~\/%?^]|\b(?:eq|in|ne|ni)\b/,
+	'punctuation': /[{}()\[\]]/
 };
 
 (function (Prism) {
-  Prism.languages.typescript = Prism.languages.extend("javascript", {
-    "class-name": {
-      pattern:
-        /(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,
-      lookbehind: true,
-      greedy: true,
-      inside: null, // see below
-    },
-    builtin:
-      /\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/,
-  });
-
-  // The keywords TypeScript adds to JavaScript
-  Prism.languages.typescript.keyword.push(
-    /\b(?:abstract|declare|is|keyof|readonly|require)\b/,
-    // keywords that have to be followed by an identifier
-    /\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,
-    // This is for `import type *, {}`
-    /\btype\b(?=\s*(?:[\{*]|$))/,
-  );
-
-  // doesn't work with TS because TS is too complex
-  delete Prism.languages.typescript["parameter"];
-  delete Prism.languages.typescript["literal-property"];
-
-  // a version of typescript specifically for highlighting types
-  var typeInside = Prism.languages.extend("typescript", {});
-  delete typeInside["class-name"];
-
-  Prism.languages.typescript["class-name"].inside = typeInside;
-
-  Prism.languages.insertBefore("typescript", "function", {
-    decorator: {
-      pattern: /@[$\w\xA0-\uFFFF]+/,
-      inside: {
-        at: {
-          pattern: /^@/,
-          alias: "operator",
-        },
-        function: /^[\s\S]+/,
-      },
-    },
-    "generic-function": {
-      // e.g. foo<T extends "bar" | "baz">( ...
-      pattern:
-        /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,
-      greedy: true,
-      inside: {
-        function: /^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,
-        generic: {
-          pattern: /<[\s\S]+/, // everything after the first <
-          alias: "class-name",
-          inside: typeInside,
-        },
-      },
-    },
-  });
-
-  Prism.languages.ts = Prism.languages.typescript;
-})(Prism);
+
+	Prism.languages.typescript = Prism.languages.extend('javascript', {
+		'class-name': {
+			pattern: /(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,
+			lookbehind: true,
+			greedy: true,
+			inside: null // see below
+		},
+		'builtin': /\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/,
+	});
+
+	// The keywords TypeScript adds to JavaScript
+	Prism.languages.typescript.keyword.push(
+		/\b(?:abstract|declare|is|keyof|readonly|require)\b/,
+		// keywords that have to be followed by an identifier
+		/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,
+		// This is for `import type *, {}`
+		/\btype\b(?=\s*(?:[\{*]|$))/
+	);
+
+	// doesn't work with TS because TS is too complex
+	delete Prism.languages.typescript['parameter'];
+	delete Prism.languages.typescript['literal-property'];
+
+	// a version of typescript specifically for highlighting types
+	var typeInside = Prism.languages.extend('typescript', {});
+	delete typeInside['class-name'];
+
+	Prism.languages.typescript['class-name'].inside = typeInside;
+
+	Prism.languages.insertBefore('typescript', 'function', {
+		'decorator': {
+			pattern: /@[$\w\xA0-\uFFFF]+/,
+			inside: {
+				'at': {
+					pattern: /^@/,
+					alias: 'operator'
+				},
+				'function': /^[\s\S]+/
+			}
+		},
+		'generic-function': {
+			// e.g. foo<T extends "bar" | "baz">( ...
+			pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,
+			greedy: true,
+			inside: {
+				'function': /^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,
+				'generic': {
+					pattern: /<[\s\S]+/, // everything after the first <
+					alias: 'class-name',
+					inside: typeInside
+				}
+			}
+		}
+	});
+
+	Prism.languages.ts = Prism.languages.typescript;
+
+}(Prism));
 
 (function (Prism) {
-  // https://yaml.org/spec/1.2/spec.html#c-ns-anchor-property
-  // https://yaml.org/spec/1.2/spec.html#c-ns-alias-node
-  var anchorOrAlias = /[*&][^\s[\]{},]+/;
-  // https://yaml.org/spec/1.2/spec.html#c-ns-tag-property
-  var tag =
-    /!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/;
-  // https://yaml.org/spec/1.2/spec.html#c-ns-properties(n,c)
-  var properties =
-    "(?:" +
-    tag.source +
-    "(?:[ \t]+" +
-    anchorOrAlias.source +
-    ")?|" +
-    anchorOrAlias.source +
-    "(?:[ \t]+" +
-    tag.source +
-    ")?)";
-  // https://yaml.org/spec/1.2/spec.html#ns-plain(n,c)
-  // This is a simplified version that doesn't support "#" and multiline keys
-  // All these long scarry character classes are simplified versions of YAML's characters
-  var plainKey =
-    /(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(
-      /<PLAIN>/g,
-      function () {
-        return /[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/
-          .source;
-      },
-    );
-  var string = /"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;
-
-  /**
-   *
-   * @param {string} value
-   * @param {string} [flags]
-   * @returns {RegExp}
-   */
-  function createValuePattern(value, flags) {
-    flags = (flags || "").replace(/m/g, "") + "m"; // add m flag
-    var pattern =
-      /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source
-        .replace(/<<prop>>/g, function () {
-          return properties;
-        })
-        .replace(/<<value>>/g, function () {
-          return value;
-        });
-    return RegExp(pattern, flags);
-  }
-
-  Prism.languages.yaml = {
-    scalar: {
-      pattern: RegExp(
-        /([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(
-          /<<prop>>/g,
-          function () {
-            return properties;
-          },
-        ),
-      ),
-      lookbehind: true,
-      alias: "string",
-    },
-    comment: /#.*/,
-    key: {
-      pattern: RegExp(
-        /((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source
-          .replace(/<<prop>>/g, function () {
-            return properties;
-          })
-          .replace(/<<key>>/g, function () {
-            return "(?:" + plainKey + "|" + string + ")";
-          }),
-      ),
-      lookbehind: true,
-      greedy: true,
-      alias: "atrule",
-    },
-    directive: {
-      pattern: /(^[ \t]*)%.+/m,
-      lookbehind: true,
-      alias: "important",
-    },
-    datetime: {
-      pattern: createValuePattern(
-        /\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/
-          .source,
-      ),
-      lookbehind: true,
-      alias: "number",
-    },
-    boolean: {
-      pattern: createValuePattern(/false|true/.source, "i"),
-      lookbehind: true,
-      alias: "important",
-    },
-    null: {
-      pattern: createValuePattern(/null|~/.source, "i"),
-      lookbehind: true,
-      alias: "important",
-    },
-    string: {
-      pattern: createValuePattern(string),
-      lookbehind: true,
-      greedy: true,
-    },
-    number: {
-      pattern: createValuePattern(
-        /[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/
-          .source,
-        "i",
-      ),
-      lookbehind: true,
-    },
-    tag: tag,
-    important: anchorOrAlias,
-    punctuation: /---|[:[\]{}\-,|>?]|\.\.\./,
-  };
-
-  Prism.languages.yml = Prism.languages.yaml;
-})(Prism);
+
+	// https://yaml.org/spec/1.2/spec.html#c-ns-anchor-property
+	// https://yaml.org/spec/1.2/spec.html#c-ns-alias-node
+	var anchorOrAlias = /[*&][^\s[\]{},]+/;
+	// https://yaml.org/spec/1.2/spec.html#c-ns-tag-property
+	var tag = /!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/;
+	// https://yaml.org/spec/1.2/spec.html#c-ns-properties(n,c)
+	var properties = '(?:' + tag.source + '(?:[ \t]+' + anchorOrAlias.source + ')?|'
+		+ anchorOrAlias.source + '(?:[ \t]+' + tag.source + ')?)';
+	// https://yaml.org/spec/1.2/spec.html#ns-plain(n,c)
+	// This is a simplified version that doesn't support "#" and multiline keys
+	// All these long scarry character classes are simplified versions of YAML's characters
+	var plainKey = /(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source
+		.replace(/<PLAIN>/g, function () { return /[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source; });
+	var string = /"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;
+
+	/**
+	 *
+	 * @param {string} value
+	 * @param {string} [flags]
+	 * @returns {RegExp}
+	 */
+	function createValuePattern(value, flags) {
+		flags = (flags || '').replace(/m/g, '') + 'm'; // add m flag
+		var pattern = /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source
+			.replace(/<<prop>>/g, function () { return properties; }).replace(/<<value>>/g, function () { return value; });
+		return RegExp(pattern, flags);
+	}
+
+	Prism.languages.yaml = {
+		'scalar': {
+			pattern: RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source
+				.replace(/<<prop>>/g, function () { return properties; })),
+			lookbehind: true,
+			alias: 'string'
+		},
+		'comment': /#.*/,
+		'key': {
+			pattern: RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source
+				.replace(/<<prop>>/g, function () { return properties; })
+				.replace(/<<key>>/g, function () { return '(?:' + plainKey + '|' + string + ')'; })),
+			lookbehind: true,
+			greedy: true,
+			alias: 'atrule'
+		},
+		'directive': {
+			pattern: /(^[ \t]*)%.+/m,
+			lookbehind: true,
+			alias: 'important'
+		},
+		'datetime': {
+			pattern: createValuePattern(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),
+			lookbehind: true,
+			alias: 'number'
+		},
+		'boolean': {
+			pattern: createValuePattern(/false|true/.source, 'i'),
+			lookbehind: true,
+			alias: 'important'
+		},
+		'null': {
+			pattern: createValuePattern(/null|~/.source, 'i'),
+			lookbehind: true,
+			alias: 'important'
+		},
+		'string': {
+			pattern: createValuePattern(string),
+			lookbehind: true,
+			greedy: true
+		},
+		'number': {
+			pattern: createValuePattern(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source, 'i'),
+			lookbehind: true
+		},
+		'tag': tag,
+		'important': anchorOrAlias,
+		'punctuation': /---|[:[\]{}\-,|>?]|\.\.\./
+	};
+
+	Prism.languages.yml = Prism.languages.yaml;
+
+}(Prism));
 
 (function (Prism) {
-  function literal(str) {
-    return function () {
-      return str;
-    };
-  }
-
-  var keyword =
-    /\b(?:align|allowzero|and|anyframe|anytype|asm|async|await|break|cancel|catch|comptime|const|continue|defer|else|enum|errdefer|error|export|extern|fn|for|if|inline|linksection|nakedcc|noalias|nosuspend|null|or|orelse|packed|promise|pub|resume|return|stdcallcc|struct|suspend|switch|test|threadlocal|try|undefined|union|unreachable|usingnamespace|var|volatile|while)\b/;
-
-  var IDENTIFIER = "\\b(?!" + keyword.source + ")(?!\\d)\\w+\\b";
-  var ALIGN = /align\s*\((?:[^()]|\([^()]*\))*\)/.source;
-  var PREFIX_TYPE_OP =
-    /(?:\?|\bpromise->|(?:\[[^[\]]*\]|\*(?!\*)|\*\*)(?:\s*<ALIGN>|\s*const\b|\s*volatile\b|\s*allowzero\b)*)/.source.replace(
-      /<ALIGN>/g,
-      literal(ALIGN),
-    );
-  var SUFFIX_EXPR =
-    /(?:\bpromise\b|(?:\berror\.)?<ID>(?:\.<ID>)*(?!\s+<ID>))/.source.replace(
-      /<ID>/g,
-      literal(IDENTIFIER),
-    );
-  var TYPE =
-    "(?!\\s)(?:!?\\s*(?:" + PREFIX_TYPE_OP + "\\s*)*" + SUFFIX_EXPR + ")+";
-
-  /*
-   * A simplified grammar for Zig compile time type literals:
-   *
-   * TypeExpr = ( "!"? PREFIX_TYPE_OP* SUFFIX_EXPR )+
-   *
-   * SUFFIX_EXPR = ( \b "promise" \b | ( \b "error" "." )? IDENTIFIER ( "." IDENTIFIER )* (?! \s+ IDENTIFIER ) )
-   *
-   * PREFIX_TYPE_OP = "?"
-   *                | \b "promise" "->"
-   *                | ( "[" [^\[\]]* "]" | "*" | "**" ) ( ALIGN | "const" \b | "volatile" \b | "allowzero" \b )*
-   *
-   * ALIGN = "align" "(" ( [^()] | "(" [^()]* ")" )* ")"
-   *
-   * IDENTIFIER = \b (?! KEYWORD ) [a-zA-Z_] \w* \b
-   *
-   */
-
-  Prism.languages.zig = {
-    comment: [
-      {
-        pattern: /\/\/[/!].*/,
-        alias: "doc-comment",
-      },
-      /\/{2}.*/,
-    ],
-    string: [
-      {
-        // "string" and c"string"
-        pattern: /(^|[^\\@])c?"(?:[^"\\\r\n]|\\.)*"/,
-        lookbehind: true,
-        greedy: true,
-      },
-      {
-        // multiline strings and c-strings
-        pattern: /([\r\n])([ \t]+c?\\{2}).*(?:(?:\r\n?|\n)\2.*)*/,
-        lookbehind: true,
-        greedy: true,
-      },
-    ],
-    char: {
-      // characters 'a', '\n', '\xFF', '\u{10FFFF}'
-      pattern:
-        /(^|[^\\])'(?:[^'\\\r\n]|[\uD800-\uDFFF]{2}|\\(?:.|x[a-fA-F\d]{2}|u\{[a-fA-F\d]{1,6}\}))'/,
-      lookbehind: true,
-      greedy: true,
-    },
-    builtin: /\B@(?!\d)\w+(?=\s*\()/,
-    label: {
-      pattern:
-        /(\b(?:break|continue)\s*:\s*)\w+\b|\b(?!\d)\w+\b(?=\s*:\s*(?:\{|while\b))/,
-      lookbehind: true,
-    },
-    "class-name": [
-      // const Foo = struct {};
-      /\b(?!\d)\w+(?=\s*=\s*(?:(?:extern|packed)\s+)?(?:enum|struct|union)\s*[({])/,
-      {
-        // const x: i32 = 9;
-        // var x: Bar;
-        // fn foo(x: bool, y: f32) void {}
-        pattern: RegExp(
-          /(:\s*)<TYPE>(?=\s*(?:<ALIGN>\s*)?[=;,)])|<TYPE>(?=\s*(?:<ALIGN>\s*)?\{)/.source
-            .replace(/<TYPE>/g, literal(TYPE))
-            .replace(/<ALIGN>/g, literal(ALIGN)),
-        ),
-        lookbehind: true,
-        inside: null, // see below
-      },
-      {
-        // extern fn foo(x: f64) f64; (optional alignment)
-        pattern: RegExp(
-          /(\)\s*)<TYPE>(?=\s*(?:<ALIGN>\s*)?;)/.source
-            .replace(/<TYPE>/g, literal(TYPE))
-            .replace(/<ALIGN>/g, literal(ALIGN)),
-        ),
-        lookbehind: true,
-        inside: null, // see below
-      },
-    ],
-    "builtin-type": {
-      pattern:
-        /\b(?:anyerror|bool|c_u?(?:int|long|longlong|short)|c_longdouble|c_void|comptime_(?:float|int)|f(?:16|32|64|128)|[iu](?:8|16|32|64|128|size)|noreturn|type|void)\b/,
-      alias: "keyword",
-    },
-    keyword: keyword,
-    function: /\b(?!\d)\w+(?=\s*\()/,
-    number:
-      /\b(?:0b[01]+|0o[0-7]+|0x[a-fA-F\d]+(?:\.[a-fA-F\d]*)?(?:[pP][+-]?[a-fA-F\d]+)?|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)\b/,
-    boolean: /\b(?:false|true)\b/,
-    operator:
-      /\.[*?]|\.{2,3}|[-=]>|\*\*|\+\+|\|\||(?:<<|>>|[-+*]%|[-+*/%^&|<>!=])=?|[?~]/,
-    punctuation: /[.:,;(){}[\]]/,
-  };
-
-  Prism.languages.zig["class-name"].forEach(function (obj) {
-    if (obj.inside === null) {
-      obj.inside = Prism.languages.zig;
-    }
-  });
-})(Prism);
+
+	function literal(str) {
+		return function () { return str; };
+	}
+
+	var keyword = /\b(?:align|allowzero|and|anyframe|anytype|asm|async|await|break|cancel|catch|comptime|const|continue|defer|else|enum|errdefer|error|export|extern|fn|for|if|inline|linksection|nakedcc|noalias|nosuspend|null|or|orelse|packed|promise|pub|resume|return|stdcallcc|struct|suspend|switch|test|threadlocal|try|undefined|union|unreachable|usingnamespace|var|volatile|while)\b/;
+
+	var IDENTIFIER = '\\b(?!' + keyword.source + ')(?!\\d)\\w+\\b';
+	var ALIGN = /align\s*\((?:[^()]|\([^()]*\))*\)/.source;
+	var PREFIX_TYPE_OP = /(?:\?|\bpromise->|(?:\[[^[\]]*\]|\*(?!\*)|\*\*)(?:\s*<ALIGN>|\s*const\b|\s*volatile\b|\s*allowzero\b)*)/.source.replace(/<ALIGN>/g, literal(ALIGN));
+	var SUFFIX_EXPR = /(?:\bpromise\b|(?:\berror\.)?<ID>(?:\.<ID>)*(?!\s+<ID>))/.source.replace(/<ID>/g, literal(IDENTIFIER));
+	var TYPE = '(?!\\s)(?:!?\\s*(?:' + PREFIX_TYPE_OP + '\\s*)*' + SUFFIX_EXPR + ')+';
+
+	/*
+	 * A simplified grammar for Zig compile time type literals:
+	 *
+	 * TypeExpr = ( "!"? PREFIX_TYPE_OP* SUFFIX_EXPR )+
+	 *
+	 * SUFFIX_EXPR = ( \b "promise" \b | ( \b "error" "." )? IDENTIFIER ( "." IDENTIFIER )* (?! \s+ IDENTIFIER ) )
+	 *
+	 * PREFIX_TYPE_OP = "?"
+	 *                | \b "promise" "->"
+	 *                | ( "[" [^\[\]]* "]" | "*" | "**" ) ( ALIGN | "const" \b | "volatile" \b | "allowzero" \b )*
+	 *
+	 * ALIGN = "align" "(" ( [^()] | "(" [^()]* ")" )* ")"
+	 *
+	 * IDENTIFIER = \b (?! KEYWORD ) [a-zA-Z_] \w* \b
+	 *
+	*/
+
+	Prism.languages.zig = {
+		'comment': [
+			{
+				pattern: /\/\/[/!].*/,
+				alias: 'doc-comment'
+			},
+			/\/{2}.*/
+		],
+		'string': [
+			{
+				// "string" and c"string"
+				pattern: /(^|[^\\@])c?"(?:[^"\\\r\n]|\\.)*"/,
+				lookbehind: true,
+				greedy: true
+			},
+			{
+				// multiline strings and c-strings
+				pattern: /([\r\n])([ \t]+c?\\{2}).*(?:(?:\r\n?|\n)\2.*)*/,
+				lookbehind: true,
+				greedy: true
+			}
+		],
+		'char': {
+			// characters 'a', '\n', '\xFF', '\u{10FFFF}'
+			pattern: /(^|[^\\])'(?:[^'\\\r\n]|[\uD800-\uDFFF]{2}|\\(?:.|x[a-fA-F\d]{2}|u\{[a-fA-F\d]{1,6}\}))'/,
+			lookbehind: true,
+			greedy: true
+		},
+		'builtin': /\B@(?!\d)\w+(?=\s*\()/,
+		'label': {
+			pattern: /(\b(?:break|continue)\s*:\s*)\w+\b|\b(?!\d)\w+\b(?=\s*:\s*(?:\{|while\b))/,
+			lookbehind: true
+		},
+		'class-name': [
+			// const Foo = struct {};
+			/\b(?!\d)\w+(?=\s*=\s*(?:(?:extern|packed)\s+)?(?:enum|struct|union)\s*[({])/,
+			{
+				// const x: i32 = 9;
+				// var x: Bar;
+				// fn foo(x: bool, y: f32) void {}
+				pattern: RegExp(/(:\s*)<TYPE>(?=\s*(?:<ALIGN>\s*)?[=;,)])|<TYPE>(?=\s*(?:<ALIGN>\s*)?\{)/.source.replace(/<TYPE>/g, literal(TYPE)).replace(/<ALIGN>/g, literal(ALIGN))),
+				lookbehind: true,
+				inside: null // see below
+			},
+			{
+				// extern fn foo(x: f64) f64; (optional alignment)
+				pattern: RegExp(/(\)\s*)<TYPE>(?=\s*(?:<ALIGN>\s*)?;)/.source.replace(/<TYPE>/g, literal(TYPE)).replace(/<ALIGN>/g, literal(ALIGN))),
+				lookbehind: true,
+				inside: null // see below
+			}
+		],
+		'builtin-type': {
+			pattern: /\b(?:anyerror|bool|c_u?(?:int|long|longlong|short)|c_longdouble|c_void|comptime_(?:float|int)|f(?:16|32|64|128)|[iu](?:8|16|32|64|128|size)|noreturn|type|void)\b/,
+			alias: 'keyword'
+		},
+		'keyword': keyword,
+		'function': /\b(?!\d)\w+(?=\s*\()/,
+		'number': /\b(?:0b[01]+|0o[0-7]+|0x[a-fA-F\d]+(?:\.[a-fA-F\d]*)?(?:[pP][+-]?[a-fA-F\d]+)?|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)\b/,
+		'boolean': /\b(?:false|true)\b/,
+		'operator': /\.[*?]|\.{2,3}|[-=]>|\*\*|\+\+|\|\||(?:<<|>>|[-+*]%|[-+*/%^&|<>!=])=?|[?~]/,
+		'punctuation': /[.:,;(){}[\]]/
+	};
+
+	Prism.languages.zig['class-name'].forEach(function (obj) {
+		if (obj.inside === null) {
+			obj.inside = Prism.languages.zig;
+		}
+	});
+
+}(Prism));
+
diff --git a/lib/docs/filters/tcllib/clean_html.rb b/lib/docs/filters/tcllib/clean_html.rb
index b61649b62e..7590c7ec0e 100644
--- a/lib/docs/filters/tcllib/clean_html.rb
+++ b/lib/docs/filters/tcllib/clean_html.rb
@@ -29,6 +29,10 @@ def call
           node.name = 'h2'
         end
 
+        css('pre').each do |node|
+          node['data-language'] = 'tcl'
+        end
+
         doc
       end
     end

From c0df2e732d376b19feb82a9c755d7c732392a7bd Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Mon, 14 Jul 2025 07:45:51 +0200
Subject: [PATCH 367/384] tcl_tk: reorder versions

---
 lib/docs/scrapers/tcl_tk.rb | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/docs/scrapers/tcl_tk.rb b/lib/docs/scrapers/tcl_tk.rb
index 8aa933c835..95a9cf86b4 100644
--- a/lib/docs/scrapers/tcl_tk.rb
+++ b/lib/docs/scrapers/tcl_tk.rb
@@ -27,15 +27,15 @@ class TclTk < UrlScraper
       Licensed under <a href="http://www.tcl-lang.org/software/tcltk/license.html">Tcl/Tk terms</a>
     HTML
 
-    version '8.6' do
+    version '9.0' do
       self.base_url = "https://www.tcl-lang.org/man/tcl#{self.version}/"
-      self.root_path = 'contents.htm'
-      self.release = '8.6.16'
+      self.release = '9.0.2'
     end
 
-    version '9.0' do
+    version '8.6' do
       self.base_url = "https://www.tcl-lang.org/man/tcl#{self.version}/"
-      self.release = '9.0.2'
+      self.root_path = 'contents.htm'
+      self.release = '8.6.16'
     end
 
     def get_latest_version(opts)

From 6b680d17621cb807e9a45639186cdb24ec4e8dc3 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Mon, 14 Jul 2025 07:47:58 +0200
Subject: [PATCH 368/384] tcl_tk: enable syntax highlighting

---
 lib/docs/filters/tcl_tk/clean_html.rb | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/docs/filters/tcl_tk/clean_html.rb b/lib/docs/filters/tcl_tk/clean_html.rb
index 5691c3f6fb..ab99f781f3 100644
--- a/lib/docs/filters/tcl_tk/clean_html.rb
+++ b/lib/docs/filters/tcl_tk/clean_html.rb
@@ -35,6 +35,10 @@ def call
           node.content = node.content.capitalize
         end
 
+        css('pre').each do |node|
+          node['data-language'] = 'tcl'
+        end
+
         doc
       end
     end

From b2e9f9a11287a01491ce3234ccb21fb5aa4a80a7 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 15 Jul 2025 22:56:07 +0000
Subject: [PATCH 369/384] chore(deps): update ruby/setup-ruby action to
 v1.246.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0955358272..952e66272c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
+      uses: ruby/setup-ruby@a4f838919020b587bb8dd4493e8881bb113d3be7 # v1.246.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 6bce275a66..381bead36b 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
+      uses: ruby/setup-ruby@a4f838919020b587bb8dd4493e8881bb113d3be7 # v1.246.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 89a56c13e9..fb29c7d563 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
+      uses: ruby/setup-ruby@a4f838919020b587bb8dd4493e8881bb113d3be7 # v1.246.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 61452296c16400e75d5155ba273b3a3e93605829 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 16 Jul 2025 01:39:27 +0000
Subject: [PATCH 370/384] chore(deps): update dependency ruby to v3.4.5

---
 .ruby-version     | 2 +-
 .tool-versions    | 2 +-
 Dockerfile        | 2 +-
 Dockerfile-alpine | 2 +-
 Gemfile           | 2 +-
 Gemfile.lock      | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.ruby-version b/.ruby-version
index f9892605c7..4f5e69734c 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.4.4
+3.4.5
diff --git a/.tool-versions b/.tool-versions
index ca745c6d6d..27a8619d7e 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1 @@
-ruby 3.4.4
+ruby 3.4.5
diff --git a/Dockerfile b/Dockerfile
index 2d8a9fee8a..4657cb6f30 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:3.4.4
+FROM ruby:3.4.5
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
 
diff --git a/Dockerfile-alpine b/Dockerfile-alpine
index 6af65c2eb5..1faf46d49a 100644
--- a/Dockerfile-alpine
+++ b/Dockerfile-alpine
@@ -1,4 +1,4 @@
-FROM ruby:3.4.4-alpine
+FROM ruby:3.4.5-alpine
 
 ENV LANG=C.UTF-8
 ENV ENABLE_SERVICE_WORKER=true
diff --git a/Gemfile b/Gemfile
index cbe55ccf8a..b4149986f5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,5 @@
 source 'https://rubygems.org'
-ruby '3.4.4'
+ruby '3.4.5'
 
 gem 'activesupport', require: false
 gem 'html-pipeline'
diff --git a/Gemfile.lock b/Gemfile.lock
index cd22f745b6..dd87335a96 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -191,7 +191,7 @@ DEPENDENCIES
   yajl-ruby
 
 RUBY VERSION
-   ruby 3.4.4p34
+   ruby 3.4.5p51
 
 BUNDLED WITH
    2.4.6

From e5457618af00a6fe2d9358fc5aa83b2aa958e457 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 17 Jul 2025 00:24:26 +0000
Subject: [PATCH 371/384] chore(deps): update ruby/setup-ruby action to
 v1.247.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 952e66272c..e1050f33a7 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a4f838919020b587bb8dd4493e8881bb113d3be7 # v1.246.0
+      uses: ruby/setup-ruby@472790540115ce5bd69d399a020189a8c87d641f # v1.247.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 381bead36b..326b7f0c4c 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a4f838919020b587bb8dd4493e8881bb113d3be7 # v1.246.0
+      uses: ruby/setup-ruby@472790540115ce5bd69d399a020189a8c87d641f # v1.247.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index fb29c7d563..1e286dab78 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a4f838919020b587bb8dd4493e8881bb113d3be7 # v1.246.0
+      uses: ruby/setup-ruby@472790540115ce5bd69d399a020189a8c87d641f # v1.247.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From de38a1e2eed88dd2c0892bdabf35f1a2be6d9f33 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 18 Jul 2025 22:45:33 +0000
Subject: [PATCH 372/384] chore(deps): update dependency thor to v1.4.0

---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index dd87335a96..cdf7725388 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -136,7 +136,7 @@ GEM
       daemons (~> 1.0, >= 1.0.9)
       eventmachine (~> 1.0, >= 1.0.4)
       rack (>= 1, < 3)
-    thor (1.3.2)
+    thor (1.4.0)
     tilt (2.6.0)
     tty-pager (0.14.0)
       strings (~> 0.2.0)

From 0fd47d5ab46b515de77842dec9d65febe5082e03 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 21 Jul 2025 04:27:45 +0000
Subject: [PATCH 373/384] chore(deps): update dependency nokogiri to v1.18.9

---
 Gemfile.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index cdf7725388..de67e1679a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -57,13 +57,13 @@ GEM
     io-console (0.8.0)
     logger (1.6.2)
     method_source (1.1.0)
-    mini_portile2 (2.8.8)
+    mini_portile2 (2.8.9)
     minitest (5.25.5)
     multi_json (1.15.0)
     mustermann (3.0.3)
       ruby2_keywords (~> 0.0.1)
     newrelic_rpm (8.16.0)
-    nokogiri (1.18.8)
+    nokogiri (1.18.9)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     options (2.3.2)

From a2f09f94d0f0639bbee4094bd63fb96e0ec1efb7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=20B=C3=B6rjesson?= <jon@spuun.se>
Date: Mon, 21 Jul 2025 11:35:22 +0200
Subject: [PATCH 374/384] Crystal 1.17.0

---
 lib/docs/scrapers/crystal.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/crystal.rb b/lib/docs/scrapers/crystal.rb
index 92bd4bcf29..fe58b165f1 100644
--- a/lib/docs/scrapers/crystal.rb
+++ b/lib/docs/scrapers/crystal.rb
@@ -2,7 +2,7 @@ module Docs
   class Crystal < UrlScraper
     include MultipleBaseUrls
     self.type = 'crystal'
-    self.release = '1.16.1'
+    self.release = '1.17.0'
     self.base_urls = [
       "https://crystal-lang.org/api/#{release}/",
       "https://crystal-lang.org/reference/#{release[0..2]}/",

From 9384aba66cd501c2a4eb292307294e737635352c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 21 Jul 2025 23:09:39 +0000
Subject: [PATCH 375/384] chore(deps): update ruby/setup-ruby action to
 v1.248.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e1050f33a7..43c110e595 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@472790540115ce5bd69d399a020189a8c87d641f # v1.247.0
+      uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 326b7f0c4c..9916aa02c5 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@472790540115ce5bd69d399a020189a8c87d641f # v1.247.0
+      uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1e286dab78..ca20cf5c15 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@472790540115ce5bd69d399a020189a8c87d641f # v1.247.0
+      uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 43f8f98990c547b80f3f62761f980eed7701e114 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 24 Jul 2025 20:50:12 +0000
Subject: [PATCH 376/384] chore(deps): update ruby/setup-ruby action to
 v1.249.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 43c110e595..600415cc52 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+      uses: ruby/setup-ruby@65937904bcddfb93f8130882d9afa8597c45f3b5 # v1.249.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 9916aa02c5..d1dfd72ff9 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+      uses: ruby/setup-ruby@65937904bcddfb93f8130882d9afa8597c45f3b5 # v1.249.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ca20cf5c15..a0374ac285 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0
+      uses: ruby/setup-ruby@65937904bcddfb93f8130882d9afa8597c45f3b5 # v1.249.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 77d747dff7ed995a8b67b465a955f800c799b35d Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 25 Jul 2025 20:31:57 +0000
Subject: [PATCH 377/384] chore(deps): update ruby/setup-ruby action to
 v1.252.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 600415cc52..a127b4ebfa 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@65937904bcddfb93f8130882d9afa8597c45f3b5 # v1.249.0
+      uses: ruby/setup-ruby@0ecad18fe538ef70f6b82773daecc6af1a7fe58a # v1.252.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index d1dfd72ff9..e5e8509174 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@65937904bcddfb93f8130882d9afa8597c45f3b5 # v1.249.0
+      uses: ruby/setup-ruby@0ecad18fe538ef70f6b82773daecc6af1a7fe58a # v1.252.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a0374ac285..21747eb145 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@65937904bcddfb93f8130882d9afa8597c45f3b5 # v1.249.0
+      uses: ruby/setup-ruby@0ecad18fe538ef70f6b82773daecc6af1a7fe58a # v1.252.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From af9a19a949bad105a4e63646ba92b57e2f11e071 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 26 Jul 2025 10:09:28 +0000
Subject: [PATCH 378/384] chore(deps): update ruby/setup-ruby action to
 v1.253.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a127b4ebfa..bbd0d24a92 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@0ecad18fe538ef70f6b82773daecc6af1a7fe58a # v1.252.0
+      uses: ruby/setup-ruby@bb6434c747fa7022e12fa1cae2a0951fcffcff26 # v1.253.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index e5e8509174..64e6610002 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@0ecad18fe538ef70f6b82773daecc6af1a7fe58a # v1.252.0
+      uses: ruby/setup-ruby@bb6434c747fa7022e12fa1cae2a0951fcffcff26 # v1.253.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 21747eb145..0f55762d9d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@0ecad18fe538ef70f6b82773daecc6af1a7fe58a # v1.252.0
+      uses: ruby/setup-ruby@bb6434c747fa7022e12fa1cae2a0951fcffcff26 # v1.253.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 9b010af737fbeb910fd3bba5dd7207acd26521b2 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 29 Jul 2025 13:51:00 +0200
Subject: [PATCH 379/384] Update OpenLayers documentation (10.6.1)

---
 lib/docs/scrapers/openlayers.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/openlayers.rb b/lib/docs/scrapers/openlayers.rb
index 1c957fbde1..b9bf9d347a 100644
--- a/lib/docs/scrapers/openlayers.rb
+++ b/lib/docs/scrapers/openlayers.rb
@@ -3,7 +3,7 @@ class Openlayers < UrlScraper
     self.name = 'OpenLayers'
     self.type = 'openlayers'
     self.slug = 'openlayers'
-    self.release = '10.4.0'
+    self.release = '10.6.1'
     self.base_url = "https://openlayers.org/en/latest/apidoc/"
     self.links = {
       home: 'https://openlayers.org/',

From 26099b76cb4fcd0c1f57445f9e90fad07b4c3c50 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 29 Jul 2025 19:57:42 +0200
Subject: [PATCH 380/384] Update Vue documentation (3.5.18)

---
 lib/docs/scrapers/vue.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vue.rb b/lib/docs/scrapers/vue.rb
index b0649eb31f..158a546b19 100644
--- a/lib/docs/scrapers/vue.rb
+++ b/lib/docs/scrapers/vue.rb
@@ -19,7 +19,7 @@ class Vue < UrlScraper
     HTML
 
     version '3' do
-      self.release = '3.5.13'
+      self.release = '3.5.18'
       self.base_url = 'https://vuejs.org/'
       self.initial_paths = %w(guide/introduction.html)
       html_filters.push 'vue/entries_v3', 'vue/clean_html'

From e1488bf828a443274d8ae4c5feb746189d811529 Mon Sep 17 00:00:00 2001
From: Simon Legner <Simon.Legner@gmail.com>
Date: Tue, 29 Jul 2025 20:04:52 +0200
Subject: [PATCH 381/384] Update VueUse documentation (13.6.0)

---
 lib/docs/scrapers/vueuse.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/docs/scrapers/vueuse.rb b/lib/docs/scrapers/vueuse.rb
index 40956fbb8f..31e1a8fb75 100644
--- a/lib/docs/scrapers/vueuse.rb
+++ b/lib/docs/scrapers/vueuse.rb
@@ -22,7 +22,7 @@ class Vueuse < UrlScraper
       Licensed under the MIT License.
     HTML
 
-    self.release = '13.1.0'
+    self.release = '13.6.0'
     self.base_url = 'https://vueuse.org/'
     self.initial_paths = %w(functions.html)
     html_filters.push 'vueuse/entries', 'vite/clean_html', 'vueuse/clean_html'

From e4cef74fcb3d1d70f3512d6ef7483e9d1f82c85c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 30 Jul 2025 00:43:12 +0000
Subject: [PATCH 382/384] chore(deps): update ruby/setup-ruby action to
 v1.254.0

---
 .github/workflows/build.yml               | 2 +-
 .github/workflows/schedule-doc-report.yml | 2 +-
 .github/workflows/test.yml                | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index bbd0d24a92..cb88838a4d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bb6434c747fa7022e12fa1cae2a0951fcffcff26 # v1.253.0
+      uses: ruby/setup-ruby@2a7b30092b0caf9c046252510f9273b4875f3db9 # v1.254.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests
diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml
index 64e6610002..3e48c51a83 100644
--- a/.github/workflows/schedule-doc-report.yml
+++ b/.github/workflows/schedule-doc-report.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bb6434c747fa7022e12fa1cae2a0951fcffcff26 # v1.253.0
+      uses: ruby/setup-ruby@2a7b30092b0caf9c046252510f9273b4875f3db9 # v1.254.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Generate report
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 0f55762d9d..dc405a2d05 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
     - name: Set up Ruby
-      uses: ruby/setup-ruby@bb6434c747fa7022e12fa1cae2a0951fcffcff26 # v1.253.0
+      uses: ruby/setup-ruby@2a7b30092b0caf9c046252510f9273b4875f3db9 # v1.254.0
       with:
         bundler-cache: true # runs 'bundle install' and caches installed gems automatically
     - name: Run tests

From 410cc7f38e8ab373c25622cd63caff5e69bbb64c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 1 Aug 2025 12:43:52 +0000
Subject: [PATCH 383/384] chore(deps): update docker/metadata-action digest to
 c1e5197

---
 .github/workflows/docker-build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index 9651a50c99..5326ce299e 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -37,7 +37,7 @@ jobs:
 
       - name: Extract metadata for Docker
         id: meta
-        uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
+        uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5
         with:
           images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
           tags: |

From 37fd89f0b70edabda45cde89cd751b2a609f21cb Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 4 Aug 2025 14:52:51 +0000
Subject: [PATCH 384/384] chore(deps): update docker/login-action digest to
 184bdaa

---
 .github/workflows/docker-build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index 5326ce299e..3f0f95f5ed 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -29,7 +29,7 @@ jobs:
           persist-credentials: false
 
       - name: Log in to the Container registry
-        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
+        uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3
         with:
           registry: ${{ env.REGISTRY }}
           username: ${{ github.actor }}
