Skip to content

src: implement util.types fast API calls #57819

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 13, 2025

Conversation

BridgeAR
Copy link
Member

@BridgeAR BridgeAR commented Apr 10, 2025

All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

  • util.inspect (and util.format and console methods respectively)
  • util.isDeepStrictEqual
  • assert.(not)deepEqual (including strict and partial mode)

Local benchmark

                                                                                                             confidence improvement accuracy (*)   (**)   (***)
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='array'                    *      1.09 %       ±1.06% ±1.41%  ±1.85%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='boolean'                         1.68 %       ±2.20% ±2.93%  ±3.84%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='circular'                       -1.71 %       ±1.93% ±2.57%  ±3.35%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='date'                   ***     11.72 %       ±3.14% ±4.20%  ±5.52%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='empty_object'                   -1.81 %       ±3.40% ±4.52%  ±5.88%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='number'                          0.53 %       ±3.54% ±4.72%  ±6.16%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='object'                          1.30 %       ±1.86% ±2.49%  ±3.29%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='regexp'                 ***     16.65 %       ±1.88% ±2.52%  ±3.29%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='set_object'             ***      8.18 %       ±1.27% ±1.69%  ±2.20%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='set_simple'             ***     13.53 %       ±3.62% ±4.84%  ±6.34%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='string'                          1.70 %       ±3.91% ±5.23%  ±6.88%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='array'                          -0.26 %       ±1.38% ±1.84%  ±2.39%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='boolean'                         1.06 %       ±2.10% ±2.80%  ±3.65%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='circular'                        0.62 %       ±1.14% ±1.51%  ±1.97%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='date'                   ***      5.26 %       ±1.39% ±1.86%  ±2.42%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='empty_object'                   -0.64 %       ±1.81% ±2.42%  ±3.17%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='number'                          1.42 %       ±2.56% ±3.40%  ±4.43%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='object'                          0.23 %       ±0.93% ±1.23%  ±1.60%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='regexp'                 ***     12.07 %       ±1.06% ±1.40%  ±1.83%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='set_object'             ***      9.73 %       ±1.01% ±1.35%  ±1.76%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='set_simple'             ***     11.74 %       ±1.45% ±1.92%  ±2.51%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='string'                         -0.64 %       ±7.18% ±9.59% ±12.56%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='array'                        0.04 %       ±1.25% ±1.67%  ±2.17%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='boolean'                      1.15 %       ±1.92% ±2.55%  ±3.32%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='circular'                    -0.48 %       ±2.19% ±2.93%  ±3.84%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='date'                ***      4.27 %       ±2.05% ±2.73%  ±3.56%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='empty_object'                 1.09 %       ±3.53% ±4.70%  ±6.12%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='number'                       4.38 %       ±5.92% ±7.95% ±10.51%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='object'                       0.29 %       ±1.05% ±1.40%  ±1.82%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='regexp'              ***     13.66 %       ±5.20% ±6.99%  ±9.24%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='set_object'          ***      9.90 %       ±3.56% ±4.76%  ±6.24%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='set_simple'          ***     13.06 %       ±0.94% ±1.25%  ±1.63%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='string'                      -0.95 %       ±3.34% ±4.45%  ±5.81%

                                                                                            confidence improvement accuracy (*)   (**)  (***)
assert/partial-deep-equal.js datasetName='array' extraProps=0 size=500 n=125                                0.48 %       ±3.02% ±4.02% ±5.23%
assert/partial-deep-equal.js datasetName='array' extraProps=1 size=500 n=125                                1.63 %       ±2.61% ±3.48% ±4.53%
assert/partial-deep-equal.js datasetName='arrayBuffers' extraProps=0 size=500 n=125                ***     14.79 %       ±1.43% ±1.91% ±2.49%
assert/partial-deep-equal.js datasetName='arrayBuffers' extraProps=1 size=500 n=125                ***      5.93 %       ±0.74% ±0.99% ±1.29%
assert/partial-deep-equal.js datasetName='circularRefs' extraProps=0 size=500 n=125                ***      4.61 %       ±0.58% ±0.78% ±1.01%
assert/partial-deep-equal.js datasetName='circularRefs' extraProps=1 size=500 n=125                ***      4.26 %       ±0.96% ±1.28% ±1.68%
assert/partial-deep-equal.js datasetName='dataViewArrayBuffers' extraProps=0 size=500 n=125        ***      3.60 %       ±1.30% ±1.73% ±2.25%
assert/partial-deep-equal.js datasetName='dataViewArrayBuffers' extraProps=1 size=500 n=125          *      1.33 %       ±1.14% ±1.51% ±1.97%
assert/partial-deep-equal.js datasetName='maps' extraProps=0 size=500 n=125                        ***      9.73 %       ±0.75% ±1.01% ±1.32%
assert/partial-deep-equal.js datasetName='maps' extraProps=1 size=500 n=125                        ***     10.36 %       ±0.86% ±1.15% ±1.49%
assert/partial-deep-equal.js datasetName='objects' extraProps=0 size=500 n=125                             -0.01 %       ±0.70% ±0.93% ±1.21%
assert/partial-deep-equal.js datasetName='objects' extraProps=1 size=500 n=125                              0.23 %       ±0.76% ±1.01% ±1.32%
assert/partial-deep-equal.js datasetName='sets' extraProps=0 size=500 n=125                        ***      7.94 %       ±0.78% ±1.05% ±1.37%
assert/partial-deep-equal.js datasetName='sets' extraProps=1 size=500 n=125                        ***      7.10 %       ±2.10% ±2.83% ±3.73%
assert/partial-deep-equal.js datasetName='setsWithObjects' extraProps=0 size=500 n=125             ***      5.96 %       ±1.09% ±1.46% ±1.90%
assert/partial-deep-equal.js datasetName='setsWithObjects' extraProps=1 size=500 n=125             ***      6.82 %       ±1.06% ±1.41% ±1.84%
assert/partial-deep-equal.js datasetName='typedArrays' extraProps=0 size=500 n=125                 ***      2.49 %       ±0.68% ±0.90% ±1.18%
assert/partial-deep-equal.js datasetName='typedArrays' extraProps=1 size=500 n=125                 ***      4.96 %       ±0.89% ±1.18% ±1.54%

                                                                      confidence improvement accuracy (*)   (**)  (***)
util/inspect.js option='colors' method='Array' n=80000                                0.21 %       ±0.76% ±1.02% ±1.32%
util/inspect.js option='colors' method='Date' n=80000                        ***      3.59 %       ±0.67% ±0.90% ±1.17%
util/inspect.js option='colors' method='Error' n=80000                       ***      2.68 %       ±0.68% ±0.91% ±1.18%
util/inspect.js option='colors' method='Number' n=80000                               0.52 %       ±1.62% ±2.16% ±2.81%
util/inspect.js option='colors' method='Object_deep_ln' n=80000                       0.44 %       ±0.63% ±0.84% ±1.10%
util/inspect.js option='colors' method='Object_empty' n=80000                ***      1.71 %       ±0.78% ±1.03% ±1.34%
util/inspect.js option='colors' method='Object' n=80000                              -0.04 %       ±0.76% ±1.02% ±1.33%
util/inspect.js option='colors' method='Set' n=80000                         ***      1.34 %       ±0.76% ±1.02% ±1.32%
util/inspect.js option='colors' method='String_boxed' n=80000                ***     26.23 %       ±0.79% ±1.05% ±1.38%
util/inspect.js option='colors' method='String_complex' n=80000                       0.61 %       ±1.01% ±1.35% ±1.75%
util/inspect.js option='colors' method='String' n=80000                              -0.17 %       ±0.94% ±1.25% ±1.63%
util/inspect.js option='colors' method='TypedArray_extra' n=80000                    -0.88 %       ±1.02% ±1.36% ±1.78%
util/inspect.js option='colors' method='TypedArray' n=80000                          -0.16 %       ±0.86% ±1.14% ±1.49%
util/inspect.js option='none' method='Array' n=80000                                  0.73 %       ±1.21% ±1.62% ±2.13%
util/inspect.js option='none' method='Date' n=80000                          ***      3.59 %       ±0.78% ±1.03% ±1.34%
util/inspect.js option='none' method='Error' n=80000                         ***      3.91 %       ±0.78% ±1.04% ±1.36%
util/inspect.js option='none' method='Number' n=80000                                 1.07 %       ±2.13% ±2.84% ±3.72%
util/inspect.js option='none' method='Object_deep_ln' n=80000                ***      2.10 %       ±0.63% ±0.84% ±1.09%
util/inspect.js option='none' method='Object_empty' n=80000                  ***      2.38 %       ±0.73% ±0.97% ±1.26%
util/inspect.js option='none' method='Object' n=80000                          *      1.07 %       ±0.83% ±1.11% ±1.44%
util/inspect.js option='none' method='Set' n=80000                           ***      1.82 %       ±0.73% ±0.98% ±1.27%
util/inspect.js option='none' method='String_boxed' n=80000                  ***     30.90 %       ±1.26% ±1.69% ±2.22%
util/inspect.js option='none' method='String_complex' n=80000                         0.62 %       ±0.96% ±1.27% ±1.66%
util/inspect.js option='none' method='String' n=80000                                -0.01 %       ±1.14% ±1.52% ±1.98%
util/inspect.js option='none' method='TypedArray_extra' n=80000                *      0.94 %       ±0.84% ±1.11% ±1.45%
util/inspect.js option='none' method='TypedArray' n=80000                             0.44 %       ±0.75% ±1.00% ±1.30%
util/inspect.js option='showHidden' method='Array' n=80000                           -0.54 %       ±0.89% ±1.19% ±1.55%
util/inspect.js option='showHidden' method='Date' n=80000                    ***      3.92 %       ±0.70% ±0.93% ±1.22%
util/inspect.js option='showHidden' method='Error' n=80000                   ***      3.24 %       ±0.80% ±1.07% ±1.39%
util/inspect.js option='showHidden' method='Number' n=80000                          -1.40 %       ±2.95% ±3.93% ±5.13%
util/inspect.js option='showHidden' method='Object_deep_ln' n=80000           **      1.40 %       ±0.95% ±1.27% ±1.68%
util/inspect.js option='showHidden' method='Object_empty' n=80000              *      2.66 %       ±2.27% ±3.01% ±3.92%
util/inspect.js option='showHidden' method='Object' n=80000                           0.60 %       ±0.60% ±0.80% ±1.05%
util/inspect.js option='showHidden' method='Set' n=80000                       *      0.95 %       ±0.80% ±1.06% ±1.38%
util/inspect.js option='showHidden' method='String_boxed' n=80000            ***     21.05 %       ±1.14% ±1.52% ±1.98%
util/inspect.js option='showHidden' method='String_complex' n=80000                   0.22 %       ±0.79% ±1.06% ±1.38%
util/inspect.js option='showHidden' method='String' n=80000                           1.10 %       ±1.59% ±2.12% ±2.77%
util/inspect.js option='showHidden' method='TypedArray_extra' n=80000        ***      2.48 %       ±0.87% ±1.16% ±1.51%
util/inspect.js option='showHidden' method='TypedArray' n=80000              ***      3.58 %       ±1.01% ±1.34% ±1.75%

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Apr 10, 2025
@BridgeAR BridgeAR force-pushed the util-types-fast-api branch from 5e8ba0a to e4b0c0a Compare April 10, 2025 13:14
@BridgeAR BridgeAR changed the title src: implement initial util.types fast API calls src: implemen util.types fast API calls Apr 10, 2025
@BridgeAR BridgeAR changed the title src: implemen util.types fast API calls src: implement util.types fast API calls Apr 10, 2025
@BridgeAR BridgeAR added assert Issues and PRs related to the assert subsystem. util Issues and PRs related to the built-in util module. performance Issues and PRs related to the performance of Node.js. labels Apr 10, 2025
@BridgeAR BridgeAR force-pushed the util-types-fast-api branch from e4b0c0a to 5770181 Compare April 10, 2025 13:20
Copy link
Member

@anonrig anonrig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add specific tests for each one of these calls to make sure these fast paths are triggered? Please take a look into the documentation:

tracked using the `TRACK_V8_FAST_API_CALL("key")` macro. This can be used to

An example can be found at

assert.strictEqual(getV8FastApiCallCount('custom_namespace.divide.error'), 1);

Copy link

codecov bot commented Apr 10, 2025

Codecov Report

Attention: Patch coverage is 89.47368% with 2 lines in your changes missing coverage. Please review.

Project coverage is 90.22%. Comparing base (8456a12) to head (1d00f22).
Report is 51 commits behind head on main.

Files with missing lines Patch % Lines
src/node_types.cc 89.47% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #57819      +/-   ##
==========================================
- Coverage   90.23%   90.22%   -0.01%     
==========================================
  Files         630      630              
  Lines      185245   185497     +252     
  Branches    36301    36376      +75     
==========================================
+ Hits       167154   167372     +218     
+ Misses      11006    10996      -10     
- Partials     7085     7129      +44     
Files with missing lines Coverage Δ
src/node_types.cc 95.12% <89.47%> (-4.88%) ⬇️

... and 62 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@BridgeAR BridgeAR force-pushed the util-types-fast-api branch 2 times, most recently from c74523f to 18a24b6 Compare April 10, 2025 20:43
@BridgeAR
Copy link
Member Author

@anonrig thanks for the hint, I just added the test. I guess we could update the documentation to add the debug part as I did now.

All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.
@BridgeAR BridgeAR force-pushed the util-types-fast-api branch from f6eca05 to 1d00f22 Compare April 12, 2025 00:14
@BridgeAR BridgeAR added the request-ci Add this label to start a Jenkins CI on a PR. label Apr 12, 2025
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Apr 12, 2025
@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@BridgeAR BridgeAR added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. commit-queue Add this label to land a pull request using GitHub Actions. labels Apr 13, 2025
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Apr 13, 2025
@nodejs-github-bot nodejs-github-bot merged commit 964e41c into nodejs:main Apr 13, 2025
63 checks passed
@nodejs-github-bot
Copy link
Collaborator

Landed in 964e41c

RafaelGSS pushed a commit that referenced this pull request May 1, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
RafaelGSS pushed a commit that referenced this pull request May 2, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request May 6, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request May 6, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
RafaelGSS pushed a commit that referenced this pull request May 14, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request May 16, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request May 17, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request May 17, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request May 17, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
aduh95 pushed a commit that referenced this pull request May 19, 2025
All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

It will also improve any other API where these APIs are used.

PR-URL: #57819
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assert Issues and PRs related to the assert subsystem. author ready PRs that have at least one approval, no pending requests for changes, and a CI started. c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. performance Issues and PRs related to the performance of Node.js. util Issues and PRs related to the built-in util module.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy