Skip to content

V2.3 - "Laying out"#7

Merged
zz85 merged 66 commits intogh-pagesfrom
v2.3
Mar 15, 2026
Merged

V2.3 - "Laying out"#7
zz85 merged 66 commits intogh-pagesfrom
v2.3

Conversation

@zz85
Copy link
Copy Markdown
Owner

@zz85 zz85 commented Mar 3, 2026

Lots of changes to come!

  • Playback note highlighting
  • Page layout mode
  • Highlighter overlay style
  • Solo/mute per staff
  • Piano keyboard fixes
  • Chord accidental fix
SCR-20260313-ezrj SCR-20260314-ubvj

Ink pressed mode
SCR-20260313-lfzg

@zz85 zz85 changed the title V2.3 V2.3 - "Laying out" Mar 14, 2026
zz85 added 28 commits March 14, 2026 23:24
Highlights active notes in blue during playback and draws a vertical
cursor at the current position. Uses single-canvas rendering (draws
highlights in quickDraw after score paint). Includes colored and glow
highlight modes, auto-scroll in both wrap and scroll layouts, and
binary-search cursor interpolation across the time-position index.
New 'page' layout mode renders the score on fixed-size pages displayed
like a PDF viewer: gray background, white page rectangles with drop
shadows, proper margins, and automatic page breaks. Systems are assigned
to pages based on available vertical content height with title/author
on page 1. Layout toggle cycles through scroll -> wrap -> page, and a
page size selector (Letter/A4) appears when page mode is active.
…ODO list

- PlaybackController: solo/mute state per staff with filtering; _reloadFiltered()
  preserves playback position when changing solo during playback
- Solo staff dropdown in toolbar, populated from score stave names
- PianoKeyboard: 88-key (A0-C8) HTML/CSS keyboard with per-staff color coding;
  keys light up on noteOn/noteOff, toggle button to show/hide
- 18 new tests (solo/mute filtering + piano keyboard), 320 total pass
- plans/features-todo.md: prioritized feature roadmap
… on pause

- Piano: proper black/white key sizing, per-octave offset positioning,
  raised z-index (10) for black keys, gradient + box-shadow for 3D look
- Default font size changed from 60 to 28
- Highlighter pause() keeps active notes visible on score and piano;
  only stop/end clears highlights
- Interpreter: add 3-tier accidental resolution (explicit > running > key sig)
  for chord child notes, matching standalone Note behavior
- buildNoteEvents: remove duplicate main chord voice; use only child notes[]
  which have correct accidentalValue from interpreter
- 6 new chord accidental tests, 326 total pass
…tems

Check off implemented features across playback (SoundFont, highlighting,
auto-scroll, piano visualization, chord accidental fix), layout (wrap/page
modes, lyrics, staff properties, courtesy clefs), UI (zoom, font controls,
persistence), and parser (binary format support, lyric extraction).

Add new planned items: MIDI/MusicXML/LilyPond import/export section,
multi-page rendering, page navigation, bar compression fix, SMuFL font
support, and MIDI instrument selection per staff.
…dynamics

- 12 SMuFL music fonts: Bravura, Petaluma, Leland, Sebastian, Golden Age,
  Leipzig, plus 6 Finale fonts (Maestro, Broadway, Ash, Engraver, Jazz, Legacy)
- Companion text fonts loaded via @font-face (BravuraText, LelandText,
  PetalumaText, SebastianText, FinaleMaestroText with full weight/style
  variants, FinaleBroadwayText, FinaleAshText, FinaleJazzText)
- Font selector dropdown with localStorage persistence
- All text elements (lyrics, titles, tempo, staff labels) use matching
  companion text font; fonts without a text companion fall back to serif
- Dynamic markings rendered as SMuFL glyphs (pre-composed pp/mp/mf/ff/etc.)
  instead of italic text, with individual letter composition fallback
- Fix augmentation dot to use standard U+E1E7 (not optional U+E1FC)
- Fix glyph lookup to use charToGlyph() directly, avoiding layout.scripts
  crash on fonts missing GSUB/GPOS tables
- Beams rendered as filled parallelograms for correct angled thickness
DynamicMarking extends Draw (like Glyph), not Text, so it lacks
Text's internal sign flip. The -(pos+4) was double-negating, placing
dynamics above the staff instead of below.
Re-export SpessaSynth's BasicMIDI parser for SMF format 0/1 binary
parsing, then convert to internal score format via grid-snap quantization
(16th note default), clef detection, key/time signature and tempo from
meta-events, chord grouping, rest inference, tie splitting at barlines,
beam grouping, and GM program name mapping to staff names.

Accidental spelling uses sharp tables for C major and sharp keys, flat
tables for flat keys, with correct key-signature interaction (omit
explicit accidentals when the key sig provides them, emit naturals to
cancel). Position computation verified via exhaustive MIDI round-trip
tests across 88 keys in 3 key signatures.

76 new tests (402 total, all passing).
… brackets, grace notes, flow directions

New drawing classes: ArticulationMark (SMuFL glyphs for staccato/accent/
tenuto/marcato/staccatissimo/fermata), Hairpin (crescendo/diminuendo
wedges), VoltaBracket (1st/2nd ending brackets with hooks and numbers),
TupletBracket (bracket with centered numeral and gap).

Typeset handles 5 new token types: DynamicVariance (hairpin wedges or
rfz/sfz text), Ending (volta brackets from repeat bitmask), Flow (Coda/
Segno as SMuFL glyphs, D.C./D.S./Fine as bold italic text), TempoVariance
(fermata glyph, breath mark, rit./rall./accel. text).

Grace notes render at 60% scale via _graceScale on Glyph.draw() with
reduced spacing. Articulations placed above/below noteheads based on stem
direction, stacking outward for multiple marks.

Post-layout passes: layoutTripletBrackets scans triplet=1..3 groups,
layoutHairpinSpans sizes wedges to next dynamic/barline, layoutVoltaSpans
sizes brackets to next ending/closing barline.

23 new tests (425 total, 0 failures).
Implement Ross/Gould-based spring-rod justification as a toggleable
alternative to the legacy sqrt-based spacing. Each note has a rigid rod
(physical width including accidentals, dots, lyrics) and an elastic
spring (duration-proportional gap) that compresses or stretches to fill
each system uniformly.

Additional fixes:
- Reserve accidental space before noteheads (prevents collisions)
- Multi-staff spring map takes max rod across all staves per beat
- Unify TickTracker multipliers (was 0.5x vs 4x, now consistent 1.0x)
- Grace note springs are duration-proportional at 40% scale
- Add 32nd/64th rest glyphs
- Split cross-system ties into trailing + leading partial arcs
- Add 0.5 staff-space breathing room before barlines
- Lyric text width factored into rod to prevent syllable overlap
Accidentals no longer call cursor.incStaveX — they hang left via offsetX
while the rod captures their width for spring-rod spacing. This keeps all
noteheads in a chord vertically aligned regardless of which notes have
accidentals.
…arline indent

- Remove pre-barline breathing room so system-end barlines sit flush
  against the stave right edge (no gap)
- Increase post-barline gap to 3 spacerWidths (accidental-safe indent)
- Double spring base multiplier (0.75 -> 1.5) for stronger duration-
  proportional spacing
- Simplify factor formula: factor = 1 + (target - natural) / springs
- Fix factor undershoot: use effective springs (after gap clamping) so
  total offset exactly equals targetWidth - naturalWidth
- Widen factor range (0.2-5.0) for more compression/stretch headroom
- Revert accidentals to pure offsetX (no cursor advance) to keep chord
  noteheads aligned
- Tie direction follows stem: stems up → below, stems down → above
- Tie Y position uses notehead offsetY (was anchored at staff top)
- Chord ties match by per-child-note position (was undefined===undefined)
- Beam convention corrected: NWC binary 1=start, 2=middle, 3=end
- Triplet brackets: numeral-only for beamed groups, full bracket for unbeamed
- Triplet numeral placed on stem side; vocal staves force above lyrics
- Grace note width scaled on glyph for correct beam/tie calculations
- Parent Chord drawingNoteHead set from first child for slur/highlight
- Cross-system tie splitting preserves direction
- 16 new tests (457 total passing)
…t rules

- Fix inverted coordinate system in drawBeamGroup (position increases
  upward, not downward): beam direction, horizontal beam extrema,
  slant limiting, and minimum stem push all corrected
- Fix computeStemLength ledger line conditions (below staff = position
  < -4 for stems-up, above staff = position > 4 for stems-down)
- Fix handleNote: pass stemLen to Stem constructor (was defaulting to 7)
- Standalone notes/chords use beamCount=0 (extra beam-line stem length
  only applies in beam groups, not to flagged notes)
- Add beam engraving guidelines to features-todo.md
- 20 new beam tests (computeStemLength + isNonMonotonic)
…lver

- Remove isNonMonotonic horizontal beam forcing (too aggressive — flattened
  beams like B-D-C that should slope upward)
- Remove iterative push-entire-beam minimum stem enforcement (caused
  over-extended stems on wide-interval groups like G5-D5-B4)
- New algorithm: compute first-to-last slope (unlimited), then solve for
  the optimal beam offset that satisfies all minimum stem lengths in one
  pass (no slant limit needed — min stem enforcement handles it)
- Remove 9 isNonMonotonic tests, keep 33 beam tests passing
…lass, collision avoidance, beam slope clamping

- New engraving-rules.js: centralized constants for tie/slur height
  interpolation (K*width+D clamped to [min,max]), thickness, anchor
  offsets, staff-line avoidance, accidental clearance

- Tie class rewritten: cubic bezier (control points at 1/3 and 2/3),
  proportional arc height (short=round, long=flat), tapered crescent
  (zero thickness at endpoints, max at midpoint), edge-anchored with
  gap from notehead edges

- New Slur class: thinner profile, center-anchored on noteheads,
  distinct from ties visually

- PartialTie upgraded to cubic bezier with proportional height

- Chord tie inner/outer direction: top note curves above, bottom
  below, inner notes follow nearest outer note

- Mixed-stem slur direction: always placed above

- Staff-line avoidance: arc peak nudged off staff lines into spaces

- Accidental collision: arc height boosted when end note has accidental
  (drawingAccidental stored on tokens in typeset.js)

- Intermediate note clearance: slur/tie arc scans notes between
  endpoints, increases height to clear protruding notes with 2 staff
  spaces of padding (e.g. D-G-F# where G pokes into the arc)

- Cross-system detection: _sysIdx stored during reflow (both wrap and
  page mode), used in splitCrossSystemTies instead of Y-threshold

- Beam slope clamped to 1 staff space max; non-monotonic pitch contours
  get horizontal beams; prevents super-extended stems on large intervals

- Triplet bracket position computed from actual note extremes + stem
  extent + padding, not hardcoded staff positions

- 35 new tests (449 total): engraving constants, proportional height,
  staff-line nudge, chord direction, mixed-stem slurs, intermediate
  note clearance
- New test/visual/index.html: VexFlow/OSMD-style visual regression page
  that renders 16 NWC files across 6 categories (Full Scores, Beams,
  Ties/Slurs, Lyrics, Dynamics, Clefs/Keys) into a labeled grid.
  Font size selector + re-run button for quick inspection after changes.

- Fix Drawing.draw() viewport culling: replace undeclared global
  scoreElm with document.getElementById('score') + null-safe fallbacks.
  The ghost global only worked in the main app due to implicit leaking;
  crashed in any other context (visual tests, unit tests with DOM).
…of NWC files

New test/visual/fixtures.js with builder helpers (note, rest, chord,
bar, clef, keySig, timeSig, dynamic, etc.) and 38 hand-crafted test
cases across 10 categories:

- Notes & Rests (6): durations, dots, stems, accidentals, ledger lines
- Beams (6): 8th/16th, wide interval, non-monotonic, triplet, unbeamed
- Ties (4): basic, high/low, chord inner/outer, accidental clearance
- Slurs (5): basic, mixed-stem, high/low middle note clearance, long
- Chords (5): 2-note, 3-4 note, wide-spread, clusters, accidentals
- Clefs & Signatures (3): treble/bass, key sigs, time sigs
- Dynamics (3): markings, hairpins, tempo/flow
- Articulations (3): individual, stacked, grace notes
- Barlines (2): styles, volta brackets
- Grand Staff (1): treble+bass with brace

Each fixture builds score data objects directly -- no file parsing --
so rendering regressions can be isolated to specific features.

Visual test page updated to render synthetic fixtures first, then
NWC file fixtures (54 total tests).
KeySignature constructor returned early for empty accidentals (C major)
without setting this.width.  The typesetter then computed
cursor.staveX += undefined + spacerWidth() = NaN, misaligning all
subsequent elements.  Now defaults this.width = 0 and null-guards
the accidentals array access.
…culation

Hairpin closed end now converges to a true point instead of having a visible
gap, and the open end is sized to ~1 staff space per standard engraving rules.
Store drawingDynamic reference on Dynamic tokens so layoutHairpinSpans can
properly terminate hairpins at text dynamics (p, f, etc.) instead of falling
back to a fixed width. Add 5 visual test fixtures covering basic, diminuendo,
swell, barline-termination, and short-span hairpin scenarios.
zz85 added 27 commits March 14, 2026 23:27
… staff-line avoidance

Articulation glyphs were placed 5 staff spaces above the notehead (+10 offset)
and horizontally misaligned because the cursor had advanced past the notehead.
Fixed Y offset to +/-2 half-spaces with isOnLine() nudging, and X offset to
reference noteHead.x directly. Added beamed and chord articulation visual tests;
extended chord() helper with marcato/staccatissimo/fermata fields.
…nit tests

Articulation Y uses ±2 half-space base offset with isOnLine nudge to avoid staff
lines. Chord articulations drawn once at chord level (not per child note), anchored
to the outermost note on the notehead side. Beamed articulation test uses explicit
stem directions (stem:1/2) so articulations appear on the correct side. Added 5
unit tests verifying the positioning math.
Add ~1.1 staff space gap (fontSize * 0.275) between the opening barline and
the clef, matching standard engraving practice. Applied consistently to the
initial system start and courtesy clefs at every line break in wrap/page modes.
Fixed page layout starting X: page mode now uses leftEdge=0 like wrap mode,
since reflow adds its own margins.
…tems forced up

Stem class gains _graceScale (60% thinner lines) and _slash (acciaccatura
diagonal through stem). handleNote/handleChord/drawBeamGroup in beams.js now
detect grace notes: force stems up, shorten to ~5 half-spaces, scale flag
glyphs, and tag beams with _graceScale for thinner beam lines. Beam class
scales thickness proportionally. Added 'Grace Note Variants' visual test
(accidentals, high position, beamed 16th grace pair).
Beam thickness corrected from 0.4sp to 0.5 staff spaces (getFontSize()/8),
center-to-center spacing set to 0.75sp (thickness + 0.25sp gap) per Gould/
Dorico standard. Adds 32nd-note visual test to exercise triple-beam layout.
Also marks grace notes as implemented in layout-features checklist.
… rest fixtures

TupletBracket constructor drops the redundant adjustY param (positionY is
always called by the caller). bracketPad now differentiates beamed groups
(1 half-space — numeral sits close to beam) from unbeamed/bracketed groups
(2 half-spaces — hooks need room to clear noteheads). Min-clearance clamps
tightened from 1.5sp to 1sp above top / 0 below bottom line. Adds visual
tests for stem-down beamed triplets and rest-containing triplets.
Draw measure numbers above the first staff using Claire.Text. In wrap/page
modes, the first measure number of each system is shown (computed from system
break boundary indices). In scroll mode, numbers appear above every barline.
Font scales with fontSize (~36%). Also adds measureIndex to _measureGeometry.
Replace the thin stroked bezier-curve brace with the Bravura U+E000 brace
glyph, vertically scaled to span the staff group height. Add 'brace' to
fontMap and export getCode/glyphPathGet from drawing.js for use in typeset.
Fix makeStaff() in test fixtures to honor braceWithNext/bracketWithNext/
connectBarsWithNext from opts (was hardcoded to false).
Add computeStaffExtents() that estimates per-staff content bounds from token
data before layout: note positions, stem tips (~7 half-spaces), dynamics
below (-9), tempo/flow marks above (+15), volta brackets (+16), and lyrics
(-10). buildStaffYMap() now accepts these extents and ensures inter-staff
gaps are large enough to prevent content overlap, with 0.6*fontSize padding.
Static boundary values from the file or fixed defaults still serve as a floor.
Draw a thin vertical line at the left edge of each system connecting the
top of the first staff to the bottom of the last (standard engraving for
any multi-staff score). Add visual test fixtures: Piano Grand Staff (brace),
Orchestral Bracket (3 staves), Brace + Bracket combined, System Barline.
Fix makeStaff opts spread for bracketWithNext/connectBarsWithNext.
Check off completed items (landscape/portrait, spring spacing, hairpins,
voltas, triplet brackets, beam angle limits, staff extents, paper sizes,
proportional spacing). Fix beam convention (1=start, 2=middle, 3=end).
Update test counts to 525. Add IMPLEMENTED/SUPERSEDED status headers to
completed plan docs. Remove emojis from all plan files.
Integrate the ink-bleed sketch as a rendering option. InkBleedRenderer class
wraps a WebGL2 pipeline that post-processes the score canvas: separable
Gaussian blur + composite shader with domain-warped ink bleed, FBM edge
roughness, letterpress pooling, paper fiber grain, micro-spatter, and
configurable paper color.

Noise is pinned to score coordinates (scroll + zoom passed to shader) so the
paper texture stays attached to the score when scrolling/zooming, rather than
feeling like an overlay. Paper color is configurable via setParams({ paperColor:
[r, g, b] }), defaulting to warm aged paper.

Toggled via 'Inked' button in toolbar. Rename 'Tuning' → 'Advanced'.

Based on ~/explorations/random-sketches/vibes/ink-bleed.
…noise

Three fixes to the ink bleed renderer:

1. Scroll/wrap mode fix: replace clearRect (transparent = R:0 = 'all ink')
   with opaque white fill so the shader correctly sees paper in empty areas.

2. Score-pinned noise: scroll offset scaled by DPR to match device-pixel
   resolution in the shader. Noise coordinates now truly pin to score-space
   across scroll, zoom, and DPR changes.

3. Paper color picker: color input next to the Inked button converts hex
   to RGB [0-1] and passes to inkBleed.setParams({ paperColor }).
Page mode: canvas fills with gray (#c8c8c8) for non-page areas; shader
detects this background color and outputs it as-is, skipping ink processing.
Page areas (white) get the full ink effect. Other layout modes fill white.

Add 'Ink' popover panel with five sliders matching the original sketch
controls: Bleed, Roughness, Ink Density, Paper Grain, Edge Pool. Each
slider maps 0-100 to the 0-1 shader uniform. Live repaint on change.
Documents all features added in v2.3 (print emulation, dynamic spacing,
articulations, grace notes, triplet brackets, beam standards, bar numbers,
braces, hairpins, voltas, MIDI import, per-staff instruments, and more).
Adds test/visual/index.html to the Web Tools section.
getChordTieDirection() had the position-to-pitch mapping backwards:
sorted[0] (most negative) was treated as 'top note' but in NWC
positive position = higher on staff. All chord ties curved the
wrong way. Swap topPos/bottomPos assignments to fix.

Add plans/engraving-rules.md documenting tie, slur, beam, articulation,
dynamics, hairpin, triplet, grace note, and spacing rules with
implementation status and constants reference.
Tie/slur thickness halved (~0.22 sp, matching MuseScore 0.21 sp),
minimum arc height halved (0.32 sp, matching MS 0.30 sp), notehead
gap and Y offsets tightened. System header spacing now uses named
constants: CLEF_LEFT_MARGIN (0.75 sp), AFTER_CLEF_GAP (0.80 sp),
AFTER_KEYSIG_GAP (1.00 sp), AFTER_TIMESIG_GAP (2.25 sp). C major
key signature no longer consumes phantom space. Grace note and
system header engraving rules documented. New bugs added to
features-todo.md.
Barline spacing now uses two components: AFTER_BARLINE_GAP (1.25 sp)
for the base gap, plus BARLINE_NOTE_EXTRA (0.75 sp) added only for
notes/rests/chords. Key/time signatures stay tight against the
barline while notes get 2.0 sp total clearance for accidental
overhang. Header spacing multiplier (default 1.15) for tuning.

Fix accidental-notehead gap: the barline extra indent was inserted
between the accidental and notehead in drawForNote, causing a
visible gap on the first note after a barline. Moved before both.

Add 'Dotted Note Articulations' visual test fixture. Add
constraint-based spacing model as future TODO.
Brace: tips now touch outer staff lines exactly (zero padding),
matching MuseScore/LilyPond/OSMD. Was starting near the bottom
line of the treble staff due to wrong Y calculation.

Barline spacing: differentiate notes vs key/time sigs using
_afterBarline flag. Notes get BARLINE_NOTE_EXTRA (0.75 sp) on top
of AFTER_BARLINE_GAP (1.25 sp). Fix accidental-notehead gap by
moving the barline indent before the accidental in drawForNote.

Header spacing multiplier (default 1.15) for global tuning.

Engraving rules doc: add beam thickness/separation (0.5/0.25 sp),
triplet bracket placement rules, brace/bracket section with
three-engine comparison, constraint-based spacing model as TODO.
Position the brace so its right edge (tips) aligns with the system
barline X, computed from the glyph bounding box rather than a
hardcoded fraction of the left margin. Add 0.3 sp horizontal
padding matching LilyPond convention. Remove unused braceX variable.
Implement notehead offset for chord seconds (adjacent notes) using
VexFlow/MuseScore toggle algorithm: walk from the end farthest from
the stem tip, toggle displaced flag for each consecutive second,
reset for larger intervals. Displaced notes shift one notehead width
to the opposite side of the stem.

Fix stem direction mismatch: seconds detection and articulations in
typeset.js now use the same formula as beams.js handleChord()
(sum of extreme positions) instead of checking only the first note.
This prevented symmetric chords like [-2,-1,0,1,2] from displacing
noteheads on the correct side of the stem.

Fix accidental displacement for stems-down chords (was only shifting
accidentals for rightward offsets, now shifts for both directions).

Add chord note layout (seconds and clusters) section to engraving
rules doc covering alternating noteheads, indeterminate clusters,
and accidental staggering.
Add 3 visual test fixtures for cross-staff notehead alignment:
staves with different key signatures (E vs C, B vs C) and same key
(Ab). Noteheads at the same beat should align vertically regardless
of header width differences. Currently not implemented — each staff
lays out independently.

Add cross-staff alignment section to engraving-rules.md with
LilyPond/MuseScore/OSMD comparison and fix approach. Add to
layout-features.md as unchecked item.

Improve keySig() fixture helper with proper accidental arrays for
all 15 key signatures.
Barline connectors for connected staves (connectBarsWithNext) now
span from the top line of the first staff to the bottom line of
the last staff, producing a single continuous barline with no gaps.

Previous code used getStaffY(si) + fontSize which started one
staff height below the bottom line, leaving a visible gap between
the individual barlines and the connector. Now uses
getStaffY(si) - fontSize (top of first) to getStaffY(nextSi)
(bottom of last), matching the system barline coordinate logic.

Document grand staff barline engraving rule.
Pre-V200 NWC files encode staff grouping in a staffType byte (0=Standard,
1=Upper Grand Staff, 2=Lower Grand Staff, 3=Orchestral) rather than the
V200+ withNext bitmask. Derive braceWithNext/connectBarsWithNext from
staffType=1 and bracketWithNext from staffType=3. Also parse the color
field (was skipped) and pass it through the adapter. Adds 4 tests
verifying adohn.nwc (V175) grand staff flags, boundaries, and color.
Flow direction glyphs (Segno, Coda) were consuming horizontal space
via cursor.incStaveX(flowGlyph.width + spacerWidth()), pushing
subsequent notes rightward. In multi-staff scores this caused
vertical misalignment at the Segno mark (e.g., adohn.nwc).

Flow directions are non-spacing markers placed above the staff at
the current X position without advancing the cursor, matching how
text flow directions (D.C., Fine, etc.) already behaved.

Add 'Cross-Staff Alignment — Flow Directions' visual test fixture
with Segno and Coda on the treble staff of a grand staff pair.
Grace notes no longer advance the display time counter (tabCounter)
in the interpreter. This ensures the principal note after a grace
note shares the same tabValue as the equivalent beat on other staves,
enabling correct vertical alignment via the TickTracker.

Grace notes still advance tickCounter for playback (NWC treats them
as having real duration). They also retain their visual space via
rod/spring — only the alignment key is affected.

Add 'Cross-Staff Alignment — Grace Notes' visual test fixture with
grace notes on treble staff of a grand staff pair. Document
cross-staff alignment rule in engraving-rules.md grace notes section.
@zz85 zz85 marked this pull request as ready for review March 15, 2026 06:35
@zz85 zz85 merged commit 4b098fe into gh-pages Mar 15, 2026
2 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.

1 participant