From 8798e40da8d56b2f0f3be0b74198d0cbbec1dc06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Sat, 26 Sep 2026 15:26:19 +0000 Subject: [PATCH] fix(registry): carousel cards fall back to their sample image inside the assets folder (#4543) * fix(registry): carousel cards fall back to their sample image inside the assets folder When an image variable resolves to nothing, the 25 carousel blocks loaded the sample card by bare file name, which 404s beside the block and draws a white card. The fallback now keeps assets/carousel-images/, the folder every card image is installed into. A guard test fails on any block with a bare fallback. * test(registry): the carousel fallback guard covers every block that uses it The guard now picks each block that reads an image variable and fails when its fallback no longer matches, instead of silently skipping it, and ignores stray files in the blocks folder. --- .../carousel-circle-1/carousel-circle-1.html | 3 +- .../carousel-circle-2/carousel-circle-2.html | 3 +- .../carousel-circle-3/carousel-circle-3.html | 3 +- .../carousel-circle-4/carousel-circle-4.html | 3 +- .../carousel-circle-5/carousel-circle-5.html | 3 +- .../carousel-orbit-1/carousel-orbit-1.html | 3 +- .../carousel-orbit-2/carousel-orbit-2.html | 3 +- .../carousel-orbit-3/carousel-orbit-3.html | 3 +- .../carousel-orbit-4/carousel-orbit-4.html | 3 +- .../carousel-orbit-5/carousel-orbit-5.html | 3 +- .../carousel-path-1/carousel-path-1.html | 3 +- .../carousel-path-2/carousel-path-2.html | 3 +- .../carousel-path-3/carousel-path-3.html | 3 +- .../carousel-path-4/carousel-path-4.html | 3 +- .../carousel-path-5/carousel-path-5.html | 3 +- .../carousel-text-circle-1.html | 3 +- .../carousel-text-circle-2.html | 3 +- .../carousel-text-circle-3.html | 3 +- .../carousel-text-circle-4.html | 3 +- .../carousel-text-circle-5.html | 3 +- .../carousel-vision-1/carousel-vision-1.html | 3 +- .../carousel-vision-2/carousel-vision-2.html | 3 +- .../carousel-vision-3/carousel-vision-3.html | 3 +- .../carousel-vision-4/carousel-vision-4.html | 3 +- .../carousel-vision-5/carousel-vision-5.html | 3 +- scripts/catalog/carousel-fallback.test.ts | 34 +++++++++++++++++++ 26 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 scripts/catalog/carousel-fallback.test.ts diff --git a/registry/blocks/carousel-circle-1/carousel-circle-1.html b/registry/blocks/carousel-circle-1/carousel-circle-1.html index 88f94f8ca0..c9da58b5f1 100644 --- a/registry/blocks/carousel-circle-1/carousel-circle-1.html +++ b/registry/blocks/carousel-circle-1/carousel-circle-1.html @@ -628,7 +628,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-circle-2/carousel-circle-2.html b/registry/blocks/carousel-circle-2/carousel-circle-2.html index 63eff2bf13..2be49ff521 100644 --- a/registry/blocks/carousel-circle-2/carousel-circle-2.html +++ b/registry/blocks/carousel-circle-2/carousel-circle-2.html @@ -628,7 +628,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-circle-3/carousel-circle-3.html b/registry/blocks/carousel-circle-3/carousel-circle-3.html index f84efe754c..36894b19bc 100644 --- a/registry/blocks/carousel-circle-3/carousel-circle-3.html +++ b/registry/blocks/carousel-circle-3/carousel-circle-3.html @@ -628,7 +628,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-circle-4/carousel-circle-4.html b/registry/blocks/carousel-circle-4/carousel-circle-4.html index 47af0c728d..1486f6d017 100644 --- a/registry/blocks/carousel-circle-4/carousel-circle-4.html +++ b/registry/blocks/carousel-circle-4/carousel-circle-4.html @@ -628,7 +628,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-circle-5/carousel-circle-5.html b/registry/blocks/carousel-circle-5/carousel-circle-5.html index 718aba5518..3e3e826f5b 100644 --- a/registry/blocks/carousel-circle-5/carousel-circle-5.html +++ b/registry/blocks/carousel-circle-5/carousel-circle-5.html @@ -628,7 +628,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-orbit-1/carousel-orbit-1.html b/registry/blocks/carousel-orbit-1/carousel-orbit-1.html index 9d2ca52c78..fdd1f3dedf 100644 --- a/registry/blocks/carousel-orbit-1/carousel-orbit-1.html +++ b/registry/blocks/carousel-orbit-1/carousel-orbit-1.html @@ -650,7 +650,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-orbit-2/carousel-orbit-2.html b/registry/blocks/carousel-orbit-2/carousel-orbit-2.html index 61d80eb386..99a9019af0 100644 --- a/registry/blocks/carousel-orbit-2/carousel-orbit-2.html +++ b/registry/blocks/carousel-orbit-2/carousel-orbit-2.html @@ -650,7 +650,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-orbit-3/carousel-orbit-3.html b/registry/blocks/carousel-orbit-3/carousel-orbit-3.html index 257bf717b3..c07cb23073 100644 --- a/registry/blocks/carousel-orbit-3/carousel-orbit-3.html +++ b/registry/blocks/carousel-orbit-3/carousel-orbit-3.html @@ -650,7 +650,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-orbit-4/carousel-orbit-4.html b/registry/blocks/carousel-orbit-4/carousel-orbit-4.html index e529a037a7..d1cfeeac9f 100644 --- a/registry/blocks/carousel-orbit-4/carousel-orbit-4.html +++ b/registry/blocks/carousel-orbit-4/carousel-orbit-4.html @@ -666,7 +666,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-orbit-5/carousel-orbit-5.html b/registry/blocks/carousel-orbit-5/carousel-orbit-5.html index ca047c5157..c9a1706de8 100644 --- a/registry/blocks/carousel-orbit-5/carousel-orbit-5.html +++ b/registry/blocks/carousel-orbit-5/carousel-orbit-5.html @@ -650,7 +650,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-path-1/carousel-path-1.html b/registry/blocks/carousel-path-1/carousel-path-1.html index 6774c4209e..6470f31baa 100644 --- a/registry/blocks/carousel-path-1/carousel-path-1.html +++ b/registry/blocks/carousel-path-1/carousel-path-1.html @@ -672,7 +672,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-path-2/carousel-path-2.html b/registry/blocks/carousel-path-2/carousel-path-2.html index 417bcd8904..dff6db7621 100644 --- a/registry/blocks/carousel-path-2/carousel-path-2.html +++ b/registry/blocks/carousel-path-2/carousel-path-2.html @@ -629,7 +629,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-path-3/carousel-path-3.html b/registry/blocks/carousel-path-3/carousel-path-3.html index 5dd866b7ca..781ba59627 100644 --- a/registry/blocks/carousel-path-3/carousel-path-3.html +++ b/registry/blocks/carousel-path-3/carousel-path-3.html @@ -643,7 +643,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-path-4/carousel-path-4.html b/registry/blocks/carousel-path-4/carousel-path-4.html index b75a769378..bcfc20d73c 100644 --- a/registry/blocks/carousel-path-4/carousel-path-4.html +++ b/registry/blocks/carousel-path-4/carousel-path-4.html @@ -672,7 +672,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-path-5/carousel-path-5.html b/registry/blocks/carousel-path-5/carousel-path-5.html index 32390f07b2..e173a4e77d 100644 --- a/registry/blocks/carousel-path-5/carousel-path-5.html +++ b/registry/blocks/carousel-path-5/carousel-path-5.html @@ -671,7 +671,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-text-circle-1/carousel-text-circle-1.html b/registry/blocks/carousel-text-circle-1/carousel-text-circle-1.html index 34ffb7a9c9..4b5e22f227 100644 --- a/registry/blocks/carousel-text-circle-1/carousel-text-circle-1.html +++ b/registry/blocks/carousel-text-circle-1/carousel-text-circle-1.html @@ -669,7 +669,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-text-circle-2/carousel-text-circle-2.html b/registry/blocks/carousel-text-circle-2/carousel-text-circle-2.html index 901771fbfe..6378e8334f 100644 --- a/registry/blocks/carousel-text-circle-2/carousel-text-circle-2.html +++ b/registry/blocks/carousel-text-circle-2/carousel-text-circle-2.html @@ -669,7 +669,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-text-circle-3/carousel-text-circle-3.html b/registry/blocks/carousel-text-circle-3/carousel-text-circle-3.html index 12450db1e6..aa5434cdee 100644 --- a/registry/blocks/carousel-text-circle-3/carousel-text-circle-3.html +++ b/registry/blocks/carousel-text-circle-3/carousel-text-circle-3.html @@ -669,7 +669,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-text-circle-4/carousel-text-circle-4.html b/registry/blocks/carousel-text-circle-4/carousel-text-circle-4.html index 8b07b94d9e..d6fa6f74cc 100644 --- a/registry/blocks/carousel-text-circle-4/carousel-text-circle-4.html +++ b/registry/blocks/carousel-text-circle-4/carousel-text-circle-4.html @@ -669,7 +669,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-text-circle-5/carousel-text-circle-5.html b/registry/blocks/carousel-text-circle-5/carousel-text-circle-5.html index 00e584b5c2..e7ed9d668d 100644 --- a/registry/blocks/carousel-text-circle-5/carousel-text-circle-5.html +++ b/registry/blocks/carousel-text-circle-5/carousel-text-circle-5.html @@ -669,7 +669,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-vision-1/carousel-vision-1.html b/registry/blocks/carousel-vision-1/carousel-vision-1.html index e71d8a39ae..33334d2f03 100644 --- a/registry/blocks/carousel-vision-1/carousel-vision-1.html +++ b/registry/blocks/carousel-vision-1/carousel-vision-1.html @@ -632,7 +632,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-vision-2/carousel-vision-2.html b/registry/blocks/carousel-vision-2/carousel-vision-2.html index edfc82bdff..e71cd9629f 100644 --- a/registry/blocks/carousel-vision-2/carousel-vision-2.html +++ b/registry/blocks/carousel-vision-2/carousel-vision-2.html @@ -632,7 +632,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-vision-3/carousel-vision-3.html b/registry/blocks/carousel-vision-3/carousel-vision-3.html index 5c46502124..e9d0e27dfe 100644 --- a/registry/blocks/carousel-vision-3/carousel-vision-3.html +++ b/registry/blocks/carousel-vision-3/carousel-vision-3.html @@ -632,7 +632,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-vision-4/carousel-vision-4.html b/registry/blocks/carousel-vision-4/carousel-vision-4.html index 633480a496..9f101318df 100644 --- a/registry/blocks/carousel-vision-4/carousel-vision-4.html +++ b/registry/blocks/carousel-vision-4/carousel-vision-4.html @@ -639,7 +639,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/registry/blocks/carousel-vision-5/carousel-vision-5.html b/registry/blocks/carousel-vision-5/carousel-vision-5.html index ea02154c60..a58968f501 100644 --- a/registry/blocks/carousel-vision-5/carousel-vision-5.html +++ b/registry/blocks/carousel-vision-5/carousel-vision-5.html @@ -632,7 +632,8 @@ const varUrl = (v) => (v && typeof v === "object" ? v.url || v.src || "" : v || ""); if (REG) { const srcs = REG.imageVars.map( - (id, i) => varUrl(V[id]) || DATA.cards[i % DATA.cards.length].file, + (id, i) => + varUrl(V[id]) || "assets/carousel-images/" + DATA.cards[i % DATA.cards.length].file, ); DATA.cards = await Promise.all( srcs.map(async (src, i) => { diff --git a/scripts/catalog/carousel-fallback.test.ts b/scripts/catalog/carousel-fallback.test.ts new file mode 100644 index 0000000000..71a0129216 --- /dev/null +++ b/scripts/catalog/carousel-fallback.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; + +const blocksDir = join(import.meta.dirname, "..", "..", "registry", "blocks"); + +// The carousels draw each card from its image variable, or from the block's own +// sample image when the variable resolves to nothing. +const FALLBACK = /varUrl\(V\[id\]\)\s*\|\|\s*([^\n]*)DATA\.cards\[i % DATA\.cards\.length\]\.file/g; + +function carousels(): Array<{ block: string; prefixes: string[] }> { + return readdirSync(blocksDir, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map(({ name }) => ({ + block: name, + html: readFileSync(join(blocksDir, name, `${name}.html`), "utf8"), + })) + .filter(({ html }) => html.includes("varUrl(V[id])")) + .map(({ block, html }) => ({ + block, + prefixes: [...html.matchAll(FALLBACK)].map((match) => match[1] ?? ""), + })); +} + +describe("carousel image fallback", () => { + it("loads the sample image from the block's assets folder, not a bare file name", () => { + const found = carousels(); + expect(found.length).toBeGreaterThan(0); + for (const { block, prefixes } of found) { + expect(prefixes.length, block).toBeGreaterThan(0); + for (const prefix of prefixes) expect(prefix, block).toContain('"assets/carousel-images/" +'); + } + }); +});