Skip to content

refactor(sandbox): spell out the player markup in the html templates - #2691

Merged
luwes merged 1 commit into
mainfrom
refactor/sandbox-html-templates
Sep 9, 2026
Merged

refactor(sandbox): spell out the player markup in the html templates#2691
luwes merged 1 commit into
mainfrom
refactor/sandbox-html-templates

Conversation

@luwes

@luwes luwes commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Refs #2586

Summary

The html sandbox templates render the whole player again — the player element, the skin, and the media inside it — so the markup can be read and copied straight from templates/html-*/main.ts. #2586 had folded that markup into createHtmlSandbox, leaving a template with only its media element.

Changes

  • createHtmlSandbox takes a render callback in place of media and poster, and its context exposes what the shell varies: the registered skinTag, the live playerTag, the source and poster/placeholder URLs, and the Options-panel attributes. The runtime still owns the sandbox-only concerns: state streaming, skin loading, <media-i18n>, caption injection, mirror, and direction.
  • Every html-* template writes its player, skin, frame classes, and poster markup literally. Non-live players and the background skin are written by tag; live-capable templates use ${playerTag}, and skinned templates use ${skinTag}.
  • Templates frame the player with the plain max-w-4xl / max-w-xl a consumer would write. An unlayered rule in app/styles.css caps those at --sandbox-player-width, so the shell's width control keeps working without the sandbox-specific classes appearing in the templates. The CDN page uses the same classes; React pages are unchanged.
Implementation details

The poster and placeholder are handed over as attribute-safe URL strings rather than markup, so templates guard on them (${poster ? html<img slot="poster" …> : ''}) the same way the runtime did, since the Mux pickers include a source with no asset.

The width rule reaches through <media-i18n> as well because the CDN page nests the provider inside the player element rather than around it.

Testing

  • pnpm -F @videojs/sandbox test: 30 passed.
  • Sandbox Playwright suite: 101 passed, 9 skipped. The one failure, sandbox-mirror.spec.ts › carries playback from one panel to the other, times out clicking Pause in the React panel while its controls auto-hide; it fails on main too and the React page is untouched here.
  • After the poster change, the html-facing specs (shell-controls, html-i18n, skin-styling, compare, cdn-i18n) were rerun: 89 passed.
  • Manual: open /?platform=html&media=video, drag the Options width slider, switch skin, source, and captions; the player resizes and re-renders as before.

Note

Medium Risk
Wide mechanical refactor across all HTML sandbox entry points and preview layout CSS; behavior should match prior tests but poster/live tag wiring now lives in many templates.

Overview
HTML sandbox templates now own the full player markup so examples read like copy-paste integration code instead of a thin media snippet wrapped by the runtime.

createHtmlSandbox drops the media and poster options in favor of a render(context) callback. The context adds playerTag, skinTag, and escaped poster / placeholder URLs; the helper no longer builds player/skin wrappers or poster slots internally. Shell behavior (state, skin load, i18n wrap, captions, mirror) is unchanged.

Every html-* template (and the CDN page) writes video-player / audio-player, ${skinTag}, framing with consumer max-w-4xl / max-w-xl, and optional poster markup—Mux pages use player poster plus blur placeholder slots explicitly. styles.css adds #root rules so those Tailwind caps still honor --sandbox-player-width; React framing via PLAYER_FRAME_CLASSES is documented as React-only.

Reviewed by Cursor Bugbot for commit 69cd83d. Bugbot is set up for automated code reviews on this repo. Configure here.

#2586 moved the player element, the skin, its frame classes, and the
poster into `createHtmlSandbox`, so a template only wrote its media
element and a reader had to open the runtime to learn how a player is
put together. Templates now render the whole player as a consumer
would write it, and the runtime hands them only what the shell varies:
the skin tag it registered, the live player tag, the source and poster
URLs, and the attributes the Options panel controls.

The frame classes become the plain `max-w-4xl` and `max-w-xl` a
consumer would use; an unlayered rule in `styles.css` caps them at the
shell's `--sandbox-player-width` so the width control still works.
@vercel

vercel Bot commented Sep 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
v10-sandbox Ready Ready Preview Sep 9, 2026 7:05pm UTC

Request Review

@netlify

netlify Bot commented Sep 9, 2026

Copy link
Copy Markdown

Deploy Preview for vjs-registry canceled.

Name Link
🔨 Latest commit 69cd83d
🔍 Latest deploy log https://app.netlify.com/projects/vjs-registry/deploys/6aa1ad877587b50008d3794e

@netlify

netlify Bot commented Sep 9, 2026

Copy link
Copy Markdown

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit 69cd83d
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/6aa1ad878b272d00089619ad
😎 Deploy Preview https://deploy-preview-2691--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@pkg-pr-new

pkg-pr-new Bot commented Sep 9, 2026

Copy link
Copy Markdown
@videojs/cdn

pnpm add https://pkg.pr.new/@videojs/cdn@2691

@videojs/core

pnpm add https://pkg.pr.new/@videojs/core@2691

@videojs/element

pnpm add https://pkg.pr.new/@videojs/element@2691

@videojs/html

pnpm add https://pkg.pr.new/@videojs/html@2691

@videojs/media

pnpm add https://pkg.pr.new/@videojs/media@2691

@videojs/react

pnpm add https://pkg.pr.new/@videojs/react@2691

@videojs/spf

pnpm add https://pkg.pr.new/@videojs/spf@2691

@videojs/store

pnpm add https://pkg.pr.new/@videojs/store@2691

@videojs/utils

pnpm add https://pkg.pr.new/@videojs/utils@2691

@videojs/cloudflare-video

pnpm add https://pkg.pr.new/@videojs/cloudflare-video@2691

@videojs/dash-video

pnpm add https://pkg.pr.new/@videojs/dash-video@2691

@videojs/hlsjs-video

pnpm add https://pkg.pr.new/@videojs/hlsjs-video@2691

@videojs/mux-audio

pnpm add https://pkg.pr.new/@videojs/mux-audio@2691

@videojs/mux-video

pnpm add https://pkg.pr.new/@videojs/mux-video@2691

@videojs/native-hls-video

pnpm add https://pkg.pr.new/@videojs/native-hls-video@2691

@videojs/shaka-video

pnpm add https://pkg.pr.new/@videojs/shaka-video@2691

@videojs/spotify-audio

pnpm add https://pkg.pr.new/@videojs/spotify-audio@2691

@videojs/tiktok-video

pnpm add https://pkg.pr.new/@videojs/tiktok-video@2691

@videojs/twitch-video

pnpm add https://pkg.pr.new/@videojs/twitch-video@2691

@videojs/vimeo-video

pnpm add https://pkg.pr.new/@videojs/vimeo-video@2691

@videojs/wistia-video

pnpm add https://pkg.pr.new/@videojs/wistia-video@2691

@videojs/youtube-video

pnpm add https://pkg.pr.new/@videojs/youtube-video@2691

@videojs/google-cast

pnpm add https://pkg.pr.new/@videojs/google-cast@2691

@videojs/mux-data

pnpm add https://pkg.pr.new/@videojs/mux-data@2691

