From 8252b69b6a1ce6b87b698123604c4d67f61a9931 Mon Sep 17 00:00:00 2001
From: shaziya <99940835+shaziyabandukia@users.noreply.github.com>
Date: Thu, 23 Jul 2026 11:13:14 -0700
Subject: [PATCH 1/4] feat(www): convert TRAE webinar page to on-demand
(#48225)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Feature — converts the TRAE webinar event page to its on-demand version
and adds a small template enhancement to support a custom type label.
## What is the current behavior?
The [TRAE webinar
page](https://supabase.com/events/supabase-trae-high-quality-apps) is
set up as a live, upcoming event: `onDemand: false`, a registration CTA
linking out to GoToWebinar, and copy written in the future tense ("What
we'll cover").
The shared event page template (`pages/events/[slug].tsx`) always
renders the raw `type` frontmatter value (e.g. "WEBINAR") as the label
at the top of the page, with no way to override it.
## What is the new behavior?
- Flips `onDemand` to `true` and swaps the `main_cta` from the
GoToWebinar registration link to a `#recording` anchor labeled "Watch
the recording", matching the pattern used for the Bolt and Perplexity
webinars once they went on-demand.
- Adds a `video-container` iframe placeholder (`id="recording"`) below
the intro copy. The `src` is intentionally left empty with a `TODO`
comment — neither the Bolt nor Perplexity on-demand pages expose the
recording URL in frontmatter, it's a hardcoded YouTube embed URL in the
MDX body, so this needs the real embed URL dropped in before merging.
- Replaces the "What we'll cover" section with updated "Key Takeaways"
copy and a closing line ("We hope you enjoy the recording!").
- Adds an optional `type_label` frontmatter field to the event page
template. When set, it renders in place of the raw `type` value at the
top of the page; when unset, behavior is unchanged for every other event
page. Used here to show "Supabase Live" instead of "WEBINAR".
## Additional context
Verified locally in preview:
- TRAE event page renders correctly with the new CTA, video placeholder,
updated copy, and "SUPABASE LIVE" label.
- Other event pages (e.g. `enterprise-innovation-with-bolt`) are
unaffected and still show their original type label, confirming the
`type_label` change is backward compatible.
Still needed before merging: the actual recording embed URL in the
iframe `src`.
---
...-07-22-supabase-trae-high-quality-apps.mdx | 36 ++++++++++++-------
apps/www/pages/events/[slug].tsx | 5 ++-
2 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/apps/www/_events/2026-07-22-supabase-trae-high-quality-apps.mdx b/apps/www/_events/2026-07-22-supabase-trae-high-quality-apps.mdx
index ae8aefb5e6ebc..716e31acd6ff5 100644
--- a/apps/www/_events/2026-07-22-supabase-trae-high-quality-apps.mdx
+++ b/apps/www/_events/2026-07-22-supabase-trae-high-quality-apps.mdx
@@ -8,7 +8,8 @@ meta_description: >-
and TRAE to see how TRAE SOLO uses your live Supabase context (schema, auth,
RLS policies, and logs) to generate code that holds up in production.
type: webinar
-onDemand: false
+type_label: 'Supabase Live'
+onDemand: true
date: '2026-07-22T19:00:00.000-07:00'
timezone: America/Los_Angeles
duration: 45 mins
@@ -22,9 +23,9 @@ company:
categories:
- webinar
main_cta:
- url: 'https://attendee.gotowebinar.com/register/2865727980603383392'
- target: _blank
- label: Register now
+ url: '#recording'
+ target: _self
+ label: Watch the recording
speakers: 'gerardo_estaba,gary_qi'
---
@@ -34,15 +35,26 @@ More people than ever are shipping real products with AI tools. The gap between
TRAE and Supabase are built for both. TRAE gives you the speed of a fully autonomous AI coding agent that takes you from prompt to working app. Supabase handles the backend: open-source managed Postgres with Auth, Storage, Edge Functions, and Realtime built in. When TRAE has live context of your Supabase projects, the code it generates is production-ready from the start.
-In this session, Gerardo Estaba from Supabase and Gary Qi from TRAE will show you how to go from prompt to production without compromising on code quality.
+In this session, Gerardo Estaba from Supabase and Gary Qi from TRAE show you how to go from prompt to production without compromising on code quality.
-### What we'll cover
+
+
+
-- Where AI-generated apps break in production and how TRAE and Supabase catch those problems before they ship
-- How TRAE SOLO uses your live Supabase context (schema, auth config, RLS policies, and logs) to generate more accurate code
-- Managing your Supabase backend with natural language via the Supabase and TRAE SOLO integration: running migrations, modifying RLS policies, creating storage buckets, and managing secrets
-- Live build: a full-stack app from prompt to deployed, with Auth, Storage, and a secure database, built entirely inside TRAE
+## Key Takeaways
-You'll leave with a clear picture of what the TRAE and Supabase workflow looks like end to end, and what to set up first on your own project.
+- Where AI-generated apps break in production, and how TRAE and Supabase catch those problems before they ship
-Plus, bring your questions for the live Q&A. Can't make it? Register anyway and we'll send you the recording.
+- How TRAE SOLO uses your live Supabase context (schema, Auth config, RLS policies, and logs) to generate more accurate code
+
+- How to manage your Supabase backend in natural language through the Supabase and TRAE SOLO integration: running migrations, modifying RLS policies, creating Storage buckets, and managing secrets
+
+- A full live build of a full-stack app, from prompt to deployed, with Auth, Storage, and a secure database, built entirely inside TRAE
+
+We hope you enjoy the recording!
diff --git a/apps/www/pages/events/[slug].tsx b/apps/www/pages/events/[slug].tsx
index ffa039f847610..029b30eae2f3e 100644
--- a/apps/www/pages/events/[slug].tsx
+++ b/apps/www/pages/events/[slug].tsx
@@ -61,6 +61,7 @@ interface EventData {
main_cta?: CTA
description: string
type: EventType
+ type_label?: string
company?: CompanyType
onDemand?: boolean
disable_page_build?: boolean
@@ -283,7 +284,9 @@ const EventPage = ({ event }: InferGetStaticPropsType) =>
- {event.type}
+
+ {event.type_label ?? event.type}
+
{dayjs(event.date).tz(event.timezone).format(`DD MMM YYYY [at] hA z`)}
From 39276f80d070b8ad3663fa50ca4c5a97c50df453 Mon Sep 17 00:00:00 2001
From: Miranda Limonczenko
Date: Thu, 23 Jul 2026 11:33:38 -0700
Subject: [PATCH 2/4] fix(docs ci): stop docs-e2e from polling the broken
GitHub Deployments API (#48226)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Summary
- `vercel/wait-for-deployment-action` in
[docs-e2e.yml](.github/workflows/docs-e2e.yml) polls GitHub's
Deployments API for a `Preview – docs` deployment, but Vercel's GitHub
App has not written a GitHub Deployment object repo-wide since
2026-02-17 (broken app auth). The step times out after 900s on every PR
that touches `apps/docs`, even though the preview build itself succeeds
(`Vercel – docs` commit status is green).
- Replace the wait step with a custom poll of the `Vercel – docs` commit
status (which Vercel keeps posting correctly), then resolve the actual
preview URL via Vercel's own deployments API (`GET
/v13/deployments/{id}`) using the deployment ID embedded in the commit
status's `target_url`, reusing the existing `VERCEL_TOKEN` /
`VERCEL_TEAM_ID` secrets.
- Drops the now-unused `deployments: read` permission.
## Context
Reported in Slack:
https://supabase.slack.com/archives/C023E4L60R3/p1784721725606599?thread_ts=1784658589.182079&cid=C023E4L60R3
(surfaced by [#48178](https://github.com/supabase/supabase/pull/48178)
failing on this step — [run
29916797889](https://github.com/supabase/supabase/actions/runs/29916797889?pr=48178)).
Agreed workaround from that thread: swap the wait step to poll the
`Vercel – docs` commit status instead of the Deployments API.
## Test plan
- [ ] Confirm this workflow run (triggered by this PR since it edits
`apps/docs/**`... actually this PR only touches the workflow file, so
verify via `workflow_dispatch` or a follow-up PR touching
`apps/docs/**`) passes the "Wait for Vercel docs preview" step and
resolves a working `deployment-url`
- [ ] Confirm downstream Playwright E2E run against the resolved preview
URL succeeds
- [ ] Confirm the step still fails cleanly (clear error, no silent hang)
if the Vercel deployment itself fails
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary by CodeRabbit
* **Bug Fixes**
* Improved documentation preview deployment handling in end-to-end
tests.
* Replaced the preview wait logic with more reliable polling for the
relevant commit status, including clear success/failure/error and
timeout behavior.
* Resolve the correct documentation preview URL before tests proceed.
* **Chores**
* Tightened permissions for the documentation E2E workflow to use only
the required access scopes.
* Streamlined job setup steps so Node/Pnpm preparation runs earlier in
the workflow.
---------
Co-authored-by: Claude Sonnet 5
---
.github/workflows/docs-e2e.yml | 41 ++++++-----
scripts/waitForVercelDocsPreview.js | 108 ++++++++++++++++++++++++++++
2 files changed, 132 insertions(+), 17 deletions(-)
create mode 100644 scripts/waitForVercelDocsPreview.js
diff --git a/.github/workflows/docs-e2e.yml b/.github/workflows/docs-e2e.yml
index eae790a43ed97..f27fa3a407d18 100644
--- a/.github/workflows/docs-e2e.yml
+++ b/.github/workflows/docs-e2e.yml
@@ -25,7 +25,6 @@ concurrency:
permissions:
contents: read
- deployments: read
statuses: read
pull-requests: read
@@ -45,8 +44,20 @@ jobs:
persist-credentials: false
sparse-checkout: |
e2e/docs
+ scripts
patches
+ - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+ name: Install pnpm
+ with:
+ run_install: false
+
+ - name: Use Node.js
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
+ with:
+ node-version-file: '.nvmrc'
+ cache: 'pnpm'
+
# Vercel skips the docs preview when a PR only changes the harness
# (e2e/docs, workflow). Wait for a preview only when apps/docs changed.
- name: Detect docs app changes
@@ -58,14 +69,21 @@ jobs:
docs_app:
- 'apps/docs/**'
+ # Vercel's GitHub App stopped writing GitHub Deployment objects on
+ # 2026-02-17 (broken app auth), so vercel/wait-for-deployment-action
+ # times out polling that API even though the preview builds fine.
+ # Poll the "Vercel – docs" commit status instead — Vercel keeps posting
+ # those — then resolve the deployment it points to via Vercel's own API
+ # to get the actual preview URL. See scripts/waitForVercelDocsPreview.js.
- name: Wait for Vercel docs preview
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && steps.filter.outputs.docs_app == 'true'
id: deployment
- uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
- with:
- project-slug: docs
- environment: preview
- timeout: '900'
+ run: node scripts/waitForVercelDocsPreview.js
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
+ VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
+ VERCEL_TEAM_ID: ${{ secrets.VERCEL_TEAM_ID }}
- name: Resolve base URL
id: base-url
@@ -87,17 +105,6 @@ jobs:
echo "use_bypass=false" >> "$GITHUB_OUTPUT"
fi
- - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
- name: Install pnpm
- with:
- run_install: false
-
- - name: Use Node.js
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
- with:
- node-version-file: '.nvmrc'
- cache: 'pnpm'
-
- name: Install dependencies
run: pnpm install --frozen-lockfile --filter=e2e-docs...
diff --git a/scripts/waitForVercelDocsPreview.js b/scripts/waitForVercelDocsPreview.js
new file mode 100644
index 0000000000000..781d62370ba9f
--- /dev/null
+++ b/scripts/waitForVercelDocsPreview.js
@@ -0,0 +1,108 @@
+// Vercel's GitHub App has stopped writing GitHub Deployment objects since
+// 2026-02-17 (broken app auth), so polling the Deployments API (as
+// vercel/wait-for-deployment-action does) times out even though the docs
+// preview builds fine. Poll the "Vercel – docs" commit status instead, then
+// resolve the actual preview URL via Vercel's own deployments API.
+const { appendFileSync } = require('fs')
+
+const STATUS_CONTEXT = 'Vercel – docs'
+const TIMEOUT_MS = 900_000
+const POLL_INTERVAL_MS = 15_000
+
+async function fetchLatestStatus(repository, sha, githubToken) {
+ const url = `https://api.github.com/repos/${repository}/commits/${sha}/statuses`
+ const response = await fetch(url, {
+ headers: {
+ Authorization: `Bearer ${githubToken}`,
+ Accept: 'application/vnd.github+json',
+ },
+ })
+
+ if (!response.ok) {
+ throw new Error(`Failed to fetch commit statuses: ${response.status} ${response.statusText}`)
+ }
+
+ const statuses = await response.json()
+
+ return statuses
+ .filter((status) => status.context === STATUS_CONTEXT)
+ .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0]
+}
+
+async function resolveDeploymentUrl(targetUrl, vercelToken, teamId) {
+ const rawId = targetUrl.split('/').filter(Boolean).pop()
+ if (!rawId) {
+ throw new Error(`Could not parse a deployment ID from target_url: ${targetUrl}`)
+ }
+ const deploymentId = rawId.startsWith('dpl_') ? rawId : `dpl_${rawId}`
+
+ const url = teamId
+ ? `https://api.vercel.com/v13/deployments/${deploymentId}?teamId=${teamId}`
+ : `https://api.vercel.com/v13/deployments/${deploymentId}`
+
+ const response = await fetch(url, {
+ headers: { Authorization: `Bearer ${vercelToken}` },
+ })
+
+ if (!response.ok) {
+ throw new Error(
+ `Failed to resolve Vercel deployment ${deploymentId}: ${response.status} ${response.statusText}`
+ )
+ }
+
+ const deployment = await response.json()
+ return `https://${deployment.url}`
+}
+
+function writeOutput(name, value) {
+ const outputFile = process.env.GITHUB_OUTPUT
+ if (!outputFile) {
+ throw new Error('GITHUB_OUTPUT environment variable is required')
+ }
+ appendFileSync(outputFile, `${name}=${value}\n`)
+}
+
+async function main() {
+ const repository = process.env.GITHUB_REPOSITORY
+ const sha = process.env.HEAD_SHA
+ const githubToken = process.env.GITHUB_TOKEN
+ const vercelToken = process.env.VERCEL_TOKEN
+ const teamId = process.env.VERCEL_TEAM_ID
+
+ if (!repository) throw new Error('GITHUB_REPOSITORY environment variable is required')
+ if (!sha) throw new Error('HEAD_SHA environment variable is required')
+ if (!githubToken) throw new Error('GITHUB_TOKEN environment variable is required')
+ if (!vercelToken) throw new Error('VERCEL_TOKEN environment variable is required')
+
+ const start = Date.now()
+
+ for (;;) {
+ const latest = await fetchLatestStatus(repository, sha, githubToken)
+
+ if (latest?.state === 'success') {
+ if (!latest.target_url) {
+ throw new Error(
+ 'Vercel docs commit status succeeded but had no target_url to resolve a deployment from'
+ )
+ }
+ const deploymentUrl = await resolveDeploymentUrl(latest.target_url, vercelToken, teamId)
+ writeOutput('deployment-url', deploymentUrl)
+ return
+ }
+
+ if (latest?.state === 'failure' || latest?.state === 'error') {
+ throw new Error(`Vercel docs deployment failed (commit status: ${latest.state})`)
+ }
+
+ if (Date.now() - start > TIMEOUT_MS) {
+ throw new Error('Timed out after 900s waiting for the Vercel docs preview deployment')
+ }
+
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS))
+ }
+}
+
+main().catch((error) => {
+ console.error('Fatal error:', error)
+ process.exit(1)
+})
From b6e574e5cd4672dee433aae0ed773f02b9bf13da Mon Sep 17 00:00:00 2001
From: shaziya <99940835+shaziyabandukia@users.noreply.github.com>
Date: Thu, 23 Jul 2026 12:19:55 -0700
Subject: [PATCH 3/4] fix(www): stop on-demand mdx events from winning the
events marquee (#48264)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Bug fix — the [events index](https://supabase.com/events) was featuring
the TRAE webinar in its marquee days after the event happened, instead
of the next genuinely upcoming event (the Dublin meetup), and counting
it toward the "Webinar" filter chip alongside actually-upcoming
webinars.
## What is the current behavior?
`getMdxEvents()` in `lib/events.ts` only excludes past events by
comparing dates against the start of today in UTC. It doesn't check
`onDemand` at all. The TRAE event's timestamp
(`2026-07-22T19:00:00.000-07:00`) converts to `2026-07-23T02:00:00Z`,
which is still "today or later" by that UTC cutoff — so even though the
event already happened and flipped to `onDemand: true`, it kept getting
returned as an "upcoming" event. Since the events marquee
(`featuredEvent`) just picks the earliest-dated event from that pool,
TRAE kept winning over the actually-upcoming Dublin meetup, and it kept
counting toward the "Webinar" filter chip.
## What is the new behavior?
`getMdxEvents()` now excludes any event with `onDemand: true` outright,
regardless of how its date converts across timezones — on-demand events
belong solely in the on-demand bucket (`getOnDemandMdxEvents`), not the
upcoming/marquee pool. Verified locally: the "Webinar" filter chip count
on `/events` drops to 0 with this in place (previously counted TRAE),
while the TRAE event's card in the on-demand list still correctly shows
its "Webinar" tag and "Supabase Live" line, matching the other on-demand
webinars (Perplexity, Datadog) — only its bucket assignment changed, not
its labeling.
## Additional context
Couldn't verify the marquee itself locally since the Luma events API
returns a 500 in local dev (missing credentials, pre-existing/unrelated
to this change). Confirmed independently via the production Luma API
that the Dublin meetup (`2026-07-28T17:00:00Z`) is genuinely the next
chronological event, so it will naturally take over the marquee once
this ships — no hardcoding needed.
## Summary by CodeRabbit
* **Bug Fixes**
* On-demand events are no longer shown in the upcoming events list.
* Upcoming events continue to be filtered by their relevant date, while
on-demand event listings remain unchanged.
---
apps/www/lib/events.ts | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/apps/www/lib/events.ts b/apps/www/lib/events.ts
index 72f5db708abf3..d5cda293d0009 100644
--- a/apps/www/lib/events.ts
+++ b/apps/www/lib/events.ts
@@ -269,10 +269,15 @@ function getAllParsedMdxEvents(): SupabaseEvent[] {
/**
* Read all events under `_events/` and return today-and-future events.
* Past events are excluded (by end_date when present, otherwise start date).
+ * Events already flipped to `onDemand: true` are excluded too — they've
+ * already happened and belong in the on-demand bucket (getOnDemandMdxEvents),
+ * not the upcoming one, regardless of how their UTC-converted date compares to today.
*/
export const getMdxEvents = (): SupabaseEvent[] => {
const today = startOfTodayUtc()
- return getAllParsedMdxEvents().filter((event) => new Date(event.end_date ?? event.date) >= today)
+ return getAllParsedMdxEvents().filter(
+ (event) => !event.onDemand && new Date(event.end_date ?? event.date) >= today
+ )
}
/** All MDX events with `onDemand: true`, including past recordings. */
From f65360051786540769c0b69c630e9ecf9ddcbc71 Mon Sep 17 00:00:00 2001
From: Ali Waseem
Date: Thu, 23 Jul 2026 14:02:10 -0600
Subject: [PATCH 4/4] fix(studio): make failed Postgres upgrade banner
dismissible (#48260)
- The failed-upgrade banner reflects the API's last-known upgrade
status, which stays "Failed" indefinitely even after a project is
restored, so it never went away
- A hard refresh didn't help, since this isn't client-cached state
- Adds a dismiss action, scoped to the attempt's `initiated_at` so a
future failed upgrade still shows the banner
Fixes FE-3964
## Summary by CodeRabbit
* **New Features**
* Added a dismiss control to project upgrade failure notifications.
* Dismissed notifications remain hidden for the current project until a
new upgrade failure occurs.
* Contact support remains available alongside the dismiss option.
* **Bug Fixes**
* Improved upgrade failure banner behavior by persisting dismissal state
across page visits.
---
.../ui/ProjectUpgradeFailedBanner.tsx | 46 +++++++++++++------
packages/common/constants/local-storage.ts | 2 +
2 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/apps/studio/components/ui/ProjectUpgradeFailedBanner.tsx b/apps/studio/components/ui/ProjectUpgradeFailedBanner.tsx
index e80fc755f57ac..53b24331c066a 100644
--- a/apps/studio/components/ui/ProjectUpgradeFailedBanner.tsx
+++ b/apps/studio/components/ui/ProjectUpgradeFailedBanner.tsx
@@ -1,13 +1,16 @@
import { SupportCategories } from '@supabase/shared-types/out/constants'
import { DatabaseUpgradeStatus } from '@supabase/shared-types/out/events'
-import { useParams } from 'common'
+import { LOCAL_STORAGE_KEYS, useParams } from 'common'
import dayjs from 'dayjs'
+import { X } from 'lucide-react'
import { Button } from 'ui'
import { Admonition } from 'ui-patterns/admonition'
+import { ButtonTooltip } from './ButtonTooltip'
import { InlineLink } from './InlineLink'
import { SupportLink } from '@/components/interfaces/Support/SupportLink'
import { useProjectUpgradingStatusQuery } from '@/data/config/project-upgrade-status-query'
+import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
import { useShowPostgresUpgradeLogs } from '@/hooks/misc/useShowPostgresUpgradeLogs'
import { IS_PLATFORM } from '@/lib/constants'
import { guessLocalTimezone } from '@/lib/dayjs'
@@ -20,7 +23,12 @@ export const ProjectUpgradeFailedBanner = () => {
const { status, initiated_at, latest_status_at, error } = data?.databaseUpgradeStatus ?? {}
const showPostgresUpgradeLogs = useShowPostgresUpgradeLogs()
- const isFailed = status === DatabaseUpgradeStatus.Failed
+ const [dismissedAt, setDismissedAt] = useLocalStorageQuery(
+ LOCAL_STORAGE_KEYS.PROJECT_UPGRADE_FAILED_BANNER_DISMISSED_AT(ref ?? 'unknown'),
+ null
+ )
+
+ const isFailed = status === DatabaseUpgradeStatus.Failed && initiated_at !== dismissedAt
const initiatedAt = dayjs
.utc(initiated_at ?? 0)
.tz(guessLocalTimezone())
@@ -48,18 +56,28 @@ export const ProjectUpgradeFailedBanner = () => {
type="warning"
title={`Postgres version upgrade was not successful (Initiated at ${initiatedAt})`}
actions={
-
+ <>
+
+ }
+ variant="text"
+ className="w-6"
+ tooltip={{ content: { side: 'bottom', text: 'Dismiss' } }}
+ aria-label="Dismiss upgrade failed banner"
+ onClick={() => setDismissedAt(initiated_at ?? null)}
+ />
+ >
}
>