Commit Graph

369 Commits

Author SHA1 Message Date
Tim van der Lippe
8e0c2d5750 Implement WindowOrWorkerGlobalScope::reportError (#40654)
This web API is alternative API to `throw e`, which is why we can reuse
a lot of the existing machinery.

The one testcase that isn't passing yet is because it reports an empty
`TypeError`. The current logic in `ErrorInfo` only retrieves the message
data, but doesn't include the type of the exception. For that, we need
to use `(*report)._base.errorNumber` and map that back to the original
type codes. However, deferring that to a follow-up as that requires some
more work in mozjs.

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
2025-11-16 09:30:16 +00:00
Sam
fa12f7a5e5 script: Add cx_no_gc/cx/realm codegen option and demostrate them (#40582)
Companion to https://github.com/servo/mozjs/pull/650

We added 3 new options to bindings.conf, each more powerful then the
previous one, so one should use the least powerful as possible to keep
things flexible:
1 `cx_no_gc` prepends argument `&JSContext`, which allows creating NoGC
tokens and using functions that do not trigger GC.
2. `cx` prepends argument `&mut JSContext`, which allows everything that
previous one allows, but it also allows calling GC triggering functions.
3. `realm` prepends argument `&mut CurrentRealm`, which can be deref_mut
to `&mut JSContext` (so it can do everything that previous can), but it
also ensures that there is current entered realm, which can be used for
creation of InRealm.

next steps: #40600 

reviewable per commit

Testing: It's just refactoring
try run: https://github.com/sagudev/servo/actions/runs/19287700927

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
2025-11-16 04:53:54 +00:00
Kingsley Yung
1ec01cc25d script: Housekeeping WebIDL dictionaries of WebCrypto API (#40652)
Housekeeping of WebIDL dictionaries of WebCrypto API, including:

- Add/Fix spec links in `SubtleCrypto.webidl` and `CryptoKey.webidl`.
- Sort dictionaries in `subtlecrypto.webidl` based on the spec.
- Sort the `subtle` structs in `subtlecrypto.rs`, based on the spec.
- Reduce unneeded visibility of those `subtle` structs.

Testing: No behavioral change. Existing tests suffice.

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2025-11-15 10:17:19 +00:00
Tim van der Lippe
c782da762b Implement protocol handler web API's behind flag (#40616)
This implements the web-facing API's behind a flag, where we further
design the embedding API in a
follow-up PR.

It passes all relevant WPT tests, since the HTML
specification leaves it up to user agents to
determine when to process these protocol handlers.

It also uses `once_cell` to lazily construct the
regex, which is what the CSP crate also uses for
its regexes [1].

Part of #40615

[1]:
db8f2e97fe/src/lib.rs (L1550-L1569)

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
2025-11-14 12:53:33 +00:00
Taym Haddadi
4658fc333a Add AbortSignal garbage collection (#40508)
Add AbortSignal garbage collection

Testing: all AbortSignal should pass.

Fixes: #40481

---------

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
2025-11-13 10:58:55 +00:00
Andrei Volykhin
59526928af html: Remove canGC argument from <media> internal seek method (#40587)
The `seek` method isn't explicitly exposed in the API, but is called
from various places (`currentTime`, `fastSeek`, by the `media metadata`
event) and doesn't itself create new DOM objects, so the `canGC`
argument can be omitted.

It was previously required because calling the `Seekable` method creates
a new `TimeRanges` object, but it will now be replaced by the internal
`seekable` method to avoid interaction with the JavaScript engine (and
potential garbage collector).

The `earlyest possible position` method has been changed to match the
specification and use `seekable` instead of `played`. See
https://html.spec.whatwg.org/multipage/#earliest-possible-position

Testing: No expected changes in tests

Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
2025-11-12 18:44:15 +00:00
austinwillis
5896cfd936 script: Add message to HierarchyRequestError (#40366)
Adds an optional error message to HierarchyRequestError

Testing: refactor
Fixes: one item in #39053

---------

Signed-off-by: Austin Willis <austinwillis8@gmail.com>
2025-11-12 07:34:47 +00:00
Kingsley Yung
a094a0bbbc script: Implement verify operation of ECDSA (#40557)
Continue on adding ECDSA support to WebCrypto API. This patch implements
verify operation of ECDSA, using ECDSA implementation from the crates
`ecdsa` for the operation, `p256`, `p384`, `p521`, and `elliptic_curve`
for the key, and `sha1`, `sha2` and `digest` for digesting messages.

Testing: Pass some WPT tests that were expected to fail.
Fixes: Part of #39060

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2025-11-11 09:51:26 +00:00
Oriol Brufau
ffd74b9a1c deps: De-duplicate phf (#40555)
Other than upgrading phf, phf_codegen and phf_shared to 0.13, this also
upgrades html5ever, markup5ever and xml5ever to 0.36, string_cache to
0.9, and Stylo to https://github.com/servo/stylo/pull/266.

Testing: Not needed, no behavior change
Fixes: #40533

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-11-11 09:15:29 +00:00
Rocketjumper
9c05abe5f3 Fixed codegen to prevent double declaration of -webkit- prefixed CSS properties (#40549)
Removed the following on `script_bindings/codegen/run.py`:

```
# https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-webkit-cased-attribute
    if property_name.startswith("-webkit-"):
        yield "".join(camel_case(property_name, True))
```
Credits to @jdm !


Fixes: issue #40545

---------

Signed-off-by: Richard Tjokroutomo <richard.tjokro2@gmail.com>
2025-11-11 03:24:06 +00:00
webbeef
29bfb3a7b1 script: improve cookie processing of control characters (#40544)
This implements character set restrictions both for the DOM API and when
getting cookies from http/ws headers. This is a local workaround for
https://github.com/rwf2/cookie-rs/issues/243

We still fail some tests because hyper errors out when parsing headers
with %x1 characters.

This patch also makes a minor change to
'ServoCookie::from_cookie_string()' to avoid some string cloning when
possible.

Testing: wpt tests expectations are updated

Signed-off-by: webbeef <me@webbeef.org>
2025-11-11 00:23:03 +00:00
Narfinger
d8c46f0b15 script_bindings: Small USVString cleanup (#40537)
Some methods for USVString were not needed as they could lead to
inefficient usage
(like in CookieStoreMethod) it is better to remove them. Fixed two
methods that take the String
directly instead of copying it.

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>

Testing: No testing necessary as the functionality stays the same.

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
2025-11-10 13:45:56 +00:00
Taym Haddadi
28dd9f9749 Implement read looping using a read request following the spec (#39510)
Implement read looping using a read request following the spec.

Testing:  current wpt test should pass.
Fixes: #39482

---------

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
2025-11-09 22:05:12 +00:00
Excitable Snowball
a5c3cc3b4e script: Use InputEvent for input events (#39989)
Use `InputEvent` for text input and set appropriate values for the
`composed`, `data`, `isComposing`, and `inputType` attributes. Use a
placeholder for `dataTransfer` attribute and `getTargetRanges` function,
as they are only applicable to contenteditable, which isn't implemented.

Testing: I added two tests under `tests/wpt/mozilla/tests/input-events`
based on the similarly named ones for contenteditable under
`tests/wpt/tests/input-events`.
Fixes: https://github.com/servo/servo/issues/36398

---------

Signed-off-by: Excitable Snowball <excitablesnowball@gmail.com>
2025-11-08 23:04:03 +00:00
Shubham Gupta
71196c02ea Add basic IDL implementation for LargestContentfulPaint (#39714)
Add basic `IDL` implementation for `LargestContentfulPaint`

Testing: Tested locally
Fixes: N/A

<img width="800" height="210" alt="Screenshot from 2025-11-06 12-56-37"
src="https://github.com/user-attachments/assets/af453b8d-7605-4300-8c87-c2574feff81f"
/>

---------

Signed-off-by: Shubham Gupta <shubham.gupta@chromium.org>
2025-11-07 02:56:30 +00:00
WaterWhisperer
401165f154 script: Add message to IndexSizeError (#40463)
Adding an optional message to be attached to a IndexSizeError.

The enum definition of IndexSize is now `IndexSize(Option<String>)`.
Future PRs should probably add more appropriate messages to some of the
`IndexSize(None)`s.

Testing: Just a refactor
Fixes: Partially #39053

Signed-off-by: WaterWhisperer <waterwhisperer24@qq.com>
2025-11-07 01:08:00 +00:00
WaterWhisperer
241bff962d Change some #[allow]s to #[expect]s (#40458)
Removes some unneeded lints.

Testing: Refactor
Part of: #40383

Signed-off-by: WaterWhisperer <waterwhisperer24@qq.com>
2025-11-06 12:31:48 +00:00
Luke Warlow
e3c4655463 Partially implement dialog.showModal() (#40405)
Partially implement dialog.showModal()

Follow-ups will be needed to further implement proper dialog
functionality but this makes a good start.

Testing: Existing WPTs cover this.

---------

Signed-off-by: Luke Warlow <lwarlow@igalia.com>
2025-11-05 15:03:13 +00:00
WaterWhisperer
a90dff6919 script/layout: Implement Element.currentCSSZoom attribute (#40304)
Implements the `currentCSSZoom` readonly attribute on the Element
interface as
[spec](https://drafts.csswg.org/cssom-view/#dom-element-currentcsszoom).
- Adds a new layout query (`CurrentCSSZoomQuery`) that traverses from
the target element up through its ancestors
- Accumulates the product of all `zoom` CSS property values to compute
the effective zoom
- Returns 1.0 for elements that are not being rendered (display: none or
no layout data)

Testing: Updated WPT (removed 4 FAIL expectations from
`idlharness.html.ini`). Behavior tests in Element-currentCSSZoom.html
remain as expected FAIL because the underlying CSS `zoom` property
implementation in Servo does not yet apply zoom values to layout (the
zoom property is parsed but computed values remain 1.0).
Fixes: #40256

Signed-off-by: WaterWhisperer <waterwhisperer24@qq.com>
2025-11-05 14:25:53 +00:00
Kingsley Yung
ffe9c45b29 script: Implement derive bits operation of ECDH (#40333)
Finish adding ECDH support to WebCrypto API. This patch implements
derive bits operation of ECDH.

Testing: Pass some WPT tests that were expected to fail.
Fixes: Part of #39060

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2025-11-05 04:29:03 +00:00
Simon Wülker
46e6d072b7 script: Enforce exclusivity between <details> elements in the same tree (#40314)
Within the same tree, only one `<details>` element with the same name
may be open at a time. Before this change, this invariant was not
enforced.

I've added a `HashMap` to `Document` and `ShadowRoot` which maps from a
name to the a list of details elements with the same name. This map
allows us to find conflicting details elements without having to
traverse the whole tree. Of course this only works when the tree is a
document tree or a shadow tree, so we still have to fall back to
`traverse_preorder` in some cases (which I believe to be uncommon).

This is ready for review, but I'd like to wait until
https://github.com/servo/servo/pull/40271 is merged to not cause
unnecessary merge conflicts.

Testing: New web platform tests start to pass

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
2025-11-04 21:54:21 +00:00
Taym Haddadi
6ec242580c Add CanGc argument to SafeFromJSValConvertible::safe_from_jsval (#40404)
Add CanGc argument to SafeFromJSValConvertible::safe_from_jsval
Fixes: #40392

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
2025-11-04 20:43:59 +00:00
Narfinger
95c8b4244c Script: Efficient DOMString methods for as_bytes, eq_ascii, is_ascii, to_jsval (#40283)
This implements efficient methods for as_bytes, eq_ascii, is_ascii and
to_jsval.
Tests were added for as_bytes. Additionally, BytesView now has an
internal type to make sure nobody can construct it.


Testing: New unit tests were added and some old ones covered the new
functions.

---------

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
2025-11-03 17:28:35 +00:00
Luke Warlow
8ca4ecba02 script: Implement ToggleEvent and use for <details> element (#40271)
Implement ToggleEvent and use for details element

Testing: Covered by existing WPTs

Signed-off-by: Luke Warlow <lwarlow@igalia.com>
2025-11-02 18:20:18 +00:00
Kingsley Yung
0ffc97ee8e script: Implement generate key operation of ECDH (#40305)
Continue on adding ECDH support to WebCrypto API. This patch implements
generate key operation of ECDH.

Testing:
- Pass some WPT tests that were expected to fail.
- Some FAIL expectations are added. They require not-yet-implemented
"derive bits" operation of ECDH. WPT skipped them when "generate key"
operation for ECDH were not yet implemented.

Fixes: Part of #39060

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2025-10-31 13:10:02 +00:00
Sam
53d8c59e77 cargo: Bump Rust to 1.91 (#39471)
Rust 1.90 uses lld by default on linux, which should improve link time
and memory usage (I personally override ld with lld globally). And
because of miscompilations we observed on 1.90 we need to skip to 1.91.

Testing: Existing tests.
try run: https://github.com/sagudev/servo/actions/runs/18951980580

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
2025-10-30 21:14:10 +00:00
Kingsley Yung
8494b565a4 script: Implement import key operation for ECDH (#40253)
Implement import key operation for ECDH, using cryptographic calculation
implementation from the crates `p256`, `p384` and `p521`.

Testing:
- Pass some WPT tests that were expected to fail.
- Some FAIL expectations are added. They are related to the
not-yet-implemented "derive bits" operation of ECDH. WPT skipped them
when "import key" operation for ECDH were not yet implemented.

Fixes: Part of #39060

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2025-10-30 12:38:58 +00:00
Narfinger
22f4bd7971 Script: Use the correct constructor for DOMString to be lazy (#40263)
Somewhere in the transition to SafeJSContext, I did not merge correctly
and used the DOMString::from_String method instead of the
DOMString::from_js_string method, hence, defeating the lazyness.
This fixes this.

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>

Testing: Compiling and the function was enabled on a local branch
earlier.

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
2025-10-29 14:10:49 +00:00
Luke Warlow
df7895b80a Implement Document.parseHTMLUnsafe (#40246)
Implement `Document.parseHTMLUnsafe`

Testing: Covered by existing WPTs, expectations have been updated.
Fixes: #40245

---------

Signed-off-by: Luke Warlow <lwarlow@igalia.com>
2025-10-28 21:58:35 +00:00
Narfinger
aac7d9006e Script: Implement more efficient methods on DOMString Part2 (#39925)
This implements the following methods in a more efficient way using the
Latin1 representation:
- starts_with,
- to_ascii_lowercase,
- contains_html_space_characters,
- is_ascii_lowercase,
- PartialEq<str>, PartialEq<String>, PartialEq<DOMString>,
- Atom::from, LocalName::from, NameSpace::from
- Removed find which was not used.

All of these methods have new tests included.

---------

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
2025-10-28 19:25:35 +00:00
Taym Haddadi
b256914f08 AbortSignal: mark throwIfAborted as [Throws] (#40224)
AbortSignal: mark throwIfAborted as [Throws]

Testing: more AbortSignal passing.
part of #36936

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
2025-10-27 21:43:14 +00:00
Simon Wülker
f9f2a132ab script: Enable xpath by default (#40212)
Fixes: #34527

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
2025-10-27 19:24:22 +00:00
Kingsley Yung
e061e5c1b9 script: Implement Compression API (#39658)
The patch implements Compression (https://compression.spec.whatwg.org/)
with the compression and decompression provided by the `flate2` crate
(https://crates.io/crates/flate2).

`flate2` supports several different backends, controlled through the
crate's features. By default, it uses `miniz_oxide`
(https://crates.io/crates/miniz_oxide).

`flate2` provides three modules `read`, `write` and `bufread` which work
on instances of the `std::io::Read`, `std::io::Write` and
`std::io::Bufread` traits, respectively. The `write` module is chosen in
the patch since it matches the streaming model in the specification.

Testing: Enable WPT for Compression API, and introduce WPT expectation.

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2025-10-27 08:21:35 +00:00
Yerkebulan Tulibergenov
c2f6a1b89d add CanGc as argument to methods in HTMLImageElement (#40177)
add CanGc as argument to methods in HTMLImageElement

Testing: These changes do not require tests because they are a refactor.
Addresses part of https://github.com/servo/servo/issues/34573

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-27 00:06:32 +00:00
Tim van der Lippe
aad08bf2a6 Properly initialize related_target in UI events (#40182)
UI events can specify `relatedTarget` themselves. These were correctly
initialized, but this wasn't the case for the base event they extend.
Therefore, we need to initialize the event `relatedTarget` and only
store this information once.

This fixes several `shadow-dom/` tests, which were using these UI events
to test behavior.

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
2025-10-26 11:36:36 +00:00
Yerkebulan Tulibergenov
daf4dd5d99 script: Add an implementation of DedicatedWorkerGlobalScope.name and DedicatedWorkerGlobalScope.onmessageerror (#40156)
add `DedicatedWorkerGlobalScope.Name` and
`DedicatedWorkerGlobalScope.onmessageerror`

Closes https://github.com/servo/servo/issues/40114

---------

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-26 08:27:09 +00:00
Yerkebulan Tulibergenov
1f6c4f0180 add CanGc as argument to methods in HTMLMediaElement (#40179)
add CanGc as argument to methods in HTMLMediaElement

Testing: These changes do not require tests because they are a refactor.
Addresses part of https://github.com/servo/servo/issues/34573

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-26 07:48:57 +00:00
Yerkebulan Tulibergenov
80aa9c45fa add CanGc as argument to safe_to_jsval (#40175)
add CanGc as argument to safe_to_jsval

Testing: These changes do not require tests because they are a refactor.
Closes https://github.com/servo/servo/issues/39236

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-26 03:15:20 +00:00
Alessandro
438432105e script: Add message to InvalidCharacterError (#40169)
Adds an optional message to be attached to an InvalidCharacterError.

Testing: simple refactor
Fixes: one of the items of #39053

---------

Signed-off-by: Alessandro Vannini <alessandrovnnn@gmail.com>
2025-10-26 01:34:06 +00:00
Yerkebulan Tulibergenov
aced94224e add CanGc as argument to structuredclone::read (#40157)
add CanGc as argument to structuredclone::read

Testing: These changes do not require tests because they are a refactor.
Closes https://github.com/servo/servo/issues/40154

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-25 08:53:05 +00:00
Yerkebulan Tulibergenov
132bd24c6d add CanGc as argument to Validatable.validity_state (#40155)
add CanGc as argument to Validatable.validity_state

Testing: These changes do not require tests because they are a refactor.
Addresses part of https://github.com/servo/servo/issues/34573.

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-25 06:06:32 +00:00
Yerkebulan Tulibergenov
92cc41abdd add CanGc as argument to key_type_to_jsval (#40153)
add CanGc as argument to key_type_to_jsval

Testing: These changes do not require tests because they are a refactor.
Closes https://github.com/servo/servo/issues/40140

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-25 05:32:40 +00:00
Josh Matthews
991ce544e1 script: Restrict scope of mutable borrow in IDBTransaction::ObjectStore. (#40139)
This avoids a borrow hazard when we create a new IDBObjectStore object
and that triggers a GC.

Testing: Many IndexedDB tests no longer crash when using a debug mozjs
build and full GC zeal. This configuration is not run in CI.
Fixes: #39946

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
2025-10-25 01:48:49 +00:00
Yerkebulan Tulibergenov
4e418ac39a add CanGc as argument to methods in BluetoothDevice (#40147)
add CanGc as argument to methods in BluetoothDevice

Testing: These changes do not require tests because they are a refactor.
Addresses part of https://github.com/servo/servo/issues/34573.

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-25 00:27:43 +00:00
Yerkebulan Tulibergenov
166be9396b add CanGc as argument to methods in PaintRenderingContext2D (#40148)
add CanGc as argument to methods in PaintRenderingContext2D

Testing: These changes do not require tests because they are a refactor.
Addresses part of https://github.com/servo/servo/issues/34573.

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-24 22:41:14 +00:00
Yerkebulan Tulibergenov
dda8878837 add CanGc as argument to methods in Credential (#40149)
add CanGc as argument to methods in Credential

Testing: These changes do not require tests because they are a refactor.
Addresses part of https://github.com/servo/servo/issues/34573.

Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
2025-10-24 22:40:19 +00:00
Andrei Volykhin
45ed17de54 html: Add the 'name' and 'areas' IDL attributes for <map> (#40133)
Follow the HTML specification and add the missing 'name' and 'areas' IDL
attributes to HTMLMapElement.

https://html.spec.whatwg.org/multipage/#htmlmapelement

Testing: Improvements in the following WPT tests
- custom-elements/reactions/customized-builtins/HTMLMapElement.html
- html/dom/idlharness.https.html

Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
2025-10-24 14:19:24 +00:00
Taym Haddadi
7e2e7b5699 Implement UIEvent.which (#40109)
Implement UIEvent.which

Testing: existing test should pass.
Fixes: #40106
Fixes: #40099

---------

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
2025-10-23 22:54:30 +00:00
Gae24
8557bf6fb3 script: implement remaining WorkerGlobalScope's event handlers (#40102)
Clean up WorkerGlobalScope webidl interface and implement all event
handlers that WorkerGlobalScope and subclasses should support.

Testing: Covered by existing tests, needs to update test expectations.

---------

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
2025-10-23 17:24:25 +00:00
Narfinger
18cac42406 Script: len,is_empty and match for DOMString (#39866)
This replaces the implementation of is_empty and len with more efficient
representation without conversion
and allocation based on the underlying bytes.
For this we use a new view, EncodedBytesView.
Additionally, we implement a new macro `match_domstring_ascii!` which
allows simple match clauses
matching ascii strings with DOMStrings without conversion/allocation.
The macro will panic in debug builds if the strings are non-ascii but
will not match all DOMStrings correctly.
We replaced the usage of `DOMString::str()` in many places with this
macro.


Testing: len and is_empty were already covered by tests.
match_domstring_ascii! has more unit tests added with this PR.

---------

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
2025-10-23 14:02:28 +00:00