commit: 69cd83d

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Initial Lazy
/video (default) 63.49 kB 58.19 kB
/video (default + hls) 65.30 kB 58.19 kB
/video (minimal) 63.87 kB 58.19 kB
/video (minimal + hls) 65.56 kB 58.19 kB
/audio (default) 47.47 kB 58.19 kB
/audio (minimal) 47.70 kB 58.19 kB
/background 11.65 kB 58.19 kB
Media (18)
Entry Initial
/media/mux-video 3.01 kB
/media/mux-audio 2.69 kB
/media/background-video 1.16 kB
/media/cloudflare-video 2.90 kB
/media/dash-video 2.63 kB
/media/hls-audio 22.05 kB
/media/hls-background-video 16.85 kB
/media/hls-video 28.01 kB
/media/hlsjs-video 2.63 kB
/media/mux-background-video 16.86 kB
/media/native-hls-video 7.59 kB
/media/shaka-video 2.63 kB
/media/spotify-audio 3.02 kB
/media/tiktok-video 3.13 kB
/media/twitch-video 2.93 kB
/media/vimeo-video 2.90 kB
/media/wistia-video 607 B
/media/youtube-video 2.90 kB
Players (5)
Entry Initial Lazy
/video/player 9.79 kB 58.19 kB
/audio/player 6.21 kB 58.19 kB
/background/player 4.46 kB 58.19 kB
/live-video/player 9.18 kB 58.19 kB
/live-audio/player 6.22 kB 58.19 kB
Skins (29)
Entry Type Initial Lazy
/video/minimal-skin.css css 7.71 kB
/video/skin.css css 7.51 kB
/video/minimal-skin js 62.24 kB 58.19 kB
/video/minimal-skin2 js 8.16 kB
/video/skin js 62.03 kB 58.19 kB
/video/skin2 js 8.00 kB
/audio/minimal-skin.css css 5.60 kB
/audio/skin.css css 5.43 kB
/audio/minimal-skin js 46.19 kB 58.19 kB
/audio/minimal-skin2 js 5.93 kB
/audio/skin js 45.94 kB 58.19 kB
/audio/skin2 js 5.75 kB
/background/skin.css css 139 B
/background/skin js 9.91 kB 58.19 kB
/background/skin2 js 187 B
/live-video/minimal-skin.css css 6.23 kB
/live-video/skin.css css 6.23 kB
/live-video/minimal-skin js 49.77 kB 58.19 kB
/live-video/minimal-skin2 js 6.58 kB
/live-video/skin js 49.79 kB 58.19 kB
/live-video/skin2 js 6.63 kB
/live-audio/minimal-skin.css css 4.45 kB
/live-audio/skin.css css 4.45 kB
/live-audio/minimal-skin js 35.64 kB 58.19 kB
/live-audio/minimal-skin2 js 4.70 kB
/live-audio/skin js 35.64 kB 58.19 kB
/live-audio/skin2 js 4.70 kB
/global.css css 190 B
/shared.css css 118 B
UI Components (62)
Entry Initial Lazy
/ui/airplay-button 11.36 kB 58.19 kB
/ui/alert-dialog 8.79 kB 58.19 kB
/ui/audio-track-radio-group 11.46 kB 58.19 kB
/ui/buffering-indicator 8.68 kB 58.19 kB
/ui/captions-button 11.59 kB 58.19 kB
/ui/captions-radio-group 11.54 kB 58.19 kB
/ui/cast-button 11.34 kB 58.19 kB
/ui/container 9.58 kB 58.19 kB
/ui/controls 8.86 kB 58.19 kB
/ui/controls-backdrop 1.69 kB 58.19 kB
/ui/controls-content 1.67 kB 58.19 kB
/ui/dialog 8.73 kB 58.19 kB
/ui/dialog-backdrop 1.70 kB 58.19 kB
/ui/dialog-close 2.06 kB 58.19 kB
/ui/dialog-description 1.69 kB 58.19 kB
/ui/dialog-popup 1.90 kB 58.19 kB
/ui/dialog-title 1.70 kB 58.19 kB
/ui/error-dialog 12.47 kB 58.19 kB
/ui/fullscreen-button 11.33 kB 58.19 kB
/ui/gesture 9.66 kB 58.19 kB
/ui/hotkey 10.13 kB 58.19 kB
/ui/live-button 9.89 kB 58.19 kB
/ui/menu 18.54 kB 58.19 kB
/ui/menu-checkbox-item 1.97 kB 58.19 kB
/ui/menu-content 7.52 kB 58.19 kB
/ui/menu-group 2.09 kB 58.19 kB
/ui/menu-group-label 1.64 kB
/ui/menu-item 2.30 kB 58.19 kB
/ui/menu-item-indicator 1.38 kB 58.19 kB
/ui/menu-radio-group 3.01 kB 58.19 kB
/ui/menu-radio-item 2.13 kB 58.19 kB
/ui/menu-separator 1.30 kB 58.19 kB
/ui/mute-button 11.36 kB 58.19 kB
/ui/pip-button 11.31 kB 58.19 kB
/ui/play-button 11.31 kB 58.19 kB
/ui/playback-rate-button 11.41 kB 58.19 kB
/ui/playback-rate-radio-group 11.46 kB 58.19 kB
/ui/popover 8.57 kB 58.19 kB
/ui/poster 8.97 kB 58.19 kB
/ui/quality-radio-group 12.05 kB 58.19 kB
/ui/seek-button 11.34 kB 58.19 kB
/ui/seek-indicator 12.77 kB 58.19 kB
/ui/seek-indicator-value 1.10 kB
/ui/slider 11.75 kB 58.19 kB
/ui/slider-preview 2.01 kB 58.19 kB
/ui/status-announcer 10.68 kB 58.19 kB
/ui/status-indicator 13.10 kB 58.19 kB
/ui/status-indicator-value 1.10 kB
/ui/thumbnail 10.35 kB 58.19 kB
/ui/time 11.11 kB 58.19 kB
/ui/time-slider 13.22 kB 58.19 kB
/ui/time-slider-chapter-title 8.87 kB 58.19 kB
/ui/time-slider-chapters 9.71 kB 58.19 kB
/ui/title 8.25 kB 58.19 kB
/ui/tooltip 9.95 kB 58.19 kB
/ui/tooltip-label 1.21 kB
/ui/tooltip-shortcut 1.18 kB
/ui/volume-indicator 13.11 kB 58.19 kB
/ui/volume-indicator-fill 1.11 kB
/ui/volume-indicator-value 1.10 kB
/ui/volume-popover 14.82 kB 58.19 kB
/ui/volume-slider 12.43 kB 58.19 kB
⚛️ @videojs/react — no changes
Presets (7)
Entry Initial Lazy
/video (default) 51.38 kB 58.19 kB
/video (default + hls) 51.54 kB 58.19 kB
/video (minimal) 51.51 kB 58.19 kB
/video (minimal + hls) 51.80 kB 58.19 kB
/audio (default) 39.82 kB 58.19 kB
/audio (minimal) 39.89 kB 58.19 kB
/background 581 B 58.19 kB
Media (22)
Entry Initial
/media/mux-video/hls-js 958 B
/media/mux-video/spf 962 B
/media/mux-audio/hls-js 699 B
/media/mux-audio/spf 703 B
/media/background-video 402 B
/media/cloudflare-video 911 B
/media/dash-video 693 B
/media/hls-audio 20.32 kB
/media/hls-background-video 16.47 kB
/media/hls-video 26.32 kB
/media/hlsjs-video 695 B
/media/mux-audio 693 B
/media/mux-background-video 16.41 kB
/media/mux-video 948 B
/media/native-hls-video 5.78 kB
/media/shaka-video 704 B
/media/spotify-audio 901 B
/media/tiktok-video 906 B
/media/twitch-video 929 B
/media/vimeo-video 888 B
/media/wistia-video 619 B
/media/youtube-video 897 B
Extensions (2)
Entry Initial
/extensions/google-cast 1.59 kB
/extensions/mux-data 1.64 kB
Players (5)
Entry Initial Lazy
/video/player 7.67 kB 58.19 kB
/audio/player 4.06 kB 58.19 kB
/background/player 2.27 kB 58.19 kB
/live-video/player 7.06 kB 58.19 kB
/live-audio/player 4.05 kB 58.19 kB
Skins (18)
Entry Type Initial Lazy
/video/minimal-skin.css css 7.56 kB
/video/skin.css css 7.37 kB
/video/minimal-skin js 51.46 kB 58.19 kB
/video/skin js 51.32 kB 58.19 kB
/audio/minimal-skin.css css 5.42 kB
/audio/skin.css css 5.25 kB
/audio/minimal-skin js 39.78 kB 58.19 kB
/audio/skin js 39.74 kB 58.19 kB
/background/skin.css css 90 B
/background/skin js 277 B
/live-video/minimal-skin.css css 6.08 kB
/live-video/skin.css css 6.08 kB
/live-video/minimal-skin js 42.90 kB 58.19 kB
/live-video/skin js 42.92 kB 58.19 kB
/live-audio/minimal-skin.css css 4.26 kB
/live-audio/skin.css css 4.26 kB
/live-audio/minimal-skin js 30.55 kB 58.19 kB
/live-audio/skin js 30.58 kB 58.19 kB
UI Components (39)
Entry Initial Lazy
/ui/airplay-button 10.53 kB 58.19 kB
/ui/alert-dialog 4.73 kB 58.19 kB
/ui/audio-track 8.04 kB 58.19 kB
/ui/audio-track-radio-group 9.57 kB 58.19 kB
/ui/buffering-indicator 7.88 kB 58.19 kB
/ui/captions-button 10.51 kB 58.19 kB
/ui/captions-radio-group 9.67 kB 58.19 kB
/ui/cast-button 10.51 kB 58.19 kB
/ui/controls 7.80 kB 58.19 kB
/ui/dialog 4.75 kB 58.19 kB
/ui/error-dialog 11.88 kB 58.19 kB
/ui/fullscreen-button 10.49 kB 58.19 kB
/ui/gesture 8.07 kB 58.19 kB
/ui/hotkey 8.56 kB 58.19 kB
/ui/live-button 8.91 kB 58.19 kB
/ui/menu 19.54 kB 58.19 kB
/ui/mute-button 10.53 kB 58.19 kB
/ui/pip-button 10.48 kB 58.19 kB
/ui/play-button 10.45 kB 58.19 kB
/ui/playback-rate 8.07 kB 58.19 kB
/ui/playback-rate-button 10.45 kB 58.19 kB
/ui/playback-rate-radio-group 9.60 kB 58.19 kB
/ui/popover 8.16 kB 58.19 kB
/ui/poster 7.95 kB 58.19 kB
/ui/quality 8.50 kB 58.19 kB
/ui/quality-radio-group 10.04 kB 58.19 kB
/ui/seek-button 10.52 kB 58.19 kB
/ui/seek-indicator 12.06 kB 58.19 kB
/ui/slider 13.12 kB 58.19 kB
/ui/status-announcer 10.18 kB 58.19 kB
/ui/status-indicator 12.37 kB 58.19 kB
/ui/thumbnail 9.18 kB 58.19 kB
/ui/time 10.03 kB 58.19 kB
/ui/time-slider 14.40 kB 58.19 kB
/ui/title 7.35 kB 58.19 kB
/ui/tooltip 8.93 kB 58.19 kB
/ui/volume-indicator 12.42 kB 58.19 kB
/ui/volume-popover 14.29 kB 58.19 kB
/ui/volume-slider 12.25 kB 58.19 kB
🧩 @videojs/core — no changes
Entries (76)
Entry Initial Lazy
. 13.35 kB
/dom 22.82 kB 58.19 kB
/vjsc 1.87 kB
/i18n 3.23 kB 58.19 kB
/i18n/locales/all 35.98 kB
/i18n/locales/ar 1.24 kB
/i18n/locales/az 1.12 kB
/i18n/locales/bg 1.32 kB
/i18n/locales/bn 1.25 kB
/i18n/locales/bs 1.03 kB
/i18n/locales/ca 1.10 kB
/i18n/locales/cs 1.11 kB
/i18n/locales/cy 1.05 kB
/i18n/locales/da 1.01 kB
/i18n/locales/de 1.11 kB
/i18n/locales/el 1.53 kB
/i18n/locales/en 801 B
/i18n/locales/es 1.02 kB
/i18n/locales/et 1.07 kB
/i18n/locales/eu 1.04 kB
/i18n/locales/fa 1.25 kB
/i18n/locales/fi 1.07 kB
/i18n/locales/fr 1.09 kB
/i18n/locales/gd 1.13 kB
/i18n/locales/gl 1.02 kB
/i18n/locales/he 1.16 kB
/i18n/locales/hi 1.33 kB
/i18n/locales/hr 1.05 kB
/i18n/locales/hu 1.11 kB
/i18n/locales/id 941 B
/i18n/locales/it 1.04 kB
/i18n/locales/ja 1.22 kB
/i18n/locales/ko 1.18 kB
/i18n/locales/lt 1.04 kB
/i18n/locales/lv 1.11 kB
/i18n/locales/mr 1.32 kB
/i18n/locales/nb 1015 B
/i18n/locales/ne 1.32 kB
/i18n/locales/nl 1.02 kB
/i18n/locales/nn 1015 B
/i18n/locales/oc 1.10 kB
/i18n/locales/pl 1.17 kB
/i18n/locales/pt 1.05 kB
/i18n/locales/pt-BR 1.05 kB
/i18n/locales/pt-PT 1.04 kB
/i18n/locales/ro 1.10 kB
/i18n/locales/ru 1.42 kB
/i18n/locales/sk 1.13 kB
/i18n/locales/sl 1.07 kB
/i18n/locales/sr 1.13 kB
/i18n/locales/sv 1.03 kB
/i18n/locales/te 1.34 kB
/i18n/locales/th 1.31 kB
/i18n/locales/tr 1.09 kB
/i18n/locales/uk 1.44 kB
/i18n/locales/vi 1.13 kB
/i18n/locales/zh 1.04 kB
/i18n/locales/zh-CN 1.04 kB
/i18n/locales/zh-TW 1.04 kB
/i18n/text/airplay 101 B
/i18n/text/buttons 137 B
/i18n/text/captions 93 B
/i18n/text/cast 114 B
/i18n/text/common 90 B
/i18n/text/container 75 B
/i18n/text/errors 285 B
/i18n/text/fullscreen 98 B
/i18n/text/live 126 B
/i18n/text/menu 249 B
/i18n/text/pip 101 B
/i18n/text/playback 80 B
/i18n/text/seek 105 B
/i18n/text/slider 65 B
/i18n/text/status 222 B
/i18n/text/time 322 B
/i18n/text/volume 133 B
🏷️ @videojs/element — no changes
Entries (2)
Entry Initial
. 1.05 kB
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Initial
. 1.72 kB
/html 703 B
/react 365 B
🔧 @videojs/utils — no changes
Entries (13)
Entry Initial
/array 271 B
/dom 5.11 kB
/events 320 B
/function 386 B
/i18n 249 B
/jwt 176 B
/object 535 B
/predicate 297 B
/percent 281 B
/string 239 B
/style 212 B
/time 976 B
/number 199 B
📦 @videojs/cdn — no changes
📦 @videojs/cloudflare-video — no changes
📦 @videojs/dash-video — no changes
📦 @videojs/google-cast — no changes
📦 @videojs/hlsjs-video — no changes
📦 @videojs/media — no changes
Entries (3)
Entry Initial
. 1.29 kB
/dom 4.12 kB
/media-tracks 2.05 kB
📦 @videojs/mux — no changes
📦 @videojs/mux-audio — no changes
Entries (2)
Entry Initial
. 135.53 kB
/spf 20.81 kB
📦 @videojs/mux-data — no changes
📦 @videojs/mux-video — no changes
Entries (2)
Entry Initial
. 135.67 kB
/spf 26.72 kB
📦 @videojs/native-hls-video — no changes
📦 @videojs/shaka-video — no changes
📦 @videojs/spf — no changes
Entries (7)
Entry Initial
. 4.55 kB
/dom 6.60 kB
/hls 22.15 kB
/media-tracks 504 B
/hls-background-video 15.84 kB
/hls-audio 19.84 kB
/hls-video 25.89 kB
📦 @videojs/spotify-audio — no changes
📦 @videojs/tiktok-video — no changes
📦 @videojs/twitch-video — no changes
📦 @videojs/vimeo-video — no changes
📦 @videojs/wistia-video — no changes
Entries (2)
Entry Initial
. 1.91 kB
/helpers 1.77 kB
📦 @videojs/youtube-video — no changes

ℹ️ How to interpret

Each entry is independently bundled, minified, and brotli-compressed. Initial size includes its static import graph; lazy dynamic chunks are reported separately.

Entries are not additive because their dependency graphs overlap. Preset rows represent realistic combined bundles.

Changes of 300 B or less across initial, lazy, and total size are collapsed, not discarded.

Run pnpm size locally to check current initial sizes.

@luwes
luwes merged commit 542829b into main Sep 9, 2026
36 of 37 checks passed
@luwes
luwes deleted the refactor/sandbox-html-templates branch September 9, 2026 21:52
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