Skip to content

fix(template-no-invalid-aria-attributes): absorb allowundefined handling into validateByType#49

Merged
johanrd merged 2 commits intomasterfrom
fix/aria-orientation-undefined-token
Apr 25, 2026
Merged

fix(template-no-invalid-aria-attributes): absorb allowundefined handling into validateByType#49
johanrd merged 2 commits intomasterfrom
fix/aria-orientation-undefined-token

Conversation

@johanrd
Copy link
Copy Markdown
Owner

@johanrd johanrd commented Apr 22, 2026

[Mirror of ember-cli#2723 for Copilot review]

Note

This is part of a series where Claude has audited eslint-plugin-ember against jsx-a11y, vuejs-accessibility, angular-eslint, lit-a11y and html-validate, ember-template-lint, and the HTML and WCAG specs.

This PR is part of a broader a11y parity audit comparing our rules against jsx-a11y, vue-a11y, angular-eslint-template, and lit-a11y.

Premise

Per aria-query 5.3.2, a handful of ARIA attributes accept the literal string "undefined" as a spec-valid value:

attr aria-query type / allowundefined spec basis
aria-orientation token / (unset) with 'undefined' in values list WAI-ARIA 1.2 §aria-orientation: `vertical
aria-expanded boolean / true §aria-expanded: `true
aria-hidden boolean / true §aria-hidden: `true
aria-grabbed boolean / true §aria-grabbed
aria-selected boolean / true §aria-selected

Two orthogonal encodings: token with 'undefined' in values (aria-orientation) and boolean with allowundefined: true (the other four). Both should produce "accept the string 'undefined'"; neither is the user's fault to write.

Problem

The pre-fix isValidAriaValue had a clunky two-layer structure:

if (value === 'undefined' && isTokenWithUndefinedInValues) return true;   // precheck
if (value === 'undefined') return Boolean(attrDef.allowundefined);        // short-circuit
return validateByType(...);

The precheck was a late patch that landed because aria-orientation="undefined" (the token case) was falsely rejected by the short-circuit. The short-circuit itself exists for the 4 boolean-type attrs. So validation was split across three locations for one attribute.

Fix

Absorb allowundefined handling directly into validateByType via a single helper allowsUndefinedLiteral(attrDef, value). The token-values check in the 'token' case naturally handles aria-orientation="undefined" without any special-casing. isValidAriaValue becomes a thin dispatcher to validateByType.

function allowsUndefinedLiteral(attrDef, value) {
  return value === 'undefined' && Boolean(attrDef.allowundefined);
}

function validateByType(attrDef, value) {
  if (allowsUndefinedLiteral(attrDef, value)) return true;
  switch (attrDef.type) {
    // 'token' case accepts 'undefined' naturally via the values list for aria-orientation
    // 'boolean' case rejects string 'undefined' (the allowundefined branch above handles the allowed cases)
    // ...
  }
}

Behavior — unchanged outcomes, cleaner structure

Input Before After
aria-orientation="undefined" ✅ accepted (via precheck) ✅ accepted (via token values list)
aria-expanded="undefined" ✅ accepted (via short-circuit) ✅ accepted (via allowsUndefinedLiteral)
aria-hidden="undefined" ✅ accepted ✅ accepted
aria-grabbed="undefined" ✅ accepted ✅ accepted
aria-selected="undefined" ✅ accepted ✅ accepted
aria-pressed="undefined" ❌ rejected (no allowundefined, no 'undefined' in values) ❌ rejected
aria-orientation="sideways" ❌ rejected ❌ rejected

Prior art — peers don't handle the 4 boolean+allowundefined attrs correctly

Verified each peer in source:

Plugin Rule Behavior on aria-expanded="undefined"
jsx-a11y aria-proptypes validityCheck('boolean', value) is typeof value === 'boolean'; string "undefined" fails. allowUndefined && value === undefined only fires on JS undefined, not the string — and is effectively dead code because jsx-a11y reads attributes.allowUndefined (camelCase) but aria-query emits allowundefined (lowercase). Rejects the string.
lit-a11y aria-attr-valid-value Same structure as jsx-a11y. allowundefined lowercase matches aria-query correctly, but still only triggers on JS undefined. Rejects the string.
@angular-eslint/template valid-aria if (allowundefined && isNil(attributeValue)) return true;allowundefined only triggers on null/undefined, not the string. Rejects the string.
vuejs-accessibility aria-props Does NOT validate token values at all — rule only checks aria.has(name). Trivially accepts the string (by not checking).

So of the four peers, three reject a spec-valid construct, one doesn't check values at all. This PR makes our rule more spec-compliant than the three value-validating peers on these 4 attrs.

Note — case-insensitivity gap (out of scope)

jsx-a11y and lit-a11y lowercase the value before the token check (permittedValues.indexOf(value.toLowerCase()) > -1). Our rule does NOT lowercase; a case-variant like aria-orientation="UNDEFINED" or "Horizontal" would still fail here even after this PR. Same class of HTML-enumerated-attribute case-insensitivity gap as ember-cli#2718 (kind="captions") and ember-cli#2728 (role tokens). Worth a follow-up PR; explicitly out of scope for this narrow change.

Tests

  • Valid: aria-orientation="undefined" / "horizontal", aria-expanded="undefined", aria-hidden="undefined", aria-grabbed="undefined", aria-selected="undefined", aria-pressed="true" / "false" / "mixed".
  • Invalid: aria-orientation="sideways", aria-pressed="undefined" (no allowundefined), aria-required="undefined" (boolean without allowundefined — pre-existing test).

…ing into validateByType

Removes the top-level string-"undefined" short-circuit in `isValidAriaValue`
(previously a two-layer dance: a token-type precheck then a boolean-ish
short-circuit). Absorbs the `allowundefined` handling directly into
`validateByType` via a new `allowsUndefinedLiteral(attrDef, value)` helper
that honors aria-query's convention for the 4 boolean-type attrs that
encode "string 'undefined' is spec-valid": aria-expanded, aria-hidden,
aria-grabbed, aria-selected.

## Before/after — same outcome, cleaner structure

| Attribute | aria-query type / allowundefined | `"undefined"` string accepted? |
|---|---|---|
| aria-orientation | token / (unset) with `'undefined'` in values | yes — via token-values check |
| aria-expanded | boolean / true | yes — via allowundefined |
| aria-hidden | boolean / true | yes — via allowundefined |
| aria-grabbed | boolean / true | yes — via allowundefined |
| aria-selected | boolean / true | yes — via allowundefined |
| aria-pressed | tristate / (unset) | NO — no allowundefined flag |
| aria-checked | tristate / (unset) | NO — no allowundefined flag |

All behavior preserved; just structured so that validity decisions
happen in one place.

## Why keep the allowundefined path at all

The 4 boolean-type attrs with `allowundefined: true` have spec-valid
`"undefined"` values per WAI-ARIA 1.2 (e.g. aria-expanded accepts
true/false/undefined). aria-query encodes this. Peers (jsx-a11y,
lit-a11y, angular-eslint) effectively reject `aria-expanded="undefined"`
because their `allowundefined` branch only fires on JS undefined, not
the string. That's a peer bug; our path keeps us spec-compliant.

Tests added for each of the 4 allowundefined attrs; new negative test
for `aria-pressed="undefined"` (tristate without allowundefined) pins
the correct rejection path.
@johanrd johanrd requested a review from Copilot April 22, 2026 10:41
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 22, 2026

🏎️ Benchmark Comparison

Benchmark Control (p50) Experiment (p50) Δ
🟢 js small 13.74 ms 12.81 ms -6.8%
js medium 6.33 ms 6.28 ms -0.8%
🟢 js large 2.48 ms 2.41 ms -2.7%
gjs small 1.16 ms 1.16 ms -0.0%
gjs medium 589.56 µs 585.23 µs -0.7%
gjs large 230.07 µs 231.02 µs +0.4%
gts small 1.18 ms 1.17 ms -1.0%
gts medium 587.13 µs 582.74 µs -0.7%
gts large 231.31 µs 232.68 µs +0.6%

🟢 faster · 🔴 slower · 🟠 slightly slower · ⚪ within 2%

Full mitata output
clk: ~3.34 GHz
cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
runtime: node 24.14.1 (x64-linux)

benchmark                   avg (min … max) p75 / p99    (min … top 1%)
------------------------------------------- -------------------------------
js small (control)            15.85 ms/iter  17.24 ms █ ▂                  
                      (11.03 ms … 31.00 ms)  27.56 ms █▂█▂                 
                    (  5.65 mb …  10.30 mb)   7.20 mb ████▇▇▇▇▇▇▁▁▄▄▁▁▁▁▇▄▄

js small (experiment)         13.34 ms/iter  14.08 ms   █                  
                      (11.42 ms … 20.27 ms)  17.94 ms █ █ ▃█  ▃            
                    (  6.70 mb …   7.85 mb)   6.83 mb ███▆██▄▄█▄▄▆▄▄▁▁▄▁▁▁▆

                             ┌                                            ┐
                             ╷  ┌─────────┬───┐                           ╷
          js small (control) ├──┤         │   ├───────────────────────────┤
                             ╵  └─────────┴───┘                           ╵
                              ╷ ┌──┬─┐          ╷
       js small (experiment)  ├─┤  │ ├──────────┤
                              ╵ └──┴─┘          ╵
                             └                                            ┘
                             11.03 ms           19.30 ms           27.56 ms

summary
  js small (experiment)
   1.19x faster than js small (control)

------------------------------------------- -------------------------------
js medium (control)            7.10 ms/iter   7.27 ms  █                   
                       (5.88 ms … 13.77 ms)  13.64 ms ▆█                   
                    (  3.00 mb …   4.38 mb)   3.53 mb ███▃▄▄▂▄▁▂▁▄▂▂▁▁▂▁▁▁▂

js medium (experiment)         6.99 ms/iter   7.00 ms  █                   
                       (5.89 ms … 15.18 ms)  11.89 ms  █                   
                    (  2.78 mb …   4.03 mb)   3.51 mb ███▄▃▁▃▂▃▃▁▂▁▂▁▂▂▁▂▂▂

                             ┌                                            ┐
                             ╷ ┌────┬┐                                    ╷
         js medium (control) ├─┤    │├────────────────────────────────────┤
                             ╵ └────┴┘                                    ╵
                             ╷┌────┬                            ╷
      js medium (experiment) ├┤    │────────────────────────────┤
                             ╵└────┴                            ╵
                             └                                            ┘
                             5.88 ms            9.76 ms            13.64 ms

summary
  js medium (experiment)
   1.02x faster than js medium (control)

------------------------------------------- -------------------------------
js large (control)             2.93 ms/iter   2.97 ms █▆                   
                       (2.17 ms … 10.83 ms)   7.29 ms ██                   
                    (284.78 kb …   2.90 mb)   1.43 mb ███▅▄▃▄▂▂▁▁▂▂▂▂▁▁▁▂▁▂

js large (experiment)          2.68 ms/iter   2.51 ms ▄█                   
                        (2.29 ms … 7.04 ms)   5.73 ms ██                   
                    (415.67 kb …   2.78 mb)   1.43 mb ██▄▃▂▂▂▂▂▁▂▂▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ╷┌─────┬                                     ╷
          js large (control) ├┤     │─────────────────────────────────────┤
                             ╵└─────┴                                     ╵
                              ╷┌──┬                         ╷
       js large (experiment)  ├┤  │─────────────────────────┤
                              ╵└──┴                         ╵
                             └                                            ┘
                             2.17 ms            4.73 ms             7.29 ms

summary
  js large (experiment)
   1.09x faster than js large (control)

------------------------------------------- -------------------------------
gjs small (control)            1.30 ms/iter   1.22 ms █                    
                        (1.13 ms … 6.38 ms)   5.42 ms █                    
                    (537.34 kb …   1.60 mb)   1.06 mb █▅▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gjs small (experiment)         1.29 ms/iter   1.22 ms █                    
                        (1.13 ms … 6.36 ms)   5.31 ms █                    
                    (190.80 kb …   1.94 mb)   1.06 mb █▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌─┬                                          ╷
         gjs small (control) │ │──────────────────────────────────────────┤
                             └─┴                                          ╵
                             ┌─┬                                         ╷
      gjs small (experiment) │ │─────────────────────────────────────────┤
                             └─┴                                         ╵
                             └                                            ┘
                             1.13 ms            3.27 ms             5.42 ms

summary
  gjs small (experiment)
   1.01x faster than gjs small (control)

------------------------------------------- -------------------------------
gjs medium (control)         648.92 µs/iter 609.75 µs █                    
                      (559.63 µs … 6.46 ms)   3.16 ms █                    
                    ( 37.88 kb …   1.38 mb) 541.79 kb █▅▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gjs medium (experiment)      640.67 µs/iter 611.53 µs █▄                   
                      (553.81 µs … 6.64 ms)   1.83 ms ██                   
                    (258.94 kb …   1.11 mb) 540.77 kb ██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌─┬                                          ╷
        gjs medium (control) │ │──────────────────────────────────────────┤
                             └─┴                                          ╵
                             ┌┬                    ╷
     gjs medium (experiment) ││────────────────────┤
                             └┴                    ╵
                             └                                            ┘
                             553.81 µs           1.86 ms            3.16 ms

summary
  gjs medium (experiment)
   1.01x faster than gjs medium (control)

------------------------------------------- -------------------------------
gjs large (control)          255.69 µs/iter 243.71 µs  █▃                  
                      (220.74 µs … 5.84 ms) 321.22 µs  ██  ▂               
                    (162.91 kb … 802.68 kb) 217.19 kb ▇██▅▆█▆▂▂▂▂▁▁▁▁▁▁▁▁▁▁

gjs large (experiment)       255.16 µs/iter 246.76 µs  █                   
                      (221.82 µs … 5.07 ms) 374.16 µs ▅█ ▄                 
                    (170.20 kb …   1.07 mb) 216.68 kb ██▆█▇▃▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ╷┌────────┬                  ╷
         gjs large (control) ├┤        │──────────────────┤
                             ╵└────────┴                  ╵
                             ╷ ┌───────┬                                  ╷
      gjs large (experiment) ├─┤       │──────────────────────────────────┤
                             ╵ └───────┴                                  ╵
                             └                                            ┘
                             220.74 µs         297.45 µs          374.16 µs

summary
  gjs large (experiment)
   1x faster than gjs large (control)

------------------------------------------- -------------------------------
gts small (control)            1.32 ms/iter   1.26 ms █                    
                        (1.14 ms … 6.43 ms)   5.20 ms █▂                   
                    (468.09 kb …   1.66 mb)   1.06 mb ██▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gts small (experiment)         1.27 ms/iter   1.20 ms █                    
                        (1.14 ms … 6.41 ms)   5.35 ms █                    
                    ( 10.84 kb …   2.12 mb)   1.05 mb █▅▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌─┬                                        ╷
         gts small (control) │ │────────────────────────────────────────┤
                             └─┴                                        ╵
                             ┌┬                                           ╷
      gts small (experiment) ││───────────────────────────────────────────┤
                             └┴                                           ╵
                             └                                            ┘
                             1.14 ms            3.24 ms             5.35 ms

summary
  gts small (experiment)
   1.03x faster than gts small (control)

------------------------------------------- -------------------------------
gts medium (control)         638.16 µs/iter 607.50 µs  █                   
                      (558.80 µs … 5.69 ms)   1.33 ms ▅█                   
                    (217.95 kb …   1.81 mb) 542.11 kb ███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gts medium (experiment)      633.57 µs/iter 594.67 µs ▃█                   
                      (556.38 µs … 5.71 ms)   1.45 ms ██                   
                    ( 86.27 kb …   1.28 mb) 540.90 kb ██▆▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ╷┌──┬                                  ╷
        gts medium (control) ├┤  │──────────────────────────────────┤
                             ╵└──┴                                  ╵
                             ╷┌──┬                                        ╷
     gts medium (experiment) ├┤  │────────────────────────────────────────┤
                             ╵└──┴                                        ╵
                             └                                            ┘
                             556.38 µs           1.00 ms            1.45 ms

summary
  gts medium (experiment)
   1.01x faster than gts medium (control)

------------------------------------------- -------------------------------
gts large (control)          257.36 µs/iter 245.29 µs  █▅                  
                      (221.53 µs … 5.76 ms) 306.56 µs  ██  ▃▃              
                    ( 80.80 kb …   1.17 mb) 217.14 kb ▄██▆▄██▆▃▃▃▂▂▁▁▁▁▁▁▁▁

gts large (experiment)       257.35 µs/iter 247.84 µs  █                   
                      (222.92 µs … 5.41 ms) 315.35 µs  █▅  ▃               
                    (170.17 kb … 953.02 kb) 216.71 kb ▅██▄▆██▃▃▃▂▂▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ╷  ┌─────────────┬                       ╷
         gts large (control) ├──┤             │───────────────────────┤
                             ╵  └─────────────┴                       ╵
                              ╷ ┌─────────────┬                           ╷
      gts large (experiment)  ├─┤             │───────────────────────────┤
                              ╵ └─────────────┴                           ╵
                             └                                            ┘
                             221.53 µs         268.44 µs          315.35 µs

summary
  gts large (experiment)
   1x faster than gts large (control)

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Refactors ARIA attribute value validation so the literal string "undefined" is handled in a single place (validateByType) via a helper, improving spec-compliance and simplifying control flow.

Changes:

  • Introduces allowsUndefinedLiteral() and moves allowundefined handling into validateByType().
  • Simplifies isValidAriaValue() into a thin dispatcher to validateByType().
  • Expands rule tests to cover boolean allowundefined attributes and aria-orientation’s token-values behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
lib/rules/template-no-invalid-aria-attributes.js Centralizes "undefined" literal handling in type validation and simplifies isValidAriaValue.
tests/lib/rules/template-no-invalid-aria-attributes.js Adds valid/invalid fixtures for "undefined" across relevant ARIA attrs and for invalid aria-orientation values.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/lib/rules/template-no-invalid-aria-attributes.js
Comment thread lib/rules/template-no-invalid-aria-attributes.js Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

lib/rules/template-no-invalid-aria-attributes.js:33

  • For attributes where attrDef.allowundefined is true, validation now accepts the literal string "undefined", but the reported expectedType (via getExpectedTypeDescription) will still describe these as just "a boolean". This can produce a misleading error message for other invalid values (e.g. aria-expanded="foo"). Consider updating getExpectedTypeDescription to include "undefined" as an allowed literal when allowundefined is set, so the message matches the actual accepted values.
// In aria-query 5.3.2, `allowundefined: true` is set only on the four
// boolean-like ARIA state attributes — `aria-expanded`, `aria-hidden`,
// `aria-grabbed`, `aria-selected` — whose WAI-ARIA 1.2 value tables list
// the literal string `"undefined"` as a spec-valid value meaning "state
// is not applicable" (e.g. https://www.w3.org/TR/wai-aria-1.2/#aria-expanded).
// The flag is nominally type-agnostic, but in practice this function only
// green-lights `"undefined"` for that boolean-like subset; no non-boolean
// ARIA attribute in aria-query currently sets `allowundefined`.
function allowsUndefinedLiteral(attrDef, value) {
  return value === 'undefined' && Boolean(attrDef.allowundefined);
}

function validateByType(attrDef, value) {
  if (allowsUndefinedLiteral(attrDef, value)) {
    return true;
  }
  switch (attrDef.type) {
    case 'boolean': {
      return isBoolean(value);
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +71 to +77
function isValidAriaValue(attrName, value) {
const attrDef = aria.get(attrName);
if (!attrDef) {
return true;
}
return validateByType(attrDef, value);
}
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

Since the rule now explicitly accepts the string "undefined" for attributes where attrDef.allowundefined is true, the error message shown for other invalid values of those attributes (via getExpectedTypeDescription) is currently incomplete (it will still say "a boolean." and omit the valid "undefined" literal). Consider updating getExpectedTypeDescription to include "or the string "undefined"" when attrDef.allowundefined is true so reported expectations match actual validation.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +21
// In aria-query 5.3.2, `allowundefined: true` is set only on the four
// boolean-like ARIA state attributes — `aria-expanded`, `aria-hidden`,
// `aria-grabbed`, `aria-selected` — whose WAI-ARIA 1.2 value tables list
// the literal string `"undefined"` as a spec-valid value meaning "state
// is not applicable" (e.g. https://www.w3.org/TR/wai-aria-1.2/#aria-expanded).
// The flag is nominally type-agnostic, but in practice this function only
// green-lights `"undefined"` for that boolean-like subset; no non-boolean
// ARIA attribute in aria-query currently sets `allowundefined`.
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

The new block comment ties behavior to an exact aria-query version (5.3.2), but package.json depends on aria-query: ^5.3.2, so consumers may run newer versions where allowundefined coverage changes. To avoid the comment becoming stale/misleading, consider rewording it to be version-agnostic (e.g., "currently in aria-query") or pinning the dependency if the version-specific assertion is important.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@johanrd johanrd merged commit f63750f into master Apr 25, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants