Skip to content

perf(linter/eslint/no-script-url): match javascript: prefix without allocating#23861

Merged
camc314 merged 3 commits into
oxc-project:mainfrom
linyiru:perf/no-script-url-no-alloc
Jun 27, 2026
Merged

perf(linter/eslint/no-script-url): match javascript: prefix without allocating#23861
camc314 merged 3 commits into
oxc-project:mainfrom
linyiru:perf/no-script-url-no-alloc

Conversation

@linyiru

@linyiru linyiru commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

What

NoScriptUrl::run fires on every StringLiteral and TemplateLiteral. The guard
used value.cow_to_ascii_lowercase().starts_with("javascript:"), which scans the
whole value to detect any ASCII uppercase and heap-allocates a lowercased copy
whenever one is present — all to compare an 11-byte prefix.

"javascript:" is ASCII, so ASCII-lowercasing never changes byte length and only
the first 11 bytes can affect the match. This replaces the check with an
allocation-free is_javascript_url helper that compares the first 11 bytes with
eq_ignore_ascii_case, shared by both the string- and template-literal arms.

Correctness

Output is unchanged. s.cow_to_ascii_lowercase().starts_with("javascript:") is true
iff s.len() >= 11 and s.as_bytes()[..11].eq_ignore_ascii_case(b"javascript:")
(ASCII-lowercasing is length-preserving, and a non-ASCII byte in the first 11 fails
both forms). The rule's snapshot test is unchanged.

Perf

Predicate microbench over a realistic literal mix (lowercase, PascalCase, long
messages with uppercase, and actual javascript: matches), with identical boolean
results both ways:

check ns/call
cow_to_ascii_lowercase().starts_with(..) 15.5
is_javascript_url (this PR) 1.0

The gain is the removed heap allocation for uppercase-containing strings plus an
O(11) prefix compare instead of an O(len) scan. CodSpeed will capture the aggregate
effect on the linter benchmark.


Disclosure: developed with AI assistance (Claude), reviewed and verified by the author.

@linyiru linyiru requested a review from camc314 as a code owner June 27, 2026 01:51
…llocating

`run` fires on every `StringLiteral` and `TemplateLiteral`, and the guard used
`value.cow_to_ascii_lowercase().starts_with("javascript:")`, which scans the whole
value to detect uppercase and heap-allocates a lowercased copy whenever one is
present — all to compare an 11-byte prefix.

`"javascript:"` is ASCII, so ASCII-lowercasing never changes byte length and only
the first 11 bytes can affect the match. Replace the check with an allocation-free
`is_javascript_url` that compares the first 11 bytes via `eq_ignore_ascii_case`.
Diagnostics are byte-for-byte unchanged (snapshot test unchanged); added pass cases
cover the new length guard (strings shorter than 11 bytes) and multi-byte prefixes.

Predicate microbench over a realistic literal mix (lowercase, PascalCase, long
messages, actual matches): 15.5 ns -> 1.0 ns per call, identical results.
@linyiru linyiru force-pushed the perf/no-script-url-no-alloc branch from 38eece4 to b9d7c9e Compare June 27, 2026 01:56
Comment thread crates/oxc_linter/src/rules/eslint/no_script_url.rs Outdated
@camc314 camc314 self-assigned this Jun 27, 2026
@camc314 camc314 added the A-linter Area - Linter label Jun 27, 2026

@camc314 camc314 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

thank you!

@camc314 camc314 merged commit f138264 into oxc-project:main Jun 27, 2026
28 checks passed
@codspeed-hq

codspeed-hq Bot commented Jun 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 5 untouched benchmarks
⏩ 66 skipped benchmarks1


Comparing linyiru:perf/no-script-url-no-alloc (99376e4) with main (5762638)

Open in CodSpeed

Footnotes

  1. 66 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

camc314 added a commit that referenced this pull request Jun 28, 2026
)

## What

`aria-props` and `aria-proptypes` run on every `JSXAttribute`. Both
lowercased the
attribute name up-front via `cow_to_ascii_lowercase()` purely to test
the `aria-`
prefix:

```rust
let name = get_jsx_attribute_name(&attr.name);
let name = name.cow_to_ascii_lowercase(); // allocates for camelCase names
if name.starts_with("aria-") && ... { ... }
```

`cow_to_ascii_lowercase()` allocates a fresh `String` whenever the name
contains an
uppercase byte — i.e. for the very common camelCase attributes
(`className`,
`onClick`, `onChange`, `tabIndex`, …) that are then discarded because
they are not
`aria-*`.

This gates on the prefix first with the allocation-free
`oxc_linter::utils::starts_with_ignore_case` (the helper introduced in
#23861), and
only lowercases for the rare attribute that actually is `aria-*` — which
still needs
the lowercased form for the property lookup and the diagnostic message.

## Correctness

Behavior-preserving:

- The new `starts_with_ignore_case(name, "aria-")` gate matches exactly
the same
names the old `cow_to_ascii_lowercase().starts_with("aria-")` did (both
are
  ASCII-case-insensitive over the 5-byte prefix).
- For matched `aria-*` attributes the name is still lowercased before
the
`is_valid_aria_property` / `AriaProperty::try_from` lookup and before
being passed
  to the diagnostic, so emitted diagnostics are byte-identical.
- Non-`aria-*` attributes never produced a diagnostic and still don't.

The full pass/fail/fix suites and snapshots for both rules are
unchanged.

## Measurement

Predicate microbench over a realistic 39-name JSX attribute distribution
(mostly
non-`aria-*`, several camelCase), release + LTO:

| prefix check | per scan (39 attrs) |
| --- | --- |
| `cow_to_ascii_lowercase().starts_with("aria-")` | 329.9 ns |
| `starts_with_ignore_case(name, "aria-")` | 40.6 ns |

~8x on the prefix check, from removing the per-attribute allocation. The
corpus-level impact is for CI CodSpeed to quantify; this is the same
allocation-free
pattern as the merged #23861.

---

_Disclosure: developed with AI assistance (Claude), reviewed and
verified by the author._

Co-authored-by: Cameron <cameron.clark@hey.com>
camc314 added a commit that referenced this pull request Jun 29, 2026
# Oxlint
### 💥 BREAKING CHANGES

- 88f4455 str: [**BREAKING**] `Str` and `Ident` methods take
`&GetAllocator` (#23781) (overlookmotel)

### 🚀 Features

- f2091b3 ast: Unify old and new `AstBuilder`s (#23875) (overlookmotel)
- 1c8f50c linter: Add schema for `eslint/no-restricted-import` (#23642)
(Sysix)

### 🐛 Bug Fixes

- 7cb85c4 linter/eslint/no-negated-condition: Add autofix for negated
conditions (#23825) (Yagiz Nizipli)
- f7d1f50 oxlint, oxfmt: Enable `disable_old_builder` Cargo feature for
`oxc_ast` crate (#23886) (overlookmotel)
- d891990 linter/jsx-a11y/role-supports-aria-props: Ignore nullish prop
values (#23865) (Mikhail Baev)
- 94b6599 linter: Deduplicate missing plugin errors (#23853) (camc314)
- eff3eff linter/oxc/branches-sharing-code: Avoid else-if false
positives (#23843) (camc314)
- 2a2d3b9 linter/eslint/prefer-destructuring: Skip
`AssignmentExpression` autofixes (#23818) (camc314)
- ddc24ae linter/eslint/id-length: Respect checkGeneric for mapped type
keys (#23802) (bab)
- cd89202 linter/react/exhaustive-deps: Skip wrapper expression when
analyzing hook initializers (#23793) (camc314)
- 20e8285 linter/unicorn/prefer-native-coercion-function: Allow ts type
predicates (#23774) (camc314)
- d86f60b lsp: Normalize user config path to watch pattern (#23723)
(Sysix)
- 52032cf linter: Newline-terminate tsgolint errors (#23762) (Mikhail
Baev)
- 368fda7 linter/eslint/no-warning-comments: Avoid dropping generated
regex patterns (#23741) (camc314)
- ce44fbd linter/valid-title: Escape disallowed words regex (#23742)
(camc314)
- 3100d11 linter/prefer-called-exactly-once-with: Avoid out-of-bounds
slice panic at end of file (#23625) (Jerry Zhao)
- 742be36 refactor/node/handle-callback-err: Reject invalid regex config
(#23740) (camc314)
- d7be179 linter/eslint/no-restricted-globals: Handle shadowed locals
(#23736) (camc314)
- b3b1ff8 linter/vitest/expect-expect: Handle global vitest detection
correctly (#23734) (camc314)

### ⚡ Performance

- 68f9472 linter/jsx-a11y: Skip lowercasing non-aria attribute names
(#23906) (Lawrence Lin)
- b9312b4 linter/unicorn/prefer-export-from: Use keyed binding lookup
(#23893) (Marius Schulz)
- cd5204e linter/typescript/no-unsafe-declaration-merging: Use keyed
binding lookup (#23894) (Marius Schulz)
- e948498 linter/eslint/prefer-named-capture-group: Only dispatch for
relevant node types (#23868) (Connor Shea)
- 4ac7a8e linter/eslint/max-depth: Derive node types (#23896) (Connor
Shea)
- daeed09 linter/eslint/no-restricted-globals: Only scan unresolved
references (#23890) (camc314)
- e808514 linter/jest-vitest: Speed up no-standalone-expect (#23883)
(camc314)
- 8b165e5 linter/react/exhaustive-deps: Skip non-reactive calls early
(#23882) (camc314)
- 54005e7 linter/eslint/no-unused-vars: Precompute exported bindings
(#23881) (camc314)
- 9bc2f8c linter/unicorn/prefer-number-properties: Speed up global
checks (#23880) (camc314)
- 4ff104f linter: Optimize `require-hook` and `prefer-mock-*` rules to
run on specific node types (#23871) (Connor Shea)
- cc2213b linter: Run `no-underscore-dangle` only when relevant node
types are present (#23867) (Connor Shea)
- 3e55c21 linter/promise/always-return: Narrow to function node types
(#23878) (Connor Shea)
- 7136182 linter/jest-vitest: Speed up no-commented-out-tests (#23864)
(camc314)
- f138264 linter/eslint/no-script-url: Match javascript: prefix without
allocating (#23861) (Lawrence Lin)
- 7ef6895 linter/react/no-array-index-key: Delay index symbol lookup
(#23857) (camc314)
- 26bc171 linter/react/no-array-index-key: Match callback methods
directly (#23856) (camc314)
- 44fbbda linter/jsx-a11y/interactive-supports-focus: Check cheap
conditions first (#23854) (camc314)
- 84a5aa3 linter/eslint/no-extend-native: Skip lowercase references
early (#23851) (camc314)
- 88a74b2 linter/eslint/no-nonoctal-decimal-escape: Scan decimal escapes
as bytes (#23850) (camc314)
- fca69a8 linter: Skip traversal without this expressions (#23845)
(camc314)
- 838fd63 linter: Reduce preallocation for per-file diagnostics `Vec`
(#23705) (Marius Schulz)
- 417b506 linter/typescript/array-type: Remove full source text clone
(#23751) (Marius Schulz)

### 📚 Documentation

- 57e4469 linter/unicorn: Update prefer-dom-node-text-content rationale
(#23933) (Mikhail Baev)
- 3d61dea all: Correct capitalization in comments (#23887)
(overlookmotel)

### 🛡️ Security

- 3cdd18f deps: Update npm packages (#23690) (renovate[bot])
# Oxfmt
### 💥 BREAKING CHANGES

- 259e0cd oxfmt,formatter_graphql: [**BREAKING**] Support draft syntax
with removing prettier fallback (#23326) (leaysgur)
- accbc49 oxfmt: [**BREAKING**] Format `parser:css,less,scss` files +
css-in-js by `oxc_formatter_css` (#23321) (leaysgur)

### 🚀 Features

- dffa4b3 formatter_css: Implement `oxc_formatter_css` (#23320)
(leaysgur)
- 01de9ec oxfmt: Format `parser:graphql` files by
`oxc_formatter_graphql` (#23318) (leaysgur)
- 4e66212 formatter_graphql: Implement oxc_formatter_graphql (#23317)
(leaysgur)

### 🐛 Bug Fixes

- 67325ae formatter_css: Handle frontmatter language (#23819) (leaysgur)
- 3f355e5 formatter_graphql: Improve major prettier diffs (#23419)
(leaysgur)
- 48e2d78 formatter_css: Improve major prettier diffs (#23327)
(leaysgur)
- 8c07cad all: Enable `disable_old_builder` Cargo feature for `oxc_ast`
crate in tests (#23888) (overlookmotel)
- f7d1f50 oxlint, oxfmt: Enable `disable_old_builder` Cargo feature for
`oxc_ast` crate (#23886) (overlookmotel)
- d86f60b lsp: Normalize user config path to watch pattern (#23723)
(Sysix)

### ⚡ Performance

- 4ddcba0 formatter_core: Add printable-ASCII fast path to TextWidth
(#23913) (Lawrence Lin)

### 📚 Documentation

- b4d0dc9 oxfmt,formatter,formatter_css,formatter_core: Update AGENTS.md
(#23814) (leaysgur)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
camc314 added a commit that referenced this pull request Jul 3, 2026
…llocating (#23861)

## What

`NoScriptUrl::run` fires on every `StringLiteral` and `TemplateLiteral`.
The guard
used `value.cow_to_ascii_lowercase().starts_with("javascript:")`, which
scans the
whole value to detect any ASCII uppercase and heap-allocates a
lowercased copy
whenever one is present — all to compare an 11-byte prefix.

`"javascript:"` is ASCII, so ASCII-lowercasing never changes byte length
and only
the first 11 bytes can affect the match. This replaces the check with an
allocation-free `is_javascript_url` helper that compares the first 11
bytes with
`eq_ignore_ascii_case`, shared by both the string- and template-literal
arms.

## Correctness

Output is unchanged.
`s.cow_to_ascii_lowercase().starts_with("javascript:")` is true
iff `s.len() >= 11` and
`s.as_bytes()[..11].eq_ignore_ascii_case(b"javascript:")`
(ASCII-lowercasing is length-preserving, and a non-ASCII byte in the
first 11 fails
both forms). The rule's snapshot test is unchanged.

## Perf

Predicate microbench over a realistic literal mix (lowercase,
PascalCase, long
messages with uppercase, and actual `javascript:` matches), with
identical boolean
results both ways:

| check | ns/call |
| --- | --- |
| `cow_to_ascii_lowercase().starts_with(..)` | 15.5 |
| `is_javascript_url` (this PR) | 1.0 |

The gain is the removed heap allocation for uppercase-containing strings
plus an
O(11) prefix compare instead of an O(len) scan. CodSpeed will capture
the aggregate
effect on the linter benchmark.

---

_Disclosure: developed with AI assistance (Claude), reviewed and
verified by the author._

---------

Co-authored-by: Cameron <cameron.clark@hey.com>
camc314 added a commit that referenced this pull request Jul 3, 2026
)

## What

`aria-props` and `aria-proptypes` run on every `JSXAttribute`. Both
lowercased the
attribute name up-front via `cow_to_ascii_lowercase()` purely to test
the `aria-`
prefix:

```rust
let name = get_jsx_attribute_name(&attr.name);
let name = name.cow_to_ascii_lowercase(); // allocates for camelCase names
if name.starts_with("aria-") && ... { ... }
```

`cow_to_ascii_lowercase()` allocates a fresh `String` whenever the name
contains an
uppercase byte — i.e. for the very common camelCase attributes
(`className`,
`onClick`, `onChange`, `tabIndex`, …) that are then discarded because
they are not
`aria-*`.

This gates on the prefix first with the allocation-free
`oxc_linter::utils::starts_with_ignore_case` (the helper introduced in
#23861), and
only lowercases for the rare attribute that actually is `aria-*` — which
still needs
the lowercased form for the property lookup and the diagnostic message.

## Correctness

Behavior-preserving:

- The new `starts_with_ignore_case(name, "aria-")` gate matches exactly
the same
names the old `cow_to_ascii_lowercase().starts_with("aria-")` did (both
are
  ASCII-case-insensitive over the 5-byte prefix).
- For matched `aria-*` attributes the name is still lowercased before
the
`is_valid_aria_property` / `AriaProperty::try_from` lookup and before
being passed
  to the diagnostic, so emitted diagnostics are byte-identical.
- Non-`aria-*` attributes never produced a diagnostic and still don't.

The full pass/fail/fix suites and snapshots for both rules are
unchanged.

## Measurement

Predicate microbench over a realistic 39-name JSX attribute distribution
(mostly
non-`aria-*`, several camelCase), release + LTO:

| prefix check | per scan (39 attrs) |
| --- | --- |
| `cow_to_ascii_lowercase().starts_with("aria-")` | 329.9 ns |
| `starts_with_ignore_case(name, "aria-")` | 40.6 ns |

~8x on the prefix check, from removing the per-attribute allocation. The
corpus-level impact is for CI CodSpeed to quantify; this is the same
allocation-free
pattern as the merged #23861.

---

_Disclosure: developed with AI assistance (Claude), reviewed and
verified by the author._

Co-authored-by: Cameron <cameron.clark@hey.com>
camc314 added a commit that referenced this pull request Jul 3, 2026
# Oxlint
### 💥 BREAKING CHANGES

- 88f4455 str: [**BREAKING**] `Str` and `Ident` methods take
`&GetAllocator` (#23781) (overlookmotel)

### 🚀 Features

- f2091b3 ast: Unify old and new `AstBuilder`s (#23875) (overlookmotel)
- 1c8f50c linter: Add schema for `eslint/no-restricted-import` (#23642)
(Sysix)

### 🐛 Bug Fixes

- 7cb85c4 linter/eslint/no-negated-condition: Add autofix for negated
conditions (#23825) (Yagiz Nizipli)
- f7d1f50 oxlint, oxfmt: Enable `disable_old_builder` Cargo feature for
`oxc_ast` crate (#23886) (overlookmotel)
- d891990 linter/jsx-a11y/role-supports-aria-props: Ignore nullish prop
values (#23865) (Mikhail Baev)
- 94b6599 linter: Deduplicate missing plugin errors (#23853) (camc314)
- eff3eff linter/oxc/branches-sharing-code: Avoid else-if false
positives (#23843) (camc314)
- 2a2d3b9 linter/eslint/prefer-destructuring: Skip
`AssignmentExpression` autofixes (#23818) (camc314)
- ddc24ae linter/eslint/id-length: Respect checkGeneric for mapped type
keys (#23802) (bab)
- cd89202 linter/react/exhaustive-deps: Skip wrapper expression when
analyzing hook initializers (#23793) (camc314)
- 20e8285 linter/unicorn/prefer-native-coercion-function: Allow ts type
predicates (#23774) (camc314)
- d86f60b lsp: Normalize user config path to watch pattern (#23723)
(Sysix)
- 52032cf linter: Newline-terminate tsgolint errors (#23762) (Mikhail
Baev)
- 368fda7 linter/eslint/no-warning-comments: Avoid dropping generated
regex patterns (#23741) (camc314)
- ce44fbd linter/valid-title: Escape disallowed words regex (#23742)
(camc314)
- 3100d11 linter/prefer-called-exactly-once-with: Avoid out-of-bounds
slice panic at end of file (#23625) (Jerry Zhao)
- 742be36 refactor/node/handle-callback-err: Reject invalid regex config
(#23740) (camc314)
- d7be179 linter/eslint/no-restricted-globals: Handle shadowed locals
(#23736) (camc314)
- b3b1ff8 linter/vitest/expect-expect: Handle global vitest detection
correctly (#23734) (camc314)

### ⚡ Performance

- 68f9472 linter/jsx-a11y: Skip lowercasing non-aria attribute names
(#23906) (Lawrence Lin)
- b9312b4 linter/unicorn/prefer-export-from: Use keyed binding lookup
(#23893) (Marius Schulz)
- cd5204e linter/typescript/no-unsafe-declaration-merging: Use keyed
binding lookup (#23894) (Marius Schulz)
- e948498 linter/eslint/prefer-named-capture-group: Only dispatch for
relevant node types (#23868) (Connor Shea)
- 4ac7a8e linter/eslint/max-depth: Derive node types (#23896) (Connor
Shea)
- daeed09 linter/eslint/no-restricted-globals: Only scan unresolved
references (#23890) (camc314)
- e808514 linter/jest-vitest: Speed up no-standalone-expect (#23883)
(camc314)
- 8b165e5 linter/react/exhaustive-deps: Skip non-reactive calls early
(#23882) (camc314)
- 54005e7 linter/eslint/no-unused-vars: Precompute exported bindings
(#23881) (camc314)
- 9bc2f8c linter/unicorn/prefer-number-properties: Speed up global
checks (#23880) (camc314)
- 4ff104f linter: Optimize `require-hook` and `prefer-mock-*` rules to
run on specific node types (#23871) (Connor Shea)
- cc2213b linter: Run `no-underscore-dangle` only when relevant node
types are present (#23867) (Connor Shea)
- 3e55c21 linter/promise/always-return: Narrow to function node types
(#23878) (Connor Shea)
- 7136182 linter/jest-vitest: Speed up no-commented-out-tests (#23864)
(camc314)
- f138264 linter/eslint/no-script-url: Match javascript: prefix without
allocating (#23861) (Lawrence Lin)
- 7ef6895 linter/react/no-array-index-key: Delay index symbol lookup
(#23857) (camc314)
- 26bc171 linter/react/no-array-index-key: Match callback methods
directly (#23856) (camc314)
- 44fbbda linter/jsx-a11y/interactive-supports-focus: Check cheap
conditions first (#23854) (camc314)
- 84a5aa3 linter/eslint/no-extend-native: Skip lowercase references
early (#23851) (camc314)
- 88a74b2 linter/eslint/no-nonoctal-decimal-escape: Scan decimal escapes
as bytes (#23850) (camc314)
- fca69a8 linter: Skip traversal without this expressions (#23845)
(camc314)
- 838fd63 linter: Reduce preallocation for per-file diagnostics `Vec`
(#23705) (Marius Schulz)
- 417b506 linter/typescript/array-type: Remove full source text clone
(#23751) (Marius Schulz)

### 📚 Documentation

- 57e4469 linter/unicorn: Update prefer-dom-node-text-content rationale
(#23933) (Mikhail Baev)
- 3d61dea all: Correct capitalization in comments (#23887)
(overlookmotel)

### 🛡️ Security

- 3cdd18f deps: Update npm packages (#23690) (renovate[bot])
# Oxfmt
### 💥 BREAKING CHANGES

- 259e0cd oxfmt,formatter_graphql: [**BREAKING**] Support draft syntax
with removing prettier fallback (#23326) (leaysgur)
- accbc49 oxfmt: [**BREAKING**] Format `parser:css,less,scss` files +
css-in-js by `oxc_formatter_css` (#23321) (leaysgur)

### 🚀 Features

- dffa4b3 formatter_css: Implement `oxc_formatter_css` (#23320)
(leaysgur)
- 01de9ec oxfmt: Format `parser:graphql` files by
`oxc_formatter_graphql` (#23318) (leaysgur)
- 4e66212 formatter_graphql: Implement oxc_formatter_graphql (#23317)
(leaysgur)

### 🐛 Bug Fixes

- 67325ae formatter_css: Handle frontmatter language (#23819) (leaysgur)
- 3f355e5 formatter_graphql: Improve major prettier diffs (#23419)
(leaysgur)
- 48e2d78 formatter_css: Improve major prettier diffs (#23327)
(leaysgur)
- 8c07cad all: Enable `disable_old_builder` Cargo feature for `oxc_ast`
crate in tests (#23888) (overlookmotel)
- f7d1f50 oxlint, oxfmt: Enable `disable_old_builder` Cargo feature for
`oxc_ast` crate (#23886) (overlookmotel)
- d86f60b lsp: Normalize user config path to watch pattern (#23723)
(Sysix)

### ⚡ Performance

- 4ddcba0 formatter_core: Add printable-ASCII fast path to TextWidth
(#23913) (Lawrence Lin)

### 📚 Documentation

- b4d0dc9 oxfmt,formatter,formatter_css,formatter_core: Update AGENTS.md
(#23814) (leaysgur)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-linter Area - Linter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants