Commit Graph

13024 Commits

Author SHA1 Message Date
Jayanta Pradhan
ae33e48cb8 script: Move xpath interfaces into xpath/ (#43616)
Moves xpath interfaces into script/dom/xpath/ module from script/dom/.

Testing: Just a refactor.
Fixes: Part of #38901

Signed-off-by: Jayanta Pradhan <pradhanjayanta91@gmail.com>
2026-03-24 15:22:48 +00:00
Euclid Ye
32cce8e6de cargo: Rename workspace-local dependencies starting with c to servo-* (#43615)
Also reorders alphabetically for the corresponding user .toml.

Similar to #43526.

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
2026-03-24 15:10:38 +00:00
Abbas Olanrewaju Sarafa
ae4a5b8de5 script: Use encoding-parse algorithm in Worker::Constructor (#43588)
Updated api base url to encoding_parse_a_url and wrote tests referencing
the suggested format

Fixes: #43557 
Testing: new passing test

Signed-off-by: Sabb <sarafaabbas@gmail.com>
2026-03-24 14:32:26 +00:00
elomscansio
7e97e82008 script: Move document DOM interfaces to script/dom/document/ (#43602)
Moves interfaces defined by the document spec to the
script/dom/document/ module from script/dom/.

Testing: Just a refactor shouldn't need any testing
Fixes: Partially #38901

---------

Signed-off-by: Emmanuel Paul Elom <elomemmanuel007@gmail.com>
2026-03-24 14:29:07 +00:00
elomscansio
fc29fea5e1 script: Move file DOM interfaces to script/dom/file/ (#43607)
Moves interfaces defined by the file spec to the script/dom/file/ module
from script/dom/.

Testing: Just a refactor shouldn't need any testing
Fixes: Partially #38901

Signed-off-by: Emmanuel Paul Elom <elomemmanuel007@gmail.com>
2026-03-24 13:15:16 +00:00
Oriol Brufau
7c1401fff8 script: Add preshints for width and height attributes of <svg> (#43583)
Lets the `width` and `height` attributes of `<svg>` set presentational
hints for the CSS properties of the same name.

Also bumps Stylo to servo/stylo#343, in order to also set the preshints
for percentage values. However, layout will ignore percentages for the
purpose of computing the natural sizes and aspect ratio.

Testing: Improves WPT

---------

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2026-03-24 09:29:03 +00:00
elomscansio
36a5885086 script: Move Clipboard DOM interfaces to script/dom/clipboard/ (#43597)
Moves interfaces defined by the clipboard spec to the
script/dom/clipboard/ module from script/dom/.

Testing: Just a refactor shouldn't need any testing
Fixes: Partially #38901

---------

Signed-off-by: Emmanuel Paul Elom <elomemmanuel007@gmail.com>
2026-03-24 08:58:07 +00:00
minghuaw
75a56e567b layout: Do not trigger dirty_all_nodes when web font loading fails (#43595)
Currently, the `web_font_finished_loading_callback` sends a
`ScriptThreadMessage::WebFontLoaded` message regardless of whether web
font loading succeeds or not, which leads to dirtying all nodes in
`script_thread.rs`. This creates unnecessary reflow. This PR removes the
boolean field from the `WebFontLoaded` message and only sends the
message when the web font loading is successful.

Testing: Existing WPT tests

Signed-off-by: Minghua Wu <michael.wu1107@gmail.com>
2026-03-24 08:03:30 +00:00
Gae24
113b06f2ee script: Correctly setup request for worker module scripts (#43585)
According to spec we should fetch worker modules using the _outside
settings_, however we can't use it directly since we are on a different
thread. To fix it, a new struct `ModuleFetchClient` is now part of
`LoadState` and replace the `with_global_scope` call done in
`fetch_a_single_module_script`.
This also tidy worker classic script related code.

Testing: There are new passes

---------

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
2026-03-24 05:28:27 +00:00
Jayanta Pradhan
29fb865a00 script: Pass down &mut JSContext to CookieStore methods (#43584)
Move CookieStore methods from CanGc to &mut JSContext.

Testing:  Just refactor.
Fixes: Part of #42638

Signed-off-by: Jayanta Pradhan <pradhanjayanta91@gmail.com>
2026-03-23 23:44:37 +00:00
Jayanta Pradhan
166a9ddd85 script: Pass down &mut JSContext to CSSGroupingRule methods (#43579)
Move `CSSGroupingRule` methods from `CanGc` to `&mut JSContext`.

Testing:  Just refactor.
Fixes: Part of  #42638

Signed-off-by: Jayanta Pradhan <pradhanjayanta91@gmail.com>
2026-03-23 21:19:28 +00:00
eri
0ee2b03b40 devtools: Remove double optional from WebIDL (#43567)
Some values of the WebIDL were wrapped two types in nullable (from not
having `required` and having a `?`). Simplify that so we don't get
`Option<Option<...>>`.

Testing: Existing tests
Part of: #36027 
Depends on: #43566

Signed-off-by: eri <eri@igalia.com>
Co-authored-by: atbrakhi <atbrakhi@igalia.com>
2026-03-23 18:15:49 +00:00
Abubakar Abdulazeez Usman
c3723affc2 script: Pass &mut JSContext to CSSStyleRule::Style (#43569)
Move `CSSStyleRule::Style` from `CanGc` to `&mut JSContext`. Also fix
the caller in `devtools.rs` to pass `cx` directly.

Testing: Refactoring, It compiles.
Fixes: Part of #42638

Signed-off-by: arabson99 <arabiusman99@gmail.com>
2026-03-23 17:00:23 +00:00
Simon Wülker
1b2a1d8da4 script: Align URL::CanParse and URL::Parse more directly with the specification (#43576)
Testing: This should not change existing behaviour and these methods are
covered by existing tests

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
2026-03-23 16:52:21 +00:00
eri
de4a79facf devtools: Rename PropertyPreview to PropertyDescriptor (#43566)
Rename `PropertyPreview` to `PropertyDescriptor`

Testing: Internal refactor
Part of: #36027

Signed-off-by: eri <eri@igalia.com>
Co-authored-by: atbrakhi <atbrakhi@igalia.com>
2026-03-23 15:27:44 +00:00
Domenico Rizzo
95aa798b2f webgl: Remove manual Drop implementation for WebGLRenderbuffer (#43563)
Moves the cleanup logic to a separate helper struct to comply with the
prohibition of manual `Drop` implementations for DOM types.

Testing: WebGL tests just cover its cases
Fixes: Partially #26488

Signed-off-by: Domenico Rizzo <domenico.rizzo@gmail.com>
2026-03-23 14:47:13 +00:00
Sharan Poojari
20e11deb96 devtools: Handle service worker eval (#43492)
This completes the service-worker side while addressing earlier panic
concerns by avoiding unconditional unwrap/expect paths.

Testing: No dedicated tests were added for this change.

Fixes: #43317

Signed-off-by: SharanRP <z8903830@gmail.com>
2026-03-23 14:18:25 +00:00
Sharan Poojari
34583dc66f script: Use encoding-parse algorithm when handling iframe and Document URL attributes (#43572)
This PR fixes iframe URL parsing to use document encoding, so non-UTF-8
pages reflect iframe.src correctly, and adds a WPT test for it.

Testing: added Test file 
Fixes: #43559

Signed-off-by: SharanRP <z8903830@gmail.com>
2026-03-23 13:48:11 +00:00
Eyüp Can Akman
1422d2a850 script: Add error messages in HMAC WebCrypto operations (#43560)
Replace all `Error::*(None)` instances in `hmac_operation.rs` with
descriptive error messages, covering sign, verify, generate_key,
import_key, and export_key operations.

Testing: Existing WPT tests cover all HMAC operations and check error
types, not message strings. No behavioral change.
Fixes: Part of #40756

---------

Signed-off-by: Eyüp Can Akman <eyupcanakman@gmail.com>
2026-03-23 13:29:17 +00:00
Abubakar Abdulazeez Usman
dae0edb5b9 script: Pass &mut JSContext to CSSKeyframesRule methods (#43571)
Move `CSSKeyframesRule` methods (`CssRules`, `AppendRule`, `DeleteRule`,
`FindRule`) from `CanGc` to `&mut JSContext`.

Testing: It compiles.
Fixes: Part of #42638

Signed-off-by: arabson99 <arabiusman99@gmail.com>
2026-03-23 12:19:44 +00:00
Abubakar Abdulazeez Usman
f78ca1cef4 script: Pass &mut JSContext to CSSNestedDeclarations::Style (#43570)
Move `CSSNestedDeclarations::Style` from `CanGc` to `&mut JSContext`.

Testing: It compiles.
Fixes: Part of #42638

Signed-off-by: arabson99 <arabiusman99@gmail.com>
2026-03-23 11:37:34 +00:00
Shubham Gupta
70e1547771 script: Suppress unused import warning related to gamepad in navigator.rs (#43513)
Just adds some imports under gamepad cfg flag.

Testing: Successful compilation is enough to verify the change.

Signed-off-by: Shubham Gupta <shubham.gupta@chromium.org>
2026-03-23 08:41:35 +00:00
rtjkro
afa4b524ab font: Consider lang attribute when shaping (#43447)
Fonts: Added `language` field in the struct `ShapingOptions` so Harfbuzz
can also consider language when shaping glyphs.

Testing: Existing WPT. Most recent try run:
[link](https://github.com/RichardTjokroutomo/servo/actions/runs/23334049878)

2 new passes, 5 new fails.

Failures:
- `/css/css-text-decor/text-emphasis-punctuation-2.html` should be a
false positive since `text-emphasis` shorthand hasn't been supported on
stylo yet.
- Not quite sure about this, but
`/css/css-text/text-spacing-trim/text-spacing-trim-quote-001.html?class=halt,htb&amp;lang=ja`
tests `text-spacing-trim` default behavior on `JA` texts. Since this
property is not defined in Stylo, I believe that this property's
behavior (including default) hasn't been considered in Servo. So Servo
previously passing the test should be a false positive. As a side note,
this test also fails on Firefox.
- `/html/canvas/element/manual/text/canvas.2d.lang.dynamic.html`,
`/html/canvas/element/manual/text/canvas.2d.lang.html`,
`/html/canvas/element/manual/text/canvas.2d.lang.inherit.disconnected.canvas.html`
fail because canvas' experimental [`lang`
attribute](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lang)
hasn't been supported yet.

credits to @mrobinson for figuring out the reason for last 3 failing WPT
tests!

Fixes: #41825

---------

Signed-off-by: Richard Tjokroutomo <richard.tjokro2@gmail.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
2026-03-23 08:39:53 +00:00
mishop-15
7a4d3e636b script: Migrate from utf_8 crate to encoding_rs in EventSource (#42179)
Migrate from `utf_8` to `encoding_rs` in `EventSource`. The `utf_8`
crate is archived and unmaintained. We already use `encoding_rs`, so it
makes sense to switch.

Testing: A new WPT test
(`tests/wpt/meta/eventsource/format-bom.any.js.ini`) is now passing.
Fixes: #42094.

Signed-off-by: mishop-15 <tanaybhutada03@gmail.com>
2026-03-23 08:30:49 +00:00
Euclid Ye
cae0752676 cargo: Rename workspace-local library starting with b to servo_* (#43552)
Follow up of #43526. This addresses Nico's comment:
https://github.com/servo/servo/pull/43526#issuecomment-4104953308

- `bluetooth_traits` -> `servo_bluetooth_traits`
- `base` -> `servo_base`
- `bluetooth` -> `servo_bluetooth`
- `background_hang_monitor` -> `servo_background_hang_monitor`

Testing: This should not change any behaviour.

---------

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
2026-03-23 08:26:49 +00:00
Kingsley Yung
23f78a06c7 script: Implement TurboSHAKE algorithm in WebCrypto (#43551)
Implement TurboSHAKE algorithm in our WebCrypto API. This includes a
WebIDL dictionary `TurboSHAKE` and the "digest" operation of TurboSHAKE.

Specification: https://wicg.github.io/webcrypto-modern-algos/#turboshake
Testing: Pass TurboSHAKE-related WPT tests.
Fixes: Part of #40687

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2026-03-23 06:22:46 +00:00
Tim van der Lippe
01a29209b2 script: Implement support for X-Frame-Options (#43539)
We now check for this header and corresponding logic. The WPT tests
mostly pass, but rely on the `contentDocument` of the iframe to be
`null`. This is not something we did before, which means that iframes
were able to access the contents of error pages.

Instead, we now mark the document as internal with an opaque origin
according to the spec [1]. We shouldn't do this post-fact, but is
required since we first need to construct the document and enter its
realm, before we determine that it is an invalid document.

Fixes #16103

[1]:
https://html.spec.whatwg.org/multipage/document-lifecycle.html#navigate-ua-inline

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
2026-03-23 06:14:27 +00:00
Jayanta Pradhan
ebfdaff63f script: Use encoding-parsing algorithm in XMLHttpRequest::Open (#43537)
Add a new method to components/script/dom/globalscope.rs which checks if
the global is a Window , then uses
window.Document().encoding_parse_a_url(..) if so. For non-Window
globals, just use the existing logic of getting the api_base_url() value
and calling join(..) on it.

Testing: Existing WPTs.
Fixes: #43509

---------

Signed-off-by: Jayanta Pradhan <pradhanjayanta91@gmail.com>
2026-03-23 03:18:24 +00:00
Abubakar Abdulazeez Usman
6c7fcd41bd script: Pass &mut JSContext to CSSKeyframeRule::Style (#43549)
Move `CSSKeyframeRule::Style` from `CanGc` to `&mut JSContext`.

Testing: Just a refactor, Existing tests suffice.
Fixes: Part of #42638

Signed-off-by: arabson99 <arabiusman99@gmail.com>
2026-03-23 02:54:31 +00:00
Philipp Albrecht
2f1b7f0f84 Pass &mut JSContext (#43543)
This is follow-up of #41459.

We replace some of these:

```rust
let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
```

..by passing a `cx: &mut JSContext` instead.

---

Testing: existing WPT tests  
Fixes: #43453

Signed-off-by: pylbrecht <pylbrecht@mailbox.org>
2026-03-22 20:58:05 +00:00
Domenico Rizzo
1e514bcfe9 webgl: Remove manual Drop implementation for WebGLQuery (#43544)
Moves the cleanup logic to a separate helper struct to comply with the
prohibition of manual `Drop` implementations for DOM types.

Testing: WebGL tests just cover its parts
Fixes: Partially #26488

Signed-off-by: Domenico Rizzo <domenico.rizzo@gmail.com>
2026-03-22 20:33:35 +00:00
Kelechi Ebiri
a63a00936f remove referrer field from ScriptFetchOptions (#43532)
Remove `referrer` field from `ScriptFetchOptions` and pass it directly
to `script_fetch_request`.

This keeps ScriptFetchOptions aligned with the HTML 
fixes #42875

---------

Signed-off-by: Kelechi Ebiri <ebiritg@gmail.com>
2026-03-22 16:41:29 +00:00
Sharan Poojari
9cbdf9d8b1 Gate picker on trusted click (#43485)
Fixes: #43360 
This PR makes `<select>` behave like other browsers by only opening the
picker for trusted user clicks, and adds a regression test to ensure
synthetic `.click()/dispatchEvent('click')` won’t open it.

---------

Signed-off-by: SharanRP <z8903830@gmail.com>
2026-03-22 12:18:20 +00:00
Euclid Ye
317e5ee7de cargo: Rename Workspace-local dependencies starting with b to servo-* (#43526)
Also reorders alphabetically for the corresponding user .toml.

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
2026-03-22 11:19:21 +00:00
Tim van der Lippe
7b9b75c545 script: Fix current URL for CSP requests (#43438)
The CSP crate was incorrectly using the request URL for both checking if
policies were matching, as well as reporting that URL. However, the CSP
specification uses the current URL to check for policies and the url for
reporting a violation.

Therefore, set the new current_url field for these requests, leaving the
ws scheme URLs as a special case. We also should take redirects into
account for navigations (which is only relevant for forms), but LoadData
currently has no notion of keeping track of that.

Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
2026-03-22 11:12:22 +00:00
Gae24
5152632f04 script_bindings: Pass &mut JSContext to CustomElementReaction::invoke (#43535)
Pass `&mut JSContext` to `CustomElementReaction::invoke` and
`upgrade_element` algorithm.

Testing: A successful build is enough
Part of #40600

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
2026-03-22 11:11:52 +00:00
Kingsley Yung
dcca7b2030 script: Rename length parameter of cSHAKE to outputLength (#43533)
Modern Algorithms in WebCrypto API specification was updated to rename
the `length` parameter of the `CShakeParams` dictionary to
`outputLength`. We update our implementation accordingly.

Specification update:
41434899e8
WPT update:
0acea989ac

The final step of the "digest" operation of cSHAKE was also updated to
clarify that it outputs a byte sequence, rather than a bit sequence.
This matches our current implementation. No change in our implementation
is needed. The specification text in our code is updated.

Specification update:
5dd19e3a9f

Testing: Pass updated WPT tests.

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2026-03-22 06:28:53 +00:00
Jayanta Pradhan
5ba6636555 script: add navigation and traversal task source (#43523)
script: Add navigation and traversal task source

Testing: This shouldn't be something that's observable through tests, so
a successful build is enough to verify the change.
Fixes: #43497

---------

Signed-off-by: Jayanta Pradhan <pradhanjayanta91@gmail.com>
2026-03-22 05:39:42 +00:00
Gae24
1626450063 script: Propagate &mut JSContext from GlobalScope::start_message_port to stream code (#43525)
Pass `&mut JSContext` to more stream related code.

Testing: A successful build is enough.
Part of #42347

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
2026-03-21 21:07:47 +00:00
Sharan Poojari
5af76f6a23 Use encoding-parse for form action (#43521)
Parse form action URLs using the document's encoding-aware URL parser.

Testing: Verified with the WPT form-action tests `./mach test-wpt
tests/wpt/tests/html/semantics/forms/the-form-element`, all relevant
tests passed.

Fixes: #43507

Signed-off-by: SharanRP <z8903830@gmail.com>
2026-03-21 16:18:40 +00:00
Shubham Gupta
ea8d93d740 script: Remove unused LayoutDom from gpucanvascontext.rs (#43514)
Remove unused `LayoutDom`

Testing: Successful Compilation is enough to verify the change.

Signed-off-by: Shubham Gupta <shubham.gupta@chromium.org>
2026-03-21 15:47:00 +00:00
Josh Matthews
5f247392be script: Move navigation origin logic into a method with spec steps. (#43491)
This pulls one bit of navigation logic out into a method that is easier
to cross-reference against the spec, and drops a bunch of custom logic
that is better served by the existing LoadOrigin infrastructure.

Testing: Existing WPT coverage is sufficient.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
2026-03-21 12:26:35 +00:00
Luke Warlow
09b0cfce8e script: Add longdesc reflection to HTMLIFrameElement and HTMLFrameElement (#43518)
script: Add longdesc reflection to HTMLIFrameElement and
HTMLFrameElement

Also corrects the reflection for HTMLImageElement to use USVString.

Testing: Covered by WPTs

Signed-off-by: Luke Warlow <lwarlow@igalia.com>
2026-03-21 11:46:16 +00:00
Jerens Lensun
4199e050d9 script: add a check for a valid key path on idb object store (#42451)
Add a check for a valid key path when create index on idb object store

Testing: `./mach test-wpt
tests/wpt/tests/IndexedDB/keypath_invalid.any.js`
Fixes: #42434

---------

Signed-off-by: Jerens Lensun <jerensslensun@gmail.com>
2026-03-21 11:44:23 +00:00
Kingsley Yung
c23d888863 script: Rework on dictionary conversion in SubtleCrypto (#43519)
Our existing `SubtleCrypto::normalize_algorithm` implementation converts
the input dictionary from a JavaScript object to a Rust struct twice.
The first conversion (Step 2 to 4) under WebIDL dictionary `Algorithm`
is for retrieving the `name` property to determine the desired
dictionary type, and the second conversion (Step 9 to 10) is for
retrieving the whole dictionary of desired WebIDL dictionary type.

If the `name` property of the input dictionary is a JavaScript getter
method, the getter will be triggered twice and leads to some undesired
side effects. For example, WPT contains some tests that the `name`
property is a getter method which transfers a buffer source. Triggering
it twice leads to a TypeError of accessing detached buffer at the second
time. Those tests then fail.


5bb4f9f103/tests/wpt/tests/WebCryptoAPI/digest/cshake.tentative.https.any.js (L215-L219)

This patch includes two changes to fix this problem.

First, the algorithm name retrieved in Step 2 to 4 is now passed to
`Op::RegisteredAlgorithm::from_object` in Step 9 to 10 so that we don't
need to read the `name` property and trigger the getter method again.

Second, we no longer use `dictionary_from_jsval` for converting the
dictionary, since it reads the whole dictionary including the `name`
property, triggering the getter method again. Instead, we add some
custom helper functions (`get_optional_parameter`,
`get_required_parameter`, `get_optional_parameter_in_box`,
`get_required_parameter_in_box`, `get_optional_buffer_source`,
`get_required_buffer_source`) to manually read properties other the
`name` property one by one, in a way that matches the specification.

Hence, each property of the input dictionary will only be read once, to
avoid this issue.

Testing: Pass some WPT tests that were expected to fail.

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
2026-03-21 11:02:58 +00:00
Euclid Ye
e573557554 cargo: Use kebab case consistenly for those already starting with servo- (#43516)
Continues what @jschwe has been doing.

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
2026-03-21 10:57:22 +00:00
Luke Warlow
ac1c86fea7 script: Add usemap reflection to HTMLInputElement and HTMLObjectElement (#43502)
script: Add usemap reflection to HTMLInputElement and HTMLObjectElement

Testing: Covered by WPTs

Signed-off-by: Luke Warlow <lwarlow@igalia.com>
2026-03-21 09:54:32 +00:00
Luke Warlow
f06e67c031 script: Add hreflang, type and charset reflection to HTMLAnchorElement (#43499)
script: Add hreflang, type and charset reflection to HTMLAnchorElement

Testing: Covered by WPTs

Signed-off-by: Luke Warlow <lwarlow@igalia.com>
2026-03-21 08:23:54 +00:00
Luke Warlow
74640b7719 script: Add nohref reflection to HTMLAreaElement (#43500)
script: Add nohref reflection to HTMLAreaElement

Testing: Covered by WPTs

Signed-off-by: Luke Warlow <lwarlow@igalia.com>
2026-03-21 08:00:48 +00:00
Rogerkoranteng
cfaaad4b66 script: Fix panic in crypto.getRandomValues when random generation fails (#43501)
## Summary

Fixes #43328

When `OsRng.try_fill_bytes` fails in `crypto.getRandomValues`, the code
previously returned `Error::JSFailed`. This error type asserts that a
JavaScript exception is already pending on the context — but `OsRng` is
a Rust library that never sets a JS exception, causing Servo to panic
with `assertion failed: JS_IsExceptionPending(*cx)`.

This PR replaces `Error::JSFailed` with `Error::Operation`, which throws
a proper `OperationError` DOMException instead of crashing. This is
consistent with how Servo's SubtleCrypto handles the same scenario
(e.g., `ed25519_operation.rs`).

## Testing

Tested by unconditionally taking the error branch (`if true`):

**Before (panic):**

<img width="960" alt="Screenshot From 2026-03-20 23-42-35"
src="https://github.com/user-attachments/assets/f15150ce-aa26-46c9-a381-985e6d850904"
/>

---


**After (fix):**

<img width="960" alt="Screenshot From 2026-03-20 23-43-05"
src="https://github.com/user-attachments/assets/99490b06-aeaa-4dcc-b10a-56336efad87d"
/>

Signed-off-by: rogerkorantenng <rogerkorantenng@gmail.com>
2026-03-21 07:18:04 +00:00