@epic-web/workshop-app 6.50.2 → 6.50.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../app/entry.server.tsx","../../../workshop-presence/src/presence.ts","../../../workshop-presence/src/presence.server.ts","../../app/components/confetti.tsx","../../app/assets/icons.svg","../../app/components/icons.tsx","../../app/utils/misc.tsx","../../app/components/error-boundary.tsx","../../app/components/exercise-warning-banner.tsx","../../app/components/ui/dialog.tsx","../../app/components/keyboard-shortcuts-dialog.tsx","../../app/components/progress-bar.tsx","../../app/components/toaster.tsx","../../app/components/ui/tooltip.tsx","../../app/components/update-repo.tsx","../../app/routes/admin+/notifications.tsx","../../app/utils/root-loader.ts","../../app/utils/client-hints.tsx","../../app/utils/forms.tsx","../../app/utils/pe.tsx","../../app/routes/theme/theme-session.server.ts","../../app/routes/theme/index.tsx","../../app/styles/app.css?url","../../app/styles/tailwind.css?url","../../app/utils/confetti.server.ts","../../app/utils/online.ts","../../app/utils/presence.tsx","../../app/utils/seo.ts","../../app/utils/toast.server.ts","../../app/root.tsx","../../app/routes/$.tsx","../../app/components/media-query.ts","../../app/components/workshop-config.tsx","../../app/components/product.tsx","../../app/components/revalidation-ws.tsx","../../app/components/user.tsx","../../app/routes/progress.tsx","../../app/routes/_app+/_layout.tsx","../../app/components/button.tsx","../../app/routes/_app+/account.tsx","../../app/utils/compile-app.server.ts","../../app/routes/_app+/app.$appName+/__utils.ts","../../app/routes/_app+/app.$appName+/$.ts","../../app/routes/_app+/app.$appName+/api.$.ts","../../app/routes/_app+/app.$appName+/epic_ws[.js].ts","../../app/routes/_app+/app.$appName+/index.ts","../../app/routes/_app+/app.$appName+/test.$testName.ts","../../app/routes/_app+/discord.tsx","../../app/routes/_app+/exercise+/_layout.tsx","../../app/routes/video-player/index.tsx","../../app/components/loading.tsx","../../app/components/epic-video.tsx","../../app/routes/launch-editor.tsx","../../app/components/mermaid.tsx","../../app/utils/mdx.tsx","../../app/routes/_app+/exercise+/__shared/error-boundary.server.ts","../../app/routes/_app+/exercise+/__shared/error-boundary.tsx","../../app/routes/_app+/exercise+/$exerciseNumber.tsx","../../app/components/nav-chevrons.tsx","../../app/routes/set-playground.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/step-mdx.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/touched-files.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/_layout.tsx","../../app/routes/start.tsx","../../app/components/in-browser-browser.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/preview.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/utils.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/app.tsx","../../app/components/accordion.tsx","../../app/components/diff.tsx","../../app/components/status-indicator.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/discord.server.ts","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/discord.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/playground-window.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/playground.tsx","../../app/utils/ansi-text.ts","../../app/components/in-browser-test-runner.tsx","../../app/routes/test.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/tests.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/index.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/test.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.index.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.finished.tsx","../../app/routes/_app+/finished.tsx","../../app/routes/_app+/index.tsx","../../app/routes/_app+/l.tsx","../../app/utils/auth-events.ts","../../app/utils/auth.server.ts","../../app/routes/login-sse.tsx","../../app/routes/_app+/login.tsx","../../app/routes/_app+/preferences.tsx","../../app/routes/_app+/support.tsx","../../app/routes/_app+/workspace-structure.tsx","../../app/routes/admin+/_layout.tsx","../../app/routes/admin+/apps.tsx","../../app/routes/admin+/cache.tsx","../../app/routes/admin+/cache.$.ts","../../app/routes/admin+/db.tsx","../../app/routes/admin+/admin-utils.server.tsx","../../app/routes/admin+/index.tsx","../../app/routes/admin+/version.tsx","../../app/routes/apps.tsx","../../app/routes/diff.tsx","../../app/routes/diff.$shortcut.tsx","../../app/routes/exercises.tsx","../../app/routes/mcp-ui+/__utils.ts","../../app/routes/mcp-ui+/epic-video.tsx","../../app/routes/og.tsx","../../app/routes/processes.tsx","../../app/routes/resources+/healthcheck.ts","../../app/routes/resources+/lookout.ts","../../app/routes/robots[.]txt.ts","../../app/routes/sitemap[.]xml.ts"],"sourcesContent":["import { PassThrough } from 'stream'\nimport { createReadableStreamFromReadable } from '@react-router/node'\n// Dynamic import of Sentry with error handling\nconst sentryPromise = import('@sentry/react-router').catch((error) => {\n\tconsole.warn(\n\t\t'Failed to import @sentry/react-router:',\n\t\terror instanceof Error ? error.message : String(error),\n\t\t'- Sentry monitoring will be disabled but the application will continue to work normally',\n\t)\n\treturn null\n})\n\nimport { isbot } from 'isbot'\nimport { renderToPipeableStream } from 'react-dom/server'\nimport {\n\ttype EntryContext,\n\tServerRouter,\n\ttype LoaderFunctionArgs,\n\ttype ActionFunctionArgs,\n} from 'react-router'\n\nexport const streamTimeout = 60000\nconst ABORT_DELAY = streamTimeout + 1000\n\nexport async function handleError(\n\terror: unknown,\n\t{ request }: LoaderFunctionArgs | ActionFunctionArgs,\n): Promise<void> {\n\tif (request.signal.aborted) return\n\t// Don't send errors to Sentry for bot requests\n\tif (isbot(request.headers.get('user-agent'))) return\n\tif (ENV.EPICSHOP_IS_PUBLISHED) {\n\t\tconst Sentry = await sentryPromise\n\t\tSentry?.captureException(error)\n\t}\n}\n\nexport default function handleRequest(\n\trequest: Request,\n\tresponseStatusCode: number,\n\tresponseHeaders: Headers,\n\treactRouterContext: EntryContext,\n) {\n\tconst callbackName = isbot(request.headers.get('user-agent'))\n\t\t? 'onAllReady'\n\t\t: 'onShellReady'\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet didError = false\n\n\t\tconst { pipe, abort } = renderToPipeableStream(\n\t\t\t<ServerRouter context={reactRouterContext} url={request.url} />,\n\t\t\t{\n\t\t\t\t[callbackName]() {\n\t\t\t\t\tconst body = new PassThrough()\n\n\t\t\t\t\tresponseHeaders.set('Content-Type', 'text/html')\n\n\t\t\t\t\tif (ENV.EPICSHOP_IS_PUBLISHED && process.env.SENTRY_DSN) {\n\t\t\t\t\t\tresponseHeaders.append('Document-Policy', 'js-profiling')\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tnew Response(createReadableStreamFromReadable(body), {\n\t\t\t\t\t\t\tstatus: didError ? 500 : responseStatusCode,\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\tpipe(body)\n\t\t\t\t},\n\t\t\t\tonShellError(err: unknown) {\n\t\t\t\t\treject(err)\n\t\t\t\t},\n\t\t\t\tonError(error: unknown) {\n\t\t\t\t\tdidError = true\n\t\t\t\t\tconsole.error(error)\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\tsetTimeout(abort, ABORT_DELAY)\n\t})\n}\n","import { z } from 'zod'\n\nexport const partykitRoom = 'epic-web-presence'\n// export const partykitBaseUrl = `http://127.0.0.1:1999/parties/main/${partykitRoom}`\nexport const partykitBaseUrl = `https://epic-web-presence.kentcdodds.partykit.dev/parties/main/${partykitRoom}`\n\nexport const RepoStatusSchema = z.object({\n\tupdatesAvailable: z.boolean().nullable().optional(),\n\tcommitsAhead: z.number().nullable().optional(),\n\tcommitsBehind: z.number().nullable().optional(),\n\tlocalCommit: z.string().nullable().optional(),\n\tremoteCommit: z.string().nullable().optional(),\n})\n\nexport type RepoStatus = z.infer<typeof RepoStatusSchema>\n\nexport const LocationSchema = z.object({\n\tworkshopTitle: z.string().nullable().optional(),\n\torigin: z.string().nullable().optional(),\n\tproductHost: z.string().nullable().optional(),\n\texercise: z\n\t\t.object({\n\t\t\ttype: z\n\t\t\t\t.union([z.literal('problem'), z.literal('solution')])\n\t\t\t\t.nullable()\n\t\t\t\t.optional(),\n\t\t\texerciseNumber: z.number().nullable().optional(),\n\t\t\tstepNumber: z.number().nullable().optional(),\n\t\t})\n\t\t.nullable()\n\t\t.optional(),\n\t// Version of the epicshop app for this location/workshop\n\tepicshopVersion: z.string().nullable().optional(),\n\t// Repository status (updates available, commits ahead/behind) for this location/workshop\n\trepoStatus: RepoStatusSchema.nullable().optional(),\n\t// ISO timestamp of when the user last sent an update for this location (server-set)\n\tlastUpdatedAt: z.string().nullable().optional(),\n})\n\nexport type Location = z.infer<typeof LocationSchema>\n\nexport const UserSchema = z.object({\n\tid: z.string(),\n\thasAccess: z.boolean().nullable().optional(),\n\t// TODO: remove the avatarUrl field once people have updated their workshops\n\tavatarUrl: z.string().nullable().optional(),\n\timageUrlSmall: z.string().nullable().optional(),\n\timageUrlLarge: z.string().nullable().optional(),\n\tname: z.string().nullable().optional(),\n\toptOut: z.boolean().nullable().optional(),\n\tloggedInProductHosts: z.array(z.string()).nullable().optional(),\n\t// Single location (for backward compat and single-connection case)\n\tlocation: LocationSchema.nullable().optional(),\n\t// Multiple locations when user is connected from multiple workshops\n\tlocations: z.array(LocationSchema).nullable().optional(),\n})\n\nexport const MessageSchema = z\n\t.object({\n\t\ttype: z.literal('remove-user'),\n\t\tpayload: z.object({ id: z.string() }),\n\t})\n\t.or(z.object({ type: z.literal('add-user'), payload: UserSchema }))\n\t.or(\n\t\tz.object({\n\t\t\ttype: z.literal('presence'),\n\t\t\tpayload: z.object({ users: z.array(UserSchema) }),\n\t\t}),\n\t)\n\nexport type Message = z.infer<typeof MessageSchema>\n\nexport type User = z.infer<typeof UserSchema>\n\nexport const PresenceSchema = z.object({ users: z.array(UserSchema) })\n\n// Product host to emoji mapping for FacePile badges\nexport const productHostEmojis: Record<string, string> = {\n\t'www.epicreact.dev': '🚀',\n\t'www.epicai.pro': '⚡',\n\t'www.epicweb.dev': '🌌',\n}\n\nexport function getProductHostEmoji(\n\thost: string | null | undefined,\n): string | null {\n\tif (!host) return null\n\treturn productHostEmojis[host] ?? null\n}\n","import {\n\tcachified,\n\tmakeSingletonCache,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetAuthInfo,\n\tgetLoggedInProductHosts,\n\tgetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { getEnv } from '@epic-web/workshop-utils/env.server'\nimport {\n\tgetUserInfo,\n\tuserHasAccessToWorkshop,\n} from '@epic-web/workshop-utils/epic-api.server'\nimport { checkForUpdatesCached } from '@epic-web/workshop-utils/git.server'\nimport { type Timings } from '@epic-web/workshop-utils/timing.server'\nimport { getUserId } from '@epic-web/workshop-utils/user.server'\nimport {\n\tPresenceSchema,\n\tpartykitBaseUrl,\n\ttype Location,\n\ttype RepoStatus,\n\ttype User,\n} from './presence.ts'\n\nexport const presenceCache = makeSingletonCache<Array<User>>('PresenceCache')\n\nexport async function getPresentUsers({\n\ttimings,\n\trequest,\n}: { timings?: Timings; request?: Request } = {}): Promise<Array<User>> {\n\tconst presence = await cachified({\n\t\tkey: 'presence',\n\t\tcache: presenceCache,\n\t\ttimings,\n\t\trequest,\n\t\tttl: 1000 * 2,\n\t\tswr: 1000 * 60 * 60 * 24,\n\t\tofflineFallbackValue: { users: [] },\n\t\tcheckValue: PresenceSchema,\n\t\tasync getFreshValue(context) {\n\t\t\ttry {\n\t\t\t\tconst response = await Promise.race([\n\t\t\t\t\tfetch(`${partykitBaseUrl}/presence`),\n\t\t\t\t\tnew Promise<Response>((resolve) =>\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tresolve(new Response('Timeout', { status: 500 }))\n\t\t\t\t\t\t}, 500),\n\t\t\t\t\t),\n\t\t\t\t] as const)\n\t\t\t\tif (response.statusText === 'Timeout') {\n\t\t\t\t\tthrow new Error(`Timeout fetching partykit presence`)\n\t\t\t\t}\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Unexpected response from partykit: ${response.status} ${response.statusText}`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tconst presence = PresenceSchema.parse(await response.json())\n\t\t\t\treturn presence\n\t\t\t} catch {\n\t\t\t\t// console.error(err)\n\t\t\t\tcontext.metadata.ttl = 300\n\t\t\t\treturn { users: [] }\n\t\t\t}\n\t\t},\n\t})\n\tconst { users } = presence\n\n\tconst authInfo = await getAuthInfo()\n\tconst userId = request\n\t\t? (await getUserId({ request })).id\n\t\t: (authInfo?.id ?? null)\n\n\tconst preferences = await getPreferences()\n\tconst isOptOut = preferences?.presence.optOut ?? false\n\n\t// If no userId, just return other users\n\tif (!userId) {\n\t\treturn uniqueUsers(users)\n\t}\n\n\t// Get logged in product hosts for the local user\n\tconst loggedInProductHosts = await getLoggedInProductHosts()\n\n\t// Get epicshop version and repo status\n\tconst ENV = getEnv()\n\tconst epicshopVersion = ENV.EPICSHOP_APP_VERSION ?? null\n\n\t// Get repo status (updates available, commits ahead/behind)\n\tlet repoStatus: RepoStatus | null = null\n\ttry {\n\t\tconst updateStatus = await checkForUpdatesCached()\n\t\tif ('updatesAvailable' in updateStatus) {\n\t\t\trepoStatus = {\n\t\t\t\tupdatesAvailable: updateStatus.updatesAvailable,\n\t\t\t\tcommitsAhead:\n\t\t\t\t\t'commitsAhead' in updateStatus ? updateStatus.commitsAhead : null,\n\t\t\t\tcommitsBehind:\n\t\t\t\t\t'commitsBehind' in updateStatus ? updateStatus.commitsBehind : null,\n\t\t\t\tlocalCommit:\n\t\t\t\t\t'localCommit' in updateStatus ? updateStatus.localCommit : null,\n\t\t\t\tremoteCommit:\n\t\t\t\t\t'remoteCommit' in updateStatus ? updateStatus.remoteCommit : null,\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors from checking for updates\n\t}\n\n\tconst config = getWorkshopConfig()\n\tconst url = request ? new URL(request.url) : undefined\n\n\t// Build location with version and repo status\n\tconst location: Location = {\n\t\tworkshopTitle: config.title,\n\t\torigin: url ? url.origin : undefined,\n\t\tproductHost: config.product.host,\n\t\tepicshopVersion,\n\t\trepoStatus,\n\t}\n\tif (url) {\n\t\tif (url.pathname.startsWith('/exercise/')) {\n\t\t\tconst [exerciseNumber, stepNumber, type] = url.pathname\n\t\t\t\t.split('/')\n\t\t\t\t.slice(2)\n\t\t\tlocation.exercise = {\n\t\t\t\texerciseNumber: isNaN(Number(exerciseNumber))\n\t\t\t\t\t? null\n\t\t\t\t\t: Number(exerciseNumber),\n\t\t\t\tstepNumber: isNaN(Number(stepNumber)) ? null : Number(stepNumber),\n\t\t\t\ttype:\n\t\t\t\t\ttype === 'problem'\n\t\t\t\t\t\t? 'problem'\n\t\t\t\t\t\t: type === 'solution'\n\t\t\t\t\t\t\t? 'solution'\n\t\t\t\t\t\t\t: null,\n\t\t\t}\n\t\t}\n\t}\n\n\t// If opted out, include user with minimal info but still include location\n\tif (isOptOut) {\n\t\tconst optOutUser: User = {\n\t\t\tid: userId,\n\t\t\toptOut: true,\n\t\t\tloggedInProductHosts,\n\t\t\tlocation,\n\t\t}\n\t\treturn uniqueUsers([...users.filter((u) => u.id !== userId), optOutUser])\n\t}\n\n\t// Build full user info\n\tconst user: User = {\n\t\tid: userId,\n\t\tloggedInProductHosts,\n\t\tlocation,\n\t}\n\n\tif (authInfo) {\n\t\tconst [userInfo, hasAccess] = await Promise.all([\n\t\t\tgetUserInfo({ request, timings }),\n\t\t\tuserHasAccessToWorkshop({ request, timings }),\n\t\t])\n\n\t\tObject.assign(user, {\n\t\t\tname: userInfo?.name,\n\t\t\tavatarUrl: userInfo?.imageUrlLarge,\n\t\t\timageUrlSmall: userInfo?.imageUrlSmall,\n\t\t\timageUrlLarge: userInfo?.imageUrlLarge,\n\t\t\thasAccess,\n\t\t})\n\t}\n\n\treturn uniqueUsers([...users.filter((u) => u.id !== userId), user])\n}\n\n// A user maybe on the same page in multiple tabs\n// so let's make sure we only show them once\nfunction uniqueUsers(users: Array<User>) {\n\tconst seen = new Set()\n\treturn users.filter(Boolean).filter((user) => {\n\t\tif (seen.has(user.id)) {\n\t\t\treturn false\n\t\t}\n\t\tseen.add(user.id)\n\t\treturn true\n\t})\n}\n","import { Index as ConfettiShower } from 'confetti-react'\nimport { ClientOnly } from 'remix-utils/client-only'\n\nexport function Confetti({ id }: { id?: string | null }) {\n\tif (!id) return null\n\n\treturn (\n\t\t<ClientOnly>\n\t\t\t{() => (\n\t\t\t\t<ConfettiShower\n\t\t\t\t\tkey={id}\n\t\t\t\t\trun={Boolean(id)}\n\t\t\t\t\trecycle={false}\n\t\t\t\t\tnumberOfPieces={800}\n\t\t\t\t\twidth={window.innerWidth}\n\t\t\t\t\theight={window.innerHeight}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</ClientOnly>\n\t)\n}\n","export default \"__VITE_ASSET__CMaiXz4u__\"","import * as React from 'react'\nimport iconsSvg from '#app/assets/icons.svg'\nimport { cn } from '#app/utils/misc.tsx'\n\ntype Sizes = 12 | 14 | 16 | 20 | 24 | 28 | 32 | 40\n\n// can't use styles in an external SVG sprite, so animated icons get inlined.\nexport function AnimatedBars({\n\ttitle,\n\tsize = 16,\n\t...props\n}: { title?: string; size?: Sizes } & React.ComponentPropsWithoutRef<'svg'>) {\n\treturn (\n\t\t<svg\n\t\t\twidth={size}\n\t\t\theight={size}\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\taria-hidden={!title}\n\t\t\t{...props}\n\t\t>\n\t\t\t{title ? <title>{title}</title> : null}\n\t\t\t<g fill=\"currentColor\">\n\t\t\t\t<g className=\"nc-loop-dots-16-icon-f\">\n\t\t\t\t\t<circle cx=\"3\" cy=\"8\" fill=\"currentColor\" r=\"2\" />\n\t\t\t\t\t<circle cx=\"8\" cy=\"8\" r=\"2\" />\n\t\t\t\t\t<circle cx=\"13\" cy=\"8\" fill=\"currentColor\" r=\"2\" />\n\t\t\t\t</g>\n\t\t\t\t<style>{`.nc-loop-dots-16-icon-f{--animation-duration:1s}.nc-loop-dots-16-icon-f *{opacity:.4;transform:scale(.7)}.nc-loop-dots-16-icon-f :nth-child(1),.nc-loop-dots-16-icon-f :nth-child(3){animation:nc-loop-dots-anim-2b var(--animation-duration) infinite linear}.nc-loop-dots-16-icon-f :nth-child(1){transform-origin:3px 8px}.nc-loop-dots-16-icon-f :nth-child(2){animation:nc-loop-dots-anim-1b calc(var(--animation-duration)/2) infinite linear;animation-delay:calc(var(--animation-duration)/4);transform-origin:8px 8px}.nc-loop-dots-16-icon-f :nth-child(3){animation-delay:calc(var(--animation-duration)/2);transform-origin:13px 8px}@keyframes nc-loop-dots-anim-1b{0%,100%{opacity:.4;transform:scale(.7)}50%{opacity:1;transform:scale(1)}}@keyframes nc-loop-dots-anim-2b{0%,100%,66%{opacity:.4;transform:scale(.7)}33%{opacity:1;transform:scale(1)}}`}</style>\n\t\t\t</g>\n\t\t</svg>\n\t)\n}\n\nexport type IconName =\n\t| 'Keyboard'\n\t| 'Linked'\n\t| 'Unlinked'\n\t| 'TriangleAlert'\n\t| 'TriangleSmall'\n\t| 'ArrowLeft'\n\t| 'ArrowRight'\n\t| 'Sun'\n\t| 'Moon'\n\t| 'ChevronLeft'\n\t| 'ChevronRight'\n\t| 'ChevronDown'\n\t| 'ChevronUp'\n\t| 'CheckSmall'\n\t| 'TriangleDownSmall'\n\t| 'Question'\n\t| 'Remove'\n\t| 'ExternalLink'\n\t| 'Refresh'\n\t| 'Files'\n\t| 'Clear'\n\t| 'Stop'\n\t| 'Deleted'\n\t| 'Modified'\n\t| 'Added'\n\t| 'Renamed'\n\t| 'Close'\n\t| 'Error'\n\t| 'Notify'\n\t| 'Success'\n\t| 'Sun'\n\t| 'Moon'\n\t| 'Laptop'\n\t| 'Video'\n\t| 'User'\n\t| 'EpicWeb'\n\t| 'EpicWebGradient'\n\t| 'FastForward'\n\t| 'Discord'\n\t| 'Chat'\n\t| 'House'\n\t| 'WifiNoConnection'\n\t| 'Copy'\n\nconst sizeClassName = {\n\tfont: 'w-[1em] h-[1em]',\n\txs: 'w-3 h-3',\n\tsm: 'w-4 h-4',\n\tmd: 'w-5 h-5',\n\tlg: 'w-6 h-6',\n\txl: 'w-7 h-7',\n\t'2xl': 'w-8 h-8',\n} as const\n\ntype Size = keyof typeof sizeClassName\n\nconst childrenSizeClassName = {\n\tfont: 'gap-1.5',\n\txs: 'gap-1.5',\n\tsm: 'gap-1.5',\n\tmd: 'gap-2',\n\tlg: 'gap-2',\n\txl: 'gap-3',\n\t'2xl': 'gap-4',\n} satisfies Record<Size, string>\n\n/**\n * Renders an SVG icon. The icon defaults to the size of the font. To make it\n * align vertically with neighboring text, you can pass the text as a child of\n * the icon and it will be automatically aligned.\n * Alternatively, if you're not ok with the icon being to the left of the text,\n * you need to wrap the icon and text in a common parent and set the parent to\n * display \"flex\" (or \"inline-flex\") with \"items-center\" and a reasonable gap.\n */\nexport function Icon({\n\tname,\n\tsize = 'font',\n\ttitle,\n\tclassName,\n\tchildren,\n\t...props\n}: React.SVGProps<SVGSVGElement> & {\n\tname: IconName\n\ttitle?: string\n\tsize?: Size\n}) {\n\tif (children) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={`inline-flex items-center ${childrenSizeClassName[size]}`}\n\t\t\t>\n\t\t\t\t<Icon name={name} size={size} className={className} {...props} />\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t)\n\t}\n\treturn (\n\t\t<svg\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t>\n\t\t\t{title ? <title>{title}</title> : null}\n\t\t\t<use href={`${iconsSvg}#${name}`} fill=\"transparent\" />\n\t\t</svg>\n\t)\n}\n","import { type ExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport slugify from '@sindresorhus/slugify'\nimport { clsx, type ClassValue } from 'clsx'\nimport dayjsLib from 'dayjs'\nimport relativeTimePlugin from 'dayjs/plugin/relativeTime'\nimport utcPlugin from 'dayjs/plugin/utc'\nimport * as React from 'react'\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport {\n\tLink,\n\tuseFormAction,\n\tuseNavigation,\n\ttype LinkProps,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport { extendTailwindMerge } from 'tailwind-merge'\nimport { Icon } from '#app/components/icons.tsx'\n\nconst useServerSafeLayoutEffect =\n\ttypeof window === 'undefined' ? () => {} : useLayoutEffect\n\ntype AnchorProps = React.DetailedHTMLProps<\n\tReact.AnchorHTMLAttributes<HTMLAnchorElement>,\n\tHTMLAnchorElement\n>\n\nexport const AnchorOrLink = function AnchorOrLink({\n\tref,\n\t...props\n}: AnchorProps &\n\tLinkProps & {\n\t\treload?: boolean\n\t}) {\n\tconst {\n\t\tto,\n\t\thref,\n\n\t\tdownload,\n\t\treload = false,\n\t\tprefetch,\n\t\tchildren,\n\t\t...rest\n\t} = props\n\tlet toUrl = ''\n\tlet shouldUserRegularAnchor = reload || Boolean(download)\n\n\tif (!shouldUserRegularAnchor && typeof href === 'string') {\n\t\tshouldUserRegularAnchor = href.includes(':') || href.startsWith('#')\n\t}\n\n\tif (!shouldUserRegularAnchor && typeof to === 'string') {\n\t\ttoUrl = to\n\t\tshouldUserRegularAnchor = to.includes(':')\n\t}\n\n\tif (!shouldUserRegularAnchor && typeof to === 'object') {\n\t\ttoUrl = `${to.pathname ?? ''}${to.hash ? `#${to.hash}` : ''}${\n\t\t\tto.search ? `?${to.search}` : ''\n\t\t}`\n\t\tshouldUserRegularAnchor = Boolean(to.pathname?.includes(':'))\n\t}\n\n\tif (shouldUserRegularAnchor) {\n\t\treturn (\n\t\t\t<a {...rest} download={download} href={href ?? toUrl} ref={ref}>\n\t\t\t\t{children}\n\t\t\t</a>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<Link prefetch={prefetch} to={to ?? href ?? ''} {...rest} ref={ref}>\n\t\t\t\t{children}\n\t\t\t</Link>\n\t\t)\n\t}\n}\n\nfunction setupDayjs() {\n\tdayjsLib.extend(utcPlugin)\n\tdayjsLib.extend(relativeTimePlugin)\n\treturn dayjsLib\n}\n\nexport function useDayjs() {\n\tconst [dayjs] = useState(() => setupDayjs())\n\treturn dayjs\n}\n\nexport function ensureUndeployed() {\n\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\tthrow new Response(\n\t\t\t'EPICSHOP_DEPLOYED is true, cannot perform this action. Run this locally instead.',\n\t\t\t{\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t)\n\t}\n}\n\nexport function ensureDeployed() {\n\tif (!ENV.EPICSHOP_DEPLOYED) {\n\t\tthrow new Response(\n\t\t\t'EPICSHOP_DEPLOYED is false, cannot perform this action. Run deployed version instead.',\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n}\n\nexport function useAltDown() {\n\tconst [altDown, setAltDown] = React.useState(false)\n\n\tReact.useEffect(() => {\n\t\tconst set = (e: KeyboardEvent) => setAltDown(e.altKey)\n\t\tdocument.addEventListener('keydown', set)\n\t\tdocument.addEventListener('keyup', set)\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keyup', set)\n\t\t\tdocument.removeEventListener('keydown', set)\n\t\t}\n\t}, [])\n\treturn altDown\n}\n\nexport const Heading = function Heading({\n\tref,\n\tid,\n\tchildren,\n\tas: asProp,\n\tclassName,\n\t...props\n}: {\n\tref: React.RefObject<HTMLHeadingElement>\n\tid?: string\n\tchildren: React.ReactNode\n\tas?: React.ElementType\n\tclassName?: string\n}) {\n\tconst Comp = asProp ?? 'h1'\n\tconst slugId = id ?? slugify(children ? String(children) : '')\n\treturn (\n\t\t<Comp\n\t\t\tid={slugId || undefined}\n\t\t\tref={ref}\n\t\t\tclassName={cn('group relative', className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{slugId ? (\n\t\t\t\t<Link\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tto={`#${slugId}`}\n\t\t\t\t\tclassName=\"absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 p-2 opacity-0 transition group-hover:opacity-100 motion-safe:transition\"\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"Linked\" />\n\t\t\t\t</Link>\n\t\t\t) : null}\n\t\t\t{children}\n\t\t</Comp>\n\t)\n}\nexport function getUserImgSrc(imageId?: string | null) {\n\treturn imageId ? `/resources/user-images/${imageId}` : '/img/user.png'\n}\n\nexport function getNoteImgSrc(imageId: string) {\n\treturn `/resources/note-images/${imageId}`\n}\n\nexport function getErrorMessage(\n\terror: unknown,\n\tdefaultMessage: string = 'Unknown Error',\n) {\n\tif (typeof error === 'string') return error\n\tif (\n\t\terror &&\n\t\ttypeof error === 'object' &&\n\t\t'message' in error &&\n\t\ttypeof error.message === 'string'\n\t) {\n\t\treturn error.message\n\t}\n\treturn defaultMessage\n}\n\nconst customTwMerge = extendTailwindMerge({})\n\nexport function cn(...inputs: ClassValue[]) {\n\treturn customTwMerge(clsx(inputs))\n}\n\nexport function getDomainUrl(request: Request) {\n\tconst url = new URL(request.url)\n\tconst host =\n\t\trequest.headers.get('X-Forwarded-Host') ??\n\t\trequest.headers.get('host') ??\n\t\turl.host\n\n\tconst protocol = host.includes('localhost') ? 'http:' : url.protocol\n\treturn `${protocol}//${host}`\n}\n\nexport function getBaseUrl({\n\trequest,\n\tdomain = request ? getDomainUrl(request) : window.location.origin,\n\tport,\n}: {\n\tport: number\n} & (\n\t| {\n\t\t\trequest: Request\n\t\t\tdomain?: never\n\t }\n\t| {\n\t\t\trequest?: never\n\t\t\tdomain: string\n\t }\n)) {\n\tconst url = new URL(domain)\n\turl.port = String(port)\n\treturn url.toString()\n}\n\nexport function getReferrerRoute(request: Request) {\n\t// spelling errors and whatever makes this annoyingly inconsistent\n\t// in my own testing, `referer` returned the right value, but 🤷‍♂️\n\tconst referrer =\n\t\trequest.headers.get('referer') ??\n\t\trequest.headers.get('referrer') ??\n\t\trequest.referrer\n\tconst domain = getDomainUrl(request)\n\tif (referrer.startsWith(domain)) {\n\t\treturn referrer.slice(domain.length)\n\t} else {\n\t\treturn '/'\n\t}\n}\n\n/**\n * Merge multiple headers objects into one (uses set so headers are overridden)\n */\nexport function mergeHeaders(\n\t...headers: Array<ResponseInit['headers'] | null | undefined>\n) {\n\tconst merged = new Headers()\n\tfor (const header of headers) {\n\t\tif (!header) continue\n\t\tfor (const [key, value] of new Headers(header).entries()) {\n\t\t\tmerged.set(key, value)\n\t\t}\n\t}\n\treturn merged\n}\n\n/**\n * Combine multiple header objects into one (uses append so headers are not overridden)\n */\nexport function combineHeaders(\n\t...headers: Array<ResponseInit['headers'] | null | undefined>\n) {\n\tconst combined = new Headers()\n\tfor (const header of headers) {\n\t\tif (!header) continue\n\t\tfor (const [key, value] of new Headers(header).entries()) {\n\t\t\tcombined.append(key, value)\n\t\t}\n\t}\n\treturn combined\n}\n\n/**\n * Combine multiple response init objects into one (uses combineHeaders)\n */\nexport function combineResponseInits(\n\t...responseInits: Array<ResponseInit | null | undefined>\n) {\n\tlet combined: ResponseInit = {}\n\tfor (const responseInit of responseInits) {\n\t\tcombined = {\n\t\t\t...responseInit,\n\t\t\theaders: combineHeaders(combined.headers, responseInit?.headers),\n\t\t}\n\t}\n\treturn combined\n}\n\n/**\n * Returns true if the current navigation is submitting the current route's\n * form. Defaults to the current route's form action and method POST.\n *\n * Defaults state to 'non-idle'\n *\n * NOTE: the default formAction will include query params, but the\n * navigation.formAction will not, so don't use the default formAction if you\n * want to know if a form is submitting without specific query params.\n */\nexport function useIsPending({\n\tformAction,\n\tformMethod = 'POST',\n\tstate = 'non-idle',\n}: {\n\tformAction?: string\n\tformMethod?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE'\n\tstate?: 'submitting' | 'loading' | 'non-idle'\n} = {}) {\n\tconst contextualFormAction = useFormAction()\n\tconst navigation = useNavigation()\n\tconst isPendingState =\n\t\tstate === 'non-idle'\n\t\t\t? navigation.state !== 'idle'\n\t\t\t: navigation.state === state\n\treturn (\n\t\tisPendingState &&\n\t\tnavigation.formAction === (formAction ?? contextualFormAction) &&\n\t\tnavigation.formMethod === formMethod\n\t)\n}\n\n/**\n * This combines useSpinDelay (from https://npm.im/spin-delay) and useIsPending\n * from our own utilities to give you a nice way to show a loading spinner for\n * a minimum amount of time, even if the request finishes right after the delay.\n *\n * This avoids a flash of loading state regardless of how fast or slow the\n * request is.\n */\nexport function useDelayedIsPending({\n\tformAction,\n\tformMethod,\n\tdelay = 400,\n\tminDuration = 300,\n}: Parameters<typeof useIsPending>[0] &\n\tParameters<typeof useSpinDelay>[1] = {}) {\n\tconst isPending = useIsPending({ formAction, formMethod })\n\tconst delayedIsPending = useSpinDelay(isPending, {\n\t\tdelay,\n\t\tminDuration,\n\t})\n\treturn delayedIsPending\n}\n\nfunction callAll<Args extends Array<unknown>>(\n\t...fns: Array<((...args: Args) => unknown) | undefined>\n) {\n\treturn (...args: Args) => fns.forEach((fn) => fn?.(...args))\n}\n\n/**\n * Use this hook with a button and it will make it so the first click sets a\n * `doubleCheck` state to true, and the second click will actually trigger the\n * `onClick` handler. This allows you to have a button that can be like a\n * \"are you sure?\" experience for the user before doing destructive operations.\n */\nexport function useDoubleCheck() {\n\tconst [doubleCheck, setDoubleCheck] = useState(false)\n\n\tfunction getButtonProps(\n\t\tprops?: React.ButtonHTMLAttributes<HTMLButtonElement>,\n\t) {\n\t\tconst onBlur: React.ButtonHTMLAttributes<HTMLButtonElement>['onBlur'] =\n\t\t\t() => setDoubleCheck(false)\n\n\t\tconst onClick: React.ButtonHTMLAttributes<HTMLButtonElement>['onClick'] =\n\t\t\tdoubleCheck\n\t\t\t\t? () => setDoubleCheck(false)\n\t\t\t\t: (e) => {\n\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t\tsetDoubleCheck(true)\n\t\t\t\t\t}\n\n\t\tconst onKeyUp: React.ButtonHTMLAttributes<HTMLButtonElement>['onKeyUp'] = (\n\t\t\te,\n\t\t) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\tsetDoubleCheck(false)\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t...props,\n\t\t\tonBlur: callAll(onBlur, props?.onBlur),\n\t\t\tonClick: callAll(onClick, props?.onClick),\n\t\t\tonKeyUp: callAll(onKeyUp, props?.onKeyUp),\n\t\t}\n\t}\n\n\treturn { doubleCheck, getButtonProps }\n}\n\nexport function useInterval(callback: () => void, delay: number | null) {\n\tconst savedCallback = useRef(callback)\n\n\t// Remember the latest callback if it changes.\n\tuseServerSafeLayoutEffect(() => {\n\t\tsavedCallback.current = callback\n\t}, [callback])\n\n\t// Set up the interval.\n\tuseEffect(() => {\n\t\t// Don't schedule if no delay is specified.\n\t\t// Note: 0 is a valid value for delay.\n\t\tif (delay === null) {\n\t\t\treturn\n\t\t}\n\n\t\tconst id = setInterval(() => {\n\t\t\tsavedCallback.current()\n\t\t}, delay)\n\n\t\treturn () => {\n\t\t\tclearInterval(id)\n\t\t}\n\t}, [delay])\n}\n\n/**\n * Simple debounce implementation\n */\nfunction debounce<Callback extends (...args: Parameters<Callback>) => void>(\n\tfn: Callback,\n\tdelay: number,\n) {\n\tlet timer: ReturnType<typeof setTimeout> | null = null\n\treturn (...args: Parameters<Callback>) => {\n\t\tif (timer) clearTimeout(timer)\n\t\ttimer = setTimeout(() => {\n\t\t\tfn(...args)\n\t\t}, delay)\n\t}\n}\n\n/**\n * Debounce a callback function\n */\nexport function useDebounce<\n\tCallback extends (...args: Parameters<Callback>) => ReturnType<Callback>,\n>(callback: Callback, delay: number) {\n\tconst callbackRef = useRef(callback)\n\tuseEffect(() => {\n\t\tcallbackRef.current = callback\n\t})\n\treturn useMemo(\n\t\t() =>\n\t\t\tdebounce(\n\t\t\t\t(...args: Parameters<Callback>) => callbackRef.current(...args),\n\t\t\t\tdelay,\n\t\t\t),\n\t\t[delay],\n\t)\n}\n\nexport async function downloadFile(url: string, retries: number = 0) {\n\tconst MAX_RETRIES = 3\n\ttry {\n\t\tconst response = await fetch(url)\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Failed to fetch image with status ${response.status}`)\n\t\t}\n\t\tconst contentType = response.headers.get('content-type') ?? 'image/jpg'\n\t\tconst blob = Buffer.from(await response.arrayBuffer())\n\t\treturn { contentType, blob }\n\t} catch (e) {\n\t\tif (retries > MAX_RETRIES) throw e\n\t\treturn downloadFile(url, retries + 1)\n\t}\n}\n\nexport function getExercisePath(exerciseNumber: number, suffix?: 'finished') {\n\tconst exerciseNumberStr = exerciseNumber.toString().padStart(2, '0')\n\tif (!suffix) return `/exercise/${exerciseNumberStr}`\n\n\treturn `/exercise/${exerciseNumberStr}/${suffix}`\n}\n\nexport function getExerciseStepPath(\n\texerciseNumber: number,\n\tstepNumber: number,\n\ttype?: ExerciseStepApp['type'],\n) {\n\tconst exerciseNumberStr = exerciseNumber.toString().padStart(2, '0')\n\tif (!stepNumber) return `/exercise/${exerciseNumberStr}`\n\n\tconst stepNumberStr = stepNumber.toString().padStart(2, '0')\n\tif (!type) return `/exercise/${exerciseNumberStr}/${stepNumberStr}`\n\n\treturn `/exercise/${exerciseNumberStr}/${stepNumberStr}/${type}`\n}\n\nexport function calculateExpirationTime(metadata: {\n\tcreatedTime: number\n\tttl?: number | null\n}): number | null {\n\tconst { createdTime, ttl } = metadata\n\tif (ttl === undefined || ttl === null || ttl === Infinity) {\n\t\treturn null // Never expires\n\t}\n\treturn createdTime + ttl\n}\n\nexport function formatTimeRemaining(expirationTime: number): {\n\ttext: string\n\tisExpired: boolean\n\tisExpiringSoon: boolean\n} {\n\tconst now = Date.now()\n\tconst remaining = expirationTime - now\n\n\tif (remaining <= 0) {\n\t\treturn { text: 'Expired', isExpired: true, isExpiringSoon: false }\n\t}\n\n\tconst seconds = Math.floor(remaining / 1000)\n\tconst minutes = Math.floor(seconds / 60)\n\tconst hours = Math.floor(minutes / 60)\n\tconst days = Math.floor(hours / 24)\n\n\tlet text: string\n\tlet isExpiringSoon: boolean\n\n\tif (days > 0) {\n\t\ttext = `${days}d ${hours % 24}h`\n\t\tisExpiringSoon = days < 1.5\n\t} else if (hours > 0) {\n\t\ttext = `${hours}h ${minutes % 60}m`\n\t\tisExpiringSoon = hours < 2\n\t} else if (minutes > 0) {\n\t\ttext = `${minutes}m ${seconds % 60}s`\n\t\tisExpiringSoon = minutes < 10\n\t} else {\n\t\ttext = `${seconds}s`\n\t\tisExpiringSoon = true\n\t}\n\n\treturn { text, isExpired: false, isExpiringSoon }\n}\n\nexport function formatDuration(ms: number): string {\n\tif (ms < 1000) return `${Math.round(ms)}ms`\n\tif (ms < 60000) return `${Math.round(ms / 1000)}s`\n\tif (ms < 3600000) return `${Math.round(ms / 60000)}m`\n\tif (ms < 86400000) return `${Math.round(ms / 3600000)}h`\n\tif (ms < 604800000) return `${Math.round(ms / 86400000)}d`\n\tif (ms < 2629746000) return `${Math.round(ms / 604800000)}w`\n\tif (ms < 31556952000) return `${Math.round(ms / 2629746000)}mo`\n\treturn `${Math.round(ms / 31556952000)}y`\n}\n\nexport function formatFileSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes} B`\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n\tif (bytes < 1024 * 1024 * 1024) {\n\t\treturn `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n\t}\n\treturn `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`\n}\n","// Dynamic import of Sentry with error handling\nconst Sentry = await import('@sentry/react-router').catch((error) => {\n\tconsole.warn(\n\t\t'Failed to import @sentry/react-router:',\n\t\terror instanceof Error ? error.message : String(error),\n\t\t'- Sentry monitoring will be disabled but the application will continue to work normally',\n\t)\n\treturn null\n})\n\nimport { useEffect, useState } from 'react'\nimport {\n\tisRouteErrorResponse,\n\tuseParams,\n\tuseRouteError,\n\ttype ErrorResponse,\n} from 'react-router'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\n\ntype StatusHandler = (info: {\n\terror: ErrorResponse\n\tparams: Record<string, string | undefined>\n}) => React.ReactNode | null\n\nconst defaultStatusHandlers: Record<number, StatusHandler> = {\n\t400: ({ error }) => (\n\t\t<div>\n\t\t\t<h1>Bad Request</h1>\n\t\t\t<p>{error.data}</p>\n\t\t</div>\n\t),\n\t401: () => (\n\t\t<div>\n\t\t\t<h1>Unauthorized</h1>\n\t\t\t<p>You don't have permission to access this resource.</p>\n\t\t</div>\n\t),\n\t403: () => (\n\t\t<div>\n\t\t\t<h1>Forbidden</h1>\n\t\t\t<p>You don't have permission to access this resource.</p>\n\t\t</div>\n\t),\n\t404: () => (\n\t\t<div>\n\t\t\t<h1>Not Found</h1>\n\t\t\t<p>Sorry, we couldn't find what you were looking for.</p>\n\t\t</div>\n\t),\n\t500: ({ error }) => (\n\t\t<div>\n\t\t\t<h1>Internal Server Error</h1>\n\t\t\t<p>Sorry, something went wrong on our end.</p>\n\t\t\t<p>{error.data}</p>\n\t\t</div>\n\t),\n\t502: () => (\n\t\t<div>\n\t\t\t<h1>Bad Gateway</h1>\n\t\t\t<p>Sorry, we're having a temporary problem. Please try again later.</p>\n\t\t\t<button onClick={() => window.location.reload()}>Refresh</button>\n\t\t</div>\n\t),\n\t503: () => (\n\t\t<div>\n\t\t\t<h1>Service Unavailable</h1>\n\t\t\t<p>Sorry, we're having a temporary problem. Please try again later.</p>\n\t\t\t<button onClick={() => window.location.reload()}>Refresh</button>\n\t\t</div>\n\t),\n}\n\nexport function GeneralErrorBoundary({\n\tclassName = 'container flex items-center justify-center p-20 text-h2',\n\tdefaultStatusHandler = ({ error }) => (\n\t\t<p>\n\t\t\t{error.status} {error.data}\n\t\t</p>\n\t),\n\tstatusHandlers: givenStatusHandlers,\n\tunexpectedErrorHandler = (error) => <p>{getErrorMessage(error)}</p>,\n}: {\n\tclassName?: string\n\tdefaultStatusHandler?: StatusHandler\n\tstatusHandlers?: Record<number, StatusHandler>\n\tunexpectedErrorHandler?: (error: unknown) => React.ReactNode | null\n}) {\n\tconst [isServerDown, setIsServerDown] = useState(false)\n\tconst error = useRouteError()\n\tconst params = useParams()\n\tconst isResponse = isRouteErrorResponse(error)\n\tconst statusHandlers = {\n\t\t...defaultStatusHandlers,\n\t\t...givenStatusHandlers,\n\t}\n\n\tuseEffect(() => {\n\t\tif (isResponse) return\n\t\tif (ENV.EPICSHOP_IS_PUBLISHED) {\n\t\t\tSentry?.captureException(error)\n\t\t}\n\t}, [error, isResponse])\n\n\tuseEffect(() => {\n\t\t// if error is \"Failed to fetch\", trigger a fetch to '/resources/healthcheck' and if it fails, show a message to the user that the server is down\n\t\tif (error instanceof Error && error.message.includes('Failed to fetch')) {\n\t\t\tfetch('/resources/healthcheck').catch(() => {\n\t\t\t\tsetIsServerDown(true)\n\t\t\t})\n\t\t}\n\t}, [error])\n\n\tif (typeof document !== 'undefined') {\n\t\tconsole.error(error)\n\t}\n\n\treturn (\n\t\t<div className={className}>\n\t\t\t{isServerDown ? (\n\t\t\t\t<div className=\"flex flex-col items-center justify-center gap-6\">\n\t\t\t\t\t<h1 className=\"text-h2 font-bold\">Server is down</h1>\n\t\t\t\t\t<p className=\"text-body-md\">\n\t\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t? \"Sorry, we're having a temporary problem. Please try again later.\"\n\t\t\t\t\t\t\t: 'Your server is not running. Please restart the workshop app.'}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t{isRouteErrorResponse(error)\n\t\t\t\t? (statusHandlers?.[error.status] ?? defaultStatusHandler)({\n\t\t\t\t\t\terror,\n\t\t\t\t\t\tparams,\n\t\t\t\t\t})\n\t\t\t\t: unexpectedErrorHandler(error)}\n\t\t</div>\n\t)\n}\n","import { Link } from 'react-router'\nimport { Icon } from './icons.tsx'\n\nexport function ExerciseWarningBanner() {\n\treturn (\n\t\t<div className=\"border-destructive bg-destructive fixed top-0 right-0 left-0 z-50 border-b\">\n\t\t\t<div className=\"relative w-full p-4\">\n\t\t\t\t{/* Full-banner clickable link, visually hidden but covers the banner */}\n\t\t\t\t<Link\n\t\t\t\t\tto=\"/workspace-structure\"\n\t\t\t\t\tclassName=\"absolute inset-0 z-10 block h-full w-full\"\n\t\t\t\t\taria-label=\"Learn more about workspace structure\"\n\t\t\t\t/>\n\t\t\t\t<div className=\"relative z-0 container flex items-center justify-between\">\n\t\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\tname=\"Error\"\n\t\t\t\t\t\t\tclassName=\"text-destructive-foreground h-5 w-5\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<h3 className=\"text-destructive-foreground text-sm font-semibold\">\n\t\t\t\t\t\t\t\tWarning: Changes detected in exercises directory\n\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t<p className=\"text-destructive-foreground/80 text-xs\">\n\t\t\t\t\t\t\t\tYou should typically work in the playground directory, not the\n\t\t\t\t\t\t\t\texercises directory.\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"text-destructive-foreground flex items-center gap-2 text-xs\">\n\t\t\t\t\t\t<span>Learn more</span>\n\t\t\t\t\t\t<Icon name=\"ArrowRight\" className=\"h-3 w-3\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n","import * as DialogPrimitive from '@radix-ui/react-dialog'\nimport * as React from 'react'\nimport { cn } from '#app/utils/misc.tsx'\nimport { Icon } from '../icons'\n\nconst Dialog = DialogPrimitive.Root\n\nconst DialogTrigger = DialogPrimitive.Trigger\n\nconst DialogPortal = DialogPrimitive.Portal\n\nconst DialogClose = DialogPrimitive.Close\n\nfunction DialogOverlay({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n\treturn (\n\t\t<DialogPrimitive.Overlay\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t'bg-background/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 backdrop-blur-sm',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName\n\nfunction DialogContent({\n\tclassName,\n\tchildren,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Content>) {\n\treturn (\n\t\t<DialogPortal>\n\t\t\t<DialogOverlay />\n\t\t\t<DialogPrimitive.Content\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t<DialogPrimitive.Close className=\"ring-offset-background data-[state=open]:bg-accent data-[state=open]:text-muted-foreground focus:ring-ring absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none\">\n\t\t\t\t\t<Icon name=\"Close\" />\n\t\t\t\t\t<span className=\"sr-only\">Close</span>\n\t\t\t\t</DialogPrimitive.Close>\n\t\t\t</DialogPrimitive.Content>\n\t\t</DialogPortal>\n\t)\n}\nDialogContent.displayName = DialogPrimitive.Content.displayName\n\nfunction DialogHeader({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex flex-col space-y-1.5 text-center sm:text-left',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogHeader.displayName = 'DialogHeader'\n\nfunction DialogFooter({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogFooter.displayName = 'DialogFooter'\n\nfunction DialogTitle({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n\treturn (\n\t\t<DialogPrimitive.Title\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t'text-lg leading-none font-semibold tracking-tight',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogTitle.displayName = DialogPrimitive.Title.displayName\n\nfunction DialogDescription({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n\treturn (\n\t\t<DialogPrimitive.Description\n\t\t\tref={ref}\n\t\t\tclassName={cn('text-muted-foreground text-sm', className)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogDescription.displayName = DialogPrimitive.Description.displayName\n\nexport {\n\tDialog,\n\tDialogClose,\n\tDialogContent,\n\tDialogDescription,\n\tDialogFooter,\n\tDialogHeader,\n\tDialogOverlay,\n\tDialogPortal,\n\tDialogTitle,\n\tDialogTrigger,\n}\n","import * as React from 'react'\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n} from './ui/dialog'\n\ninterface KeyboardShortcut {\n\tkeys: string[]\n\tdescription: string\n}\n\ninterface ShortcutCategory {\n\ttitle: string\n\tshortcuts: KeyboardShortcut[]\n}\n\nconst shortcutCategories: ShortcutCategory[] = [\n\t{\n\t\ttitle: 'Navigation',\n\t\tshortcuts: [\n\t\t\t{ keys: ['g', 'h'], description: 'Go to home' },\n\t\t\t{\n\t\t\t\tkeys: ['g', '1-9'],\n\t\t\t\tdescription: 'Go to exercise (e.g., g+1 → /exercise/01)',\n\t\t\t},\n\t\t\t{\n\t\t\t\tkeys: ['g', '1-9', '.', '1-9'],\n\t\t\t\tdescription:\n\t\t\t\t\t'Go to exercise step (e.g., g+1+.+2 → /exercise/01/02/problem)',\n\t\t\t},\n\t\t\t{\n\t\t\t\tkeys: ['g', '1-9', '.', 'f'],\n\t\t\t\tdescription:\n\t\t\t\t\t'Go to exercise finished page (e.g., g+1+.+f → /exercise/01/finished)',\n\t\t\t},\n\t\t\t{ keys: ['g', 'p'], description: 'Go to previous step/page' },\n\t\t\t{ keys: ['g', 'n'], description: 'Go to next step/page' },\n\t\t\t{ keys: ['g', 'a'], description: 'Go to account page' },\n\t\t\t{ keys: ['g', 'd'], description: 'Go to admin page' },\n\t\t\t{ keys: ['g', 'l'], description: 'Go to last exercise solution' },\n\t\t\t{ keys: ['Escape'], description: 'Close sidebar navigation (when open)' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Playback Controls',\n\t\tshortcuts: [\n\t\t\t{ keys: ['Space', 'k'], description: 'Play/pause video' },\n\t\t\t{ keys: ['j'], description: 'Seek backward 10 seconds' },\n\t\t\t{ keys: ['l'], description: 'Seek forward 10 seconds' },\n\t\t\t{ keys: ['←'], description: 'Seek backward 10 seconds' },\n\t\t\t{ keys: ['→'], description: 'Seek forward 10 seconds' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Frame-by-Frame Navigation',\n\t\tshortcuts: [\n\t\t\t{ keys: [','], description: 'Go to previous frame (when paused)' },\n\t\t\t{ keys: ['.'], description: 'Go to next frame (when paused)' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Volume Control',\n\t\tshortcuts: [\n\t\t\t{ keys: ['↑'], description: 'Increase volume by 10%' },\n\t\t\t{ keys: ['↓'], description: 'Decrease volume by 10%' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Playback Speed',\n\t\tshortcuts: [\n\t\t\t{ keys: ['Shift', '>'], description: 'Increase playback speed' },\n\t\t\t{ keys: ['Shift', '<'], description: 'Decrease playback speed' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Fullscreen and Picture-in-Picture',\n\t\tshortcuts: [\n\t\t\t{ keys: ['f'], description: 'Toggle fullscreen mode' },\n\t\t\t{ keys: ['i'], description: 'Toggle picture-in-picture mode' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Captions',\n\t\tshortcuts: [{ keys: ['c'], description: 'Toggle captions/subtitles' }],\n\t},\n\t{\n\t\ttitle: 'Quick Seek',\n\t\tshortcuts: [\n\t\t\t{\n\t\t\t\tkeys: ['0-9'],\n\t\t\t\tdescription:\n\t\t\t\t\t'Seek to percentage of video (0 = 0%, 1 = 10%, ..., 9 = 90%)',\n\t\t\t},\n\t\t],\n\t},\n]\n\nfunction KeyboardShortcutsDialog({\n\topen,\n\tonOpenChange,\n}: {\n\topen: boolean\n\tonOpenChange: (open: boolean) => void\n}) {\n\treturn (\n\t\t<Dialog open={open} onOpenChange={onOpenChange}>\n\t\t\t<DialogContent className=\"max-h-[80vh] max-w-2xl overflow-y-auto\">\n\t\t\t\t<DialogHeader>\n\t\t\t\t\t<DialogTitle>Keyboard Shortcuts</DialogTitle>\n\t\t\t\t\t<DialogDescription>\n\t\t\t\t\t\tUse these keyboard shortcuts to navigate and control the video\n\t\t\t\t\t\tplayer\n\t\t\t\t\t</DialogDescription>\n\t\t\t\t</DialogHeader>\n\t\t\t\t<div className=\"space-y-6\">\n\t\t\t\t\t{shortcutCategories.map((category) => (\n\t\t\t\t\t\t<div key={category.title}>\n\t\t\t\t\t\t\t<h3 className=\"text-foreground mb-3 text-sm font-semibold\">\n\t\t\t\t\t\t\t\t{category.title}\n\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t\t{category.shortcuts.map((shortcut, index) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center justify-between gap-4\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground flex-1 text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t{shortcut.description}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex shrink-0 items-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t{shortcut.keys.map((key, keyIndex) => (\n\t\t\t\t\t\t\t\t\t\t\t\t<React.Fragment key={keyIndex}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<kbd className=\"border-border bg-muted rounded border px-2 py-1 font-mono text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</kbd>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{keyIndex < shortcut.keys.length - 1 && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">+</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</React.Fragment>\n\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"border-border mt-4 border-t pt-4\">\n\t\t\t\t\t<p className=\"text-muted-foreground text-xs\">\n\t\t\t\t\t\t<strong>Note:</strong> Shortcuts are ignored when focus is on\n\t\t\t\t\t\tinteractive elements (inputs, buttons, etc.). Press{' '}\n\t\t\t\t\t\t<kbd className=\"border-border bg-muted rounded border px-1.5 py-0.5 font-mono text-xs\">\n\t\t\t\t\t\t\t?\n\t\t\t\t\t\t</kbd>{' '}\n\t\t\t\t\t\tto toggle this dialog.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t)\n}\n\nexport { KeyboardShortcutsDialog }\n","import { useEffect, useRef, useState } from 'react'\nimport { useFetchers, useNavigation } from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport const showProgressBarField = (\n\t<input type=\"hidden\" name=\"show-progress-bar\" value=\"true\" />\n)\n\nfunction EpicProgress() {\n\tconst transition = useNavigation()\n\tconst fetchers = useFetchers().filter(\n\t\t(fetcher) => fetcher.formData?.get('show-progress-bar') === 'true',\n\t)\n\tconst states = [transition.state, ...fetchers.map((f) => f.state)]\n\tconst busy = states.some((s) => s !== 'idle')\n\tconst delayedPending = useSpinDelay(busy, {\n\t\tdelay: 600,\n\t\tminDuration: 400,\n\t})\n\tconst ref = useRef<HTMLDivElement>(null)\n\tconst [animationComplete, setAnimationComplete] = useState(true)\n\n\tconst isIdle = states.every((s) => s === 'idle')\n\tconst isSubmitting = states.some((s) => s === 'submitting')\n\tconst isLoading = states.some((s) => s === 'loading')\n\n\tuseEffect(() => {\n\t\tif (!ref.current) return\n\t\tif (delayedPending) setAnimationComplete(false)\n\n\t\tconst animationPromises = ref.current\n\t\t\t.getAnimations()\n\t\t\t.map(({ finished }) => finished)\n\n\t\tvoid Promise.allSettled(animationPromises).then(() => {\n\t\t\tif (!delayedPending) setAnimationComplete(true)\n\t\t})\n\t}, [delayedPending])\n\n\treturn (\n\t\t<div\n\t\t\trole=\"progressbar\"\n\t\t\taria-hidden={delayedPending ? undefined : true}\n\t\t\taria-valuetext={delayedPending ? 'Loading' : undefined}\n\t\t\tclassName=\"fixed inset-x-0 top-0 left-0 z-50 h-[0.20rem] animate-pulse\"\n\t\t>\n\t\t\t<div\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'bg-highlight h-full w-0 duration-500 ease-in-out',\n\t\t\t\t\tisIdle &&\n\t\t\t\t\t\t(animationComplete\n\t\t\t\t\t\t\t? 'transition-none'\n\t\t\t\t\t\t\t: 'w-full opacity-0 transition-all'),\n\t\t\t\t\tdelayedPending && isSubmitting && 'w-5/12',\n\t\t\t\t\tdelayedPending && isLoading && 'w-8/12',\n\t\t\t\t)}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\nexport { EpicProgress }\n","import { useEffect } from 'react'\nimport { Toaster, toast as showToast } from 'sonner'\nimport { type Toast } from '#app/utils/toast.server.ts'\n\nexport function EpicToaster({ toast }: { toast?: Toast | null }) {\n\treturn (\n\t\t<>\n\t\t\t<Toaster closeButton position=\"top-center\" />\n\t\t\t{toast ? <ShowToast toast={toast} /> : null}\n\t\t</>\n\t)\n}\n\nfunction ShowToast({ toast }: { toast: Toast }) {\n\tconst { id, type, title, description } = toast\n\tuseEffect(() => {\n\t\tsetTimeout(() => {\n\t\t\tshowToast[type](title, { id, description })\n\t\t}, 0)\n\t}, [description, id, title, type])\n\treturn null\n}\n","import * as TooltipPrimitive from '@radix-ui/react-tooltip'\nimport * as React from 'react'\n\nimport { cn } from '#app/utils/misc.tsx'\n\nconst TooltipProvider = TooltipPrimitive.Provider\n\nconst Tooltip = TooltipPrimitive.Root\n\nconst TooltipTrigger = TooltipPrimitive.Trigger\n\nfunction TooltipContent({\n\tclassName,\n\tsideOffset = 4,\n\tref,\n\t...props\n}: React.ComponentProps<typeof TooltipPrimitive.Content>) {\n\treturn (\n\t\t<TooltipPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t'bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md border px-3 py-1.5 text-sm shadow-md',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport function SimpleTooltip({\n\tcontent,\n\tchildren,\n}: {\n\tcontent: React.ReactNode\n\tchildren: React.ReactNode\n}) {\n\tif (!content) return children\n\treturn (\n\t\t<Tooltip>\n\t\t\t<TooltipTrigger asChild>{children}</TooltipTrigger>\n\t\t\t<TooltipContent>{content}</TooltipContent>\n\t\t</Tooltip>\n\t)\n}\n\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }\n","import { type checkForUpdatesCached } from '@epic-web/workshop-utils/git.server'\nimport { useEffect, useRef } from 'react'\nimport { useFetcher } from 'react-router'\nimport { toast } from 'sonner'\nimport { z } from 'zod'\n\nexport function UpdateToast({\n\trepoUpdates,\n}: {\n\trepoUpdates: Awaited<ReturnType<typeof checkForUpdatesCached>>\n}) {\n\tconst { updatesAvailable } = repoUpdates\n\tconst diffLink = 'diffLink' in repoUpdates ? repoUpdates.diffLink : null\n\tconst remoteCommit =\n\t\t'remoteCommit' in repoUpdates ? repoUpdates.remoteCommit : undefined\n\tconst fetcher = useFetcher()\n\tconst fetcherRef = useRef(fetcher)\n\tuseEffect(() => {\n\t\tfetcherRef.current = fetcher\n\t}, [fetcher])\n\n\t// Track the in-progress toast id and update notification id\n\tconst inProgressToastId = useRef<ReturnType<typeof toast.loading> | null>(\n\t\tnull,\n\t)\n\tconst updateNotificationId = useRef<ReturnType<typeof toast.info> | null>(\n\t\tnull,\n\t)\n\tconst updateInProgress = useRef(false)\n\n\tuseEffect(() => {\n\t\tif (updatesAvailable && remoteCommit) {\n\t\t\tconst id = toast.info('New workshop updates available', {\n\t\t\t\tduration: Infinity,\n\t\t\t\tdescription: (\n\t\t\t\t\t<div>\n\t\t\t\t\t\t{`Get the latest updates by clicking the update button. `}\n\t\t\t\t\t\t{diffLink ? (\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={diffLink}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName=\"text-xs underline\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tView changes\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t),\n\t\t\t\tonDismiss: () => {\n\t\t\t\t\t// No-op for now, could call a dismiss endpoint if needed\n\t\t\t\t},\n\t\t\t\taction: {\n\t\t\t\t\tlabel: 'Update',\n\t\t\t\t\tonClick: async () => {\n\t\t\t\t\t\t// Dismiss the update notification immediately\n\t\t\t\t\t\tif (updateNotificationId.current) {\n\t\t\t\t\t\t\ttoast.dismiss(updateNotificationId.current)\n\t\t\t\t\t\t\tupdateNotificationId.current = null\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Show in-progress toast\n\t\t\t\t\t\tif (!inProgressToastId.current) {\n\t\t\t\t\t\t\tinProgressToastId.current = toast.loading('Update in progress...')\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (updateInProgress.current) return\n\t\t\t\t\t\tupdateInProgress.current = true\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst { EPICSHOP_PARENT_PORT, EPICSHOP_PARENT_TOKEN } =\n\t\t\t\t\t\t\t\twindow.ENV || {}\n\t\t\t\t\t\t\tif (!EPICSHOP_PARENT_PORT || !EPICSHOP_PARENT_TOKEN) {\n\t\t\t\t\t\t\t\tthrow new Error('Update API not available')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst res = await fetch(\n\t\t\t\t\t\t\t\t`http://localhost:${EPICSHOP_PARENT_PORT}/__epicshop-restart`,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\t\t\t'x-epicshop-token': EPICSHOP_PARENT_TOKEN,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tif (!res.ok) {\n\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t`Request to update workshop failed: ${res.statusText}`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst data = await res.json().catch(() => ({}))\n\t\t\t\t\t\t\tconst schema = z.object({\n\t\t\t\t\t\t\t\tstatus: z.enum(['ok', 'error']),\n\t\t\t\t\t\t\t\tmessage: z.string().optional(),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tconst parsed = schema.safeParse(data)\n\t\t\t\t\t\t\tif (!parsed.success) {\n\t\t\t\t\t\t\t\tconsole.error('Invalid response from update API', data)\n\t\t\t\t\t\t\t\tthrow new Error('Invalid response from update API')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst { status, message } = parsed.data\n\t\t\t\t\t\t\tif (status === 'ok') {\n\t\t\t\t\t\t\t\tlet reloaded = false\n\t\t\t\t\t\t\t\ttoast.success('Workshop updated', {\n\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t'Reloading in 2 seconds... You can reload now if you prefer.',\n\t\t\t\t\t\t\t\t\tduration: 2000,\n\t\t\t\t\t\t\t\t\taction: {\n\t\t\t\t\t\t\t\t\t\tlabel: 'Reload now',\n\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\treloaded = true\n\t\t\t\t\t\t\t\t\t\t\twindow.location.reload()\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tonAutoClose: () => {\n\t\t\t\t\t\t\t\t\t\tif (!reloaded) {\n\t\t\t\t\t\t\t\t\t\t\twindow.location.reload()\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ttoast.error('Failed to update workshop', {\n\t\t\t\t\t\t\t\t\tdescription: message || 'Unknown error',\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\ttoast.error('Failed to update workshop', {\n\t\t\t\t\t\t\t\tdescription: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tupdateInProgress.current = false\n\t\t\t\t\t\t\tif (inProgressToastId.current) {\n\t\t\t\t\t\t\t\ttoast.dismiss(inProgressToastId.current)\n\t\t\t\t\t\t\t\tinProgressToastId.current = null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tcancel: {\n\t\t\t\t\tlabel: 'Dismiss',\n\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t// Dismiss the notification toast\n\t\t\t\t\t\tif (updateNotificationId.current) {\n\t\t\t\t\t\t\ttoast.dismiss(updateNotificationId.current)\n\t\t\t\t\t\t\tupdateNotificationId.current = null\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Mute the notification persistently\n\t\t\t\t\t\tvoid fetcherRef.current.submit(\n\t\t\t\t\t\t\t{ intent: 'mute', id: `update-repo-${remoteCommit}` },\n\t\t\t\t\t\t\t{ method: 'post', action: '/admin/notifications' },\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t\tupdateNotificationId.current = id\n\t\t}\n\t}, [updatesAvailable, diffLink, remoteCommit])\n\n\treturn null\n}\n","import { muteNotification } from '@epic-web/workshop-utils/db.server'\nimport { type getUnmutedNotifications } from '@epic-web/workshop-utils/notifications.server'\nimport { useEffect, useRef } from 'react'\nimport { data, type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { toast } from 'sonner'\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tconst id = formData.get('id')\n\tif (typeof id !== 'string') {\n\t\treturn data({ error: 'Invalid notification id' }, { status: 400 })\n\t}\n\tif (intent === 'mute') {\n\t\tawait muteNotification(id)\n\t\treturn data({ success: true })\n\t}\n\treturn data({ error: 'Invalid intent' }, { status: 400 })\n}\n\nexport function Notifications({\n\tunmutedNotifications,\n}: {\n\tunmutedNotifications: Awaited<ReturnType<typeof getUnmutedNotifications>>\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst fetcherRef = useRef(fetcher)\n\tconst toastedIds = useRef<Set<string>>(new Set())\n\n\tuseEffect(() => {\n\t\tfor (const notification of unmutedNotifications) {\n\t\t\tif (toastedIds.current.has(notification.id)) continue\n\t\t\ttoastedIds.current.add(notification.id)\n\n\t\t\ttoast.info(notification.title, {\n\t\t\t\tid: notification.id,\n\t\t\t\tdescription: (\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<p>{notification.message}</p>\n\t\t\t\t\t\t{notification.link && (\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={notification.link}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\tclassName=\"text-xs underline\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tLearn more\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t),\n\t\t\t\tduration: Infinity,\n\t\t\t\taction: {\n\t\t\t\t\tlabel: 'Dismiss',\n\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\tvoid fetcherRef.current.submit(\n\t\t\t\t\t\t\t{ intent: 'mute', id: notification.id },\n\t\t\t\t\t\t\t{ method: 'post', action: '/admin/notifications' },\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}, [unmutedNotifications])\n\n\treturn null\n}\n","import { invariant } from '@epic-web/invariant'\nimport { unstable_useRoute as useRoute } from 'react-router'\nimport { type Route } from '../+types/root.tsx'\n\n/**\n * @returns the loader data from the root loader\n * @throws if the loader data is null\n */\nexport function useRootLoaderData() {\n\tconst route = useRoute('root')\n\tinvariant(\n\t\troute.loaderData,\n\t\t`useRootLoaderData: useRoute('root') loaderData returned null. This can happen if there was an error in the root loader. In this case, the error boundary to should render and we cannot use useRootLoaderData.`,\n\t)\n\treturn route.loaderData\n}\n\n/**\n * @returns the request info from the root loader\n */\nexport function useRequestInfo() {\n\tconst route = useRootLoaderData()\n\treturn route.requestInfo\n}\n\nexport function useApps() {\n\tconst data = useRootLoaderData()\n\treturn data.apps\n}\n\nexport function getRootMatchLoaderData(\n\tmatches: Array<{ id: string; loaderData: unknown } | undefined>,\n) {\n\treturn matches.find((m) => m?.id === 'root')?.loaderData as\n\t\t| Route.ComponentProps['loaderData']\n\t\t| undefined\n}\n","/**\n * This file contains utilities for using client hints for user preference which\n * are needed by the server, but are only known by the browser.\n */\nimport { getHintUtils } from '@epic-web/client-hints'\nimport {\n\tclientHint as colorSchemeHint,\n\tsubscribeToSchemeChange,\n} from '@epic-web/client-hints/color-scheme'\nimport {\n\tclientHint as reducedMotionHint,\n\tsubscribeToMotionChange,\n} from '@epic-web/client-hints/reduced-motion'\nimport { clientHint as timeZoneHint } from '@epic-web/client-hints/time-zone'\nimport * as React from 'react'\nimport { useRevalidator } from 'react-router'\nimport { useRequestInfo } from './root-loader.ts'\n\nconst themeCookieName = 'EpicShop_CH-prefers-color-scheme'\nconst motionCookieName = 'EpicShop_CH-reduced-motion'\nconst hintsUtils = getHintUtils({\n\ttheme: {\n\t\t...colorSchemeHint,\n\t\tcookieName: themeCookieName,\n\t},\n\ttimeZone: {\n\t\t...timeZoneHint,\n\t\tcookieName: 'EpicShop_CH-time-zone',\n\t},\n\treducedMotion: {\n\t\t...reducedMotionHint,\n\t\tcookieName: motionCookieName,\n\t},\n\t// add other hints here\n})\n\nexport const { getHints } = hintsUtils\n\n/**\n * @returns an object with the client hints and their values\n */\nexport function useHints() {\n\tconst requestInfo = useRequestInfo()\n\treturn requestInfo.hints\n}\n\n/**\n * @returns inline script element that checks for client hints and sets cookies\n * if they are not set then reloads the page if any cookie was set to an\n * inaccurate value.\n */\nexport function ClientHintCheck() {\n\tconst { revalidate } = useRevalidator()\n\tReact.useEffect(\n\t\t() => subscribeToSchemeChange(() => revalidate(), themeCookieName),\n\t\t[revalidate],\n\t)\n\tReact.useEffect(\n\t\t() => subscribeToMotionChange(() => revalidate(), motionCookieName),\n\t\t[revalidate],\n\t)\n\n\treturn (\n\t\t<script\n\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t__html: hintsUtils.getClientHintCheckScript(),\n\t\t\t}}\n\t\t/>\n\t)\n}\n","export type ListOfErrors = Array<string | null | undefined> | null | undefined\n\nexport function ErrorList({\n\tid,\n\terrors,\n}: {\n\terrors?: ListOfErrors\n\tid?: string\n}) {\n\tconst errorsToRender = errors?.filter(Boolean)\n\tif (!errorsToRender?.length) return null\n\treturn (\n\t\t<ul id={id} className=\"space-y-1\">\n\t\t\t{errorsToRender.map((e) => (\n\t\t\t\t<li key={e} className=\"text-foreground-destructive text-[10px]\">\n\t\t\t\t\t{e}\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t)\n}\n","// This is a progressive enhancement utility to ensure that the user is redirected\n// to the page they are on if the JavaScript hasn't had a chance to hydrate yet.\n// I think when Remix has middleware, this will be easier to do automatically.\n\nimport { data, redirect, useLocation } from 'react-router'\nimport { safeRedirect } from 'remix-utils/safe-redirect'\nimport { ServerOnly } from 'remix-utils/server-only'\n\nconst PE_REDIRECT_INPUT_NAME = '__PE_redirectTo'\n\nexport function usePERedirectInput() {\n\tconst location = useLocation()\n\treturn (\n\t\t<ServerOnly>\n\t\t\t{() => (\n\t\t\t\t<input\n\t\t\t\t\ttype=\"hidden\"\n\t\t\t\t\tname={PE_REDIRECT_INPUT_NAME}\n\t\t\t\t\tvalue={location.pathname}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</ServerOnly>\n\t)\n}\n\nexport function ensureProgressiveEnhancement(\n\trequest: Request,\n\tformData: FormData,\n\tresponseInit?: () => Parameters<typeof redirect>[1],\n) {\n\tconst redirectTo = formData.get(PE_REDIRECT_INPUT_NAME)\n\tif (typeof redirectTo === 'string') {\n\t\tthrow redirect(safeRedirect(redirectTo), responseInit?.())\n\t}\n\n\t// if request does not accept application/json, it means JS hasn't hydrated yet\n\tif (!acceptsJson(request)) {\n\t\tconst redirectToReferrer = request.headers.get('Referer') ?? '/'\n\t\tthrow redirect(safeRedirect(redirectToReferrer), responseInit?.())\n\t}\n}\n\nfunction acceptsJson(request: Request) {\n\tconst accept = request.headers.get('Accept') ?? ''\n\treturn (\n\t\taccept.includes('application/json') ||\n\t\taccept.includes('*/*') ||\n\t\taccept.includes('application/*') ||\n\t\taccept.includes('*/json')\n\t)\n}\n\nexport function dataWithPE<Data>(\n\trequest: Request,\n\tformData: FormData,\n\t...args: Parameters<typeof data<Data>>\n) {\n\tensureProgressiveEnhancement(request, formData, () => ({\n\t\tstatusText: JSON.stringify(args[0]),\n\t\t...(typeof args[1] === 'number' ? { status: args[1] } : args[1]),\n\t}))\n\treturn data(...args)\n}\n","import * as cookie from 'cookie'\n\nconst cookieName = 'EpicShop_theme'\nexport type Theme = 'light' | 'dark'\n\nexport function getTheme(request: Request): Theme | null {\n\tconst cookieHeader = request.headers.get('cookie')\n\tconst parsed = cookieHeader ? cookie.parse(cookieHeader)[cookieName] : null\n\tif (parsed === 'light' || parsed === 'dark') return parsed\n\treturn null\n}\n\nexport function setTheme(theme: Theme | 'system') {\n\treturn cookie.serialize(cookieName, theme, {\n\t\tpath: '/',\n\t\tmaxAge: theme === 'system' ? 0 : 60 * 60 * 365 * 100,\n\t})\n}\n","import { getFormProps, useForm } from '@conform-to/react'\nimport { parseWithZod } from '@conform-to/zod'\nimport { data, redirect, useFetcher, useFetchers } from 'react-router'\nimport { safeRedirect } from 'remix-utils/safe-redirect'\nimport { z } from 'zod'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { useHints } from '#app/utils/client-hints.tsx'\nimport { ErrorList } from '#app/utils/forms.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { type Route } from './+types/index.tsx'\nimport { setTheme } from './theme-session.server.ts'\n\nconst ROUTE_PATH = '/theme'\n\nconst ThemeFormSchema = z.object({\n\ttheme: z.enum(['system', 'light', 'dark']),\n})\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst referrer = request.headers.get('Referer')\n\treturn redirect(safeRedirect(referrer ?? '/'), {\n\t\theaders: { 'Cache-Control': 'no-cache' },\n\t})\n}\n\nexport async function action({ request }: Route.ActionArgs) {\n\tconst formData = await request.formData()\n\tconst submission = parseWithZod(formData, {\n\t\tschema: ThemeFormSchema,\n\t})\n\tif (submission.status !== 'success') {\n\t\treturn data(submission.reply(), {\n\t\t\t// You can also use the status to determine the HTTP status code\n\t\t\tstatus: submission.status === 'error' ? 400 : 200,\n\t\t})\n\t}\n\tconst { theme } = submission.value\n\n\tconst responseInit = {\n\t\theaders: { 'set-cookie': setTheme(theme) },\n\t}\n\treturn dataWithPE(request, formData, submission.reply(), responseInit)\n}\n\nexport function ThemeSwitch() {\n\tconst requestInfo = useRequestInfo()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst fetcher = useFetcher<Route.ComponentProps['actionData']>()\n\n\tconst [form] = useForm({\n\t\tlastResult: fetcher.data,\n\t\tonValidate({ formData }) {\n\t\t\treturn parseWithZod(formData, { schema: ThemeFormSchema })\n\t\t},\n\t})\n\n\tconst mode = requestInfo.session.theme ?? 'system'\n\tconst nextMode =\n\t\tmode === 'system' ? 'light' : mode === 'light' ? 'dark' : 'system'\n\tconst modeLabel = {\n\t\tlight: <Icon size=\"md\" name=\"Sun\" title=\"Light mode\" />,\n\t\tdark: <Icon size=\"md\" name=\"Moon\" title=\"Dark mode\" />,\n\t\tsystem: <Icon size=\"md\" name=\"Laptop\" title=\"System mode\" />,\n\t}\n\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action={ROUTE_PATH} {...getFormProps(form)}>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t{peRedirectInput}\n\t\t\t\t<input type=\"hidden\" name=\"theme\" value={nextMode} />\n\t\t\t\t<SimpleTooltip content={`Change theme from ${mode} mode`}>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\tvalue=\"update-theme\"\n\t\t\t\t\t\tclassName=\"flex h-8 w-8 cursor-pointer items-center justify-center\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{modeLabel[mode]}\n\t\t\t\t\t</button>\n\t\t\t\t</SimpleTooltip>\n\t\t\t</div>\n\t\t\t<ErrorList errors={form.errors} id={form.errorId} />\n\t\t</fetcher.Form>\n\t)\n}\n\n/**\n * @returns the user's theme preference, or the client hint theme if the user\n * has not set a preference.\n */\nexport function useTheme() {\n\tconst hints = useHints()\n\tconst requestInfo = useRequestInfo()\n\tconst fetchers = useFetchers()\n\tconst fetcher = fetchers.find(\n\t\t(f) => f.formData?.get('intent') === 'update-theme',\n\t)\n\tconst optimisticTheme = fetcher?.formData?.get('theme')\n\tif (optimisticTheme === 'system') return hints.theme\n\tif (optimisticTheme === 'light' || optimisticTheme === 'dark') {\n\t\treturn optimisticTheme\n\t}\n\treturn requestInfo.session.theme ?? hints.theme\n}\n","import \"/home/runner/work/epicshop/epicshop/packages/workshop-app/app/styles/app.css?transform-only\";export default \"__VITE_CSS_URL__2f686f6d652f72756e6e65722f776f726b2f6570696373686f702f6570696373686f702f7061636b616765732f776f726b73686f702d6170702f6170702f7374796c65732f6170702e6373733f7472616e73666f726d2d6f6e6c79__\"","import \"/home/runner/work/epicshop/epicshop/packages/workshop-app/app/styles/tailwind.css?transform-only\";export default \"__VITE_CSS_URL__2f686f6d652f72756e6e65722f776f726b2f6570696373686f702f6570696373686f702f7061636b616765732f776f726b73686f702d6170702f6170702f7374796c65732f7461696c77696e642e6373733f7472616e73666f726d2d6f6e6c79__\"","import * as cookie from 'cookie'\nimport { redirect } from 'react-router'\nimport { combineHeaders } from './misc.tsx'\n\nconst cookieName = 'EpicShop_confetti'\n\nexport function getConfetti(request: Request) {\n\tconst cookieHeader = request.headers.get('cookie')\n\tconst confettiId = cookieHeader\n\t\t? cookie.parse(cookieHeader)[cookieName]\n\t\t: null\n\treturn {\n\t\tconfettiId,\n\t\theaders: confettiId ? createConfettiHeaders(null) : null,\n\t}\n}\n\n/**\n * This defaults the value to something reasonable if you want to show confetti.\n * If you want to clear the cookie, pass null and it will make a set-cookie\n * header that will delete the cookie\n *\n * @param value the value for the cookie in the set-cookie header\n * @returns Headers with a set-cookie header set to the value\n */\nexport function createConfettiHeaders(\n\tvalue: string | null = String(Date.now()),\n) {\n\treturn new Headers({\n\t\t'set-cookie': cookie.serialize(cookieName, value ? value : '', {\n\t\t\tpath: '/',\n\t\t\tmaxAge: value ? 60 : -1,\n\t\t}),\n\t})\n}\n\nexport async function redirectWithConfetti(url: string, init?: ResponseInit) {\n\treturn redirect(url, {\n\t\t...init,\n\t\theaders: combineHeaders(init?.headers, createConfettiHeaders()),\n\t})\n}\n","import { useSyncExternalStore } from 'react'\nimport { useRequestInfo } from './root-loader.ts'\n\nfunction getSnapshot() {\n\treturn window.navigator.onLine\n}\n\nfunction subscribe(callback: () => void) {\n\twindow.addEventListener('online', callback)\n\twindow.addEventListener('offline', callback)\n\treturn () => {\n\t\twindow.removeEventListener('online', callback)\n\t\twindow.removeEventListener('offline', callback)\n\t}\n}\n\nexport function useIsOnline() {\n\tconst requestInfo = useRequestInfo()\n\treturn useSyncExternalStore(subscribe, getSnapshot, () => requestInfo.online)\n}\n","import {\n\tMessageSchema,\n\tpartykitBaseUrl,\n\tpartykitRoom,\n\ttype Message,\n\ttype User,\n} from '@epic-web/workshop-presence/presence'\nimport { usePartySocket } from 'partysocket/react'\nimport {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport { useParams } from 'react-router'\nimport { z } from 'zod'\nimport { useIsOnline } from './online.ts'\nimport { useRequestInfo, useRootLoaderData } from './root-loader.ts'\n\nexport * from '@epic-web/workshop-presence/presence'\n\nconst PresenceContext = createContext<ReturnType<\n\ttypeof usePresenceSocket\n> | null>(null)\n\nexport function usePresencePreferences() {\n\tconst data = useRootLoaderData()\n\treturn data?.preferences?.presence ?? null\n}\n\nexport function useOptionalWorkshopTitle() {\n\tconst data = useRootLoaderData()\n\treturn data?.workshopTitle ?? null\n}\n\nconst ExerciseAppParamsSchema = z.object({\n\ttype: z.union([z.literal('problem'), z.literal('solution')]).optional(),\n\texerciseNumber: z.coerce.number().finite(),\n\tstepNumber: z.coerce.number().finite().optional(),\n})\n\n/**\n * useFirstCallDelayedCallback\n *\n * This hook creates a callback that is delayed on its first call.\n * It's useful for scenarios where you want to delay the execution of a function\n * for a certain amount of time, but only on the initial call.\n *\n * If it's called again before the delay expires, then the prior call is ignored\n * and when the delay expires, the latest call is executed.\n *\n * The motivation here is that the server may get one set of presence and by the\n * time it shows up on the client it's stale. This delays the re-rendering of\n * the UI to avoid a flicker as soon as you land on the page.\n *\n * @param cb The callback function to be delayed\n * @param delay The delay in milliseconds before the callback is executed\n * @returns A new function that wraps the original callback with the delay logic\n */\nfunction useFirstCallDelayedCallback<Args extends unknown[]>(\n\tcb: (...args: Args) => void,\n\tdelay: number,\n) {\n\tconst [timedPromise] = useState(\n\t\t() => new Promise((resolve) => setTimeout(resolve, delay)),\n\t)\n\tconst mounted = useRef(true)\n\tconst currentCallRef = useRef<symbol | null>(null)\n\tconst lastCbRef = useRef(cb)\n\n\tuseEffect(() => {\n\t\tlastCbRef.current = cb\n\t}, [cb])\n\n\tconst delayedCb = useCallback(\n\t\t(...args: Args) => {\n\t\t\tconst thisOne = Symbol()\n\t\t\tcurrentCallRef.current = thisOne\n\t\t\tvoid timedPromise.then(() => {\n\t\t\t\tif (!mounted.current) return\n\t\t\t\tif (currentCallRef.current !== thisOne) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlastCbRef.current(...args)\n\t\t\t})\n\t\t},\n\t\t[timedPromise],\n\t)\n\n\treturn delayedCb\n}\n\nfunction useProductHost() {\n\tconst data = useRootLoaderData()\n\treturn data?.workshopConfig?.product?.host ?? null\n}\n\nfunction useLoggedInProductHosts() {\n\tconst data = useRootLoaderData()\n\treturn data?.loggedInProductHosts ?? []\n}\n\nfunction useUsersLocation() {\n\tconst workshopTitle = useOptionalWorkshopTitle()\n\tconst requestInfo = useRequestInfo()\n\tconst productHost = useProductHost()\n\tconst rawParams = useParams()\n\tconst paramsResult = ExerciseAppParamsSchema.safeParse(rawParams)\n\tconst params = paramsResult.success ? paramsResult.data : null\n\tconst { ENV, repoUpdates } = useRootLoaderData() ?? {}\n\n\t// Extract epicshopVersion and repoStatus from root loader data\n\tconst epicshopVersion = ENV?.EPICSHOP_APP_VERSION ?? null\n\tconst repoStatus =\n\t\trepoUpdates && 'updatesAvailable' in repoUpdates ? { ...repoUpdates } : null\n\n\treturn {\n\t\tworkshopTitle,\n\t\torigin: requestInfo.origin,\n\t\tproductHost,\n\t\tepicshopVersion,\n\t\trepoStatus,\n\t\t...(params\n\t\t\t? {\n\t\t\t\t\texercise: {\n\t\t\t\t\t\ttype: params.type,\n\t\t\t\t\t\texerciseNumber: params.exerciseNumber,\n\t\t\t\t\t\tstepNumber: params.stepNumber,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: null),\n\t} satisfies User['location']\n}\n\nfunction usePresenceSocket(user?: User | null) {\n\tconst prefs = usePresencePreferences()\n\tconst { userId, presence, userHasAccess } = useRootLoaderData() ?? {}\n\tconst [users, setUsers] = useState(presence?.users ?? [])\n\tconst usersLocation = useUsersLocation()\n\tconst loggedInProductHosts = useLoggedInProductHosts()\n\n\tconst handleMessage = useFirstCallDelayedCallback((evt: MessageEvent) => {\n\t\tconst messageResult = MessageSchema.safeParse(JSON.parse(String(evt.data)))\n\t\tif (!messageResult.success) return\n\t\tif (messageResult.data.type === 'presence') {\n\t\t\tsetUsers(messageResult.data.payload.users)\n\t\t}\n\t}, 2000)\n\n\tconst socket = usePartySocket({\n\t\thost: new URL(partykitBaseUrl).host,\n\t\troom: partykitRoom,\n\t\tonMessage: handleMessage,\n\t})\n\n\t// Find the current user in presence.users (includes epicshopVersion, repoStatus, etc.)\n\tconst currentUserId = user?.id ?? userId?.id\n\tconst currentUserFromPresence = currentUserId\n\t\t? presence?.users?.find((u) => u.id === currentUserId)\n\t\t: null\n\n\t// Use the user data from presence.users as the base (has epicshopVersion, repoStatus, etc.)\n\t// Merge with user prop if provided, then override with dynamic fields\n\tconst baseUser = currentUserFromPresence ?? user ?? {}\n\n\tlet message: Message | null = null\n\tif (currentUserId) {\n\t\tif (prefs?.optOut) {\n\t\t\t// Send opt-out user with minimal info instead of removing entirely\n\t\t\tmessage = {\n\t\t\t\ttype: 'add-user',\n\t\t\t\tpayload: {\n\t\t\t\t\t...baseUser,\n\t\t\t\t\tid: currentUserId,\n\t\t\t\t\thasAccess: userHasAccess,\n\t\t\t\t\toptOut: true,\n\t\t\t\t\tloggedInProductHosts,\n\t\t\t\t\tlocation: usersLocation,\n\t\t\t\t},\n\t\t\t}\n\t\t} else {\n\t\t\t// Use the user data as-is, only update dynamic fields\n\t\t\tmessage = {\n\t\t\t\ttype: 'add-user',\n\t\t\t\tpayload: {\n\t\t\t\t\t...baseUser,\n\t\t\t\t\tid: currentUserId,\n\t\t\t\t\thasAccess: userHasAccess,\n\t\t\t\t\tlocation: usersLocation,\n\t\t\t\t\tloggedInProductHosts,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t}\n\n\tconst messageJson = message ? JSON.stringify(message) : null\n\tuseEffect(() => {\n\t\tif (messageJson) socket.send(messageJson)\n\t}, [messageJson, socket])\n\n\tconst scoredUsers = scoreUsers(\n\t\t{ id: userId?.id, location: usersLocation },\n\t\tusers,\n\t)\n\n\treturn { users: scoredUsers }\n}\n\n/**\n * Get all locations for a user (from locations array or falling back to location)\n */\nfunction getUserLocations(user: User): Array<NonNullable<User['location']>> {\n\tif (user.locations && user.locations.length > 0) {\n\t\treturn user.locations.filter(Boolean) as Array<\n\t\t\tNonNullable<User['location']>\n\t\t>\n\t}\n\tif (user.location) {\n\t\treturn [user.location]\n\t}\n\treturn []\n}\n\n/**\n * Sorts and scores users based on proximity to the current user.\n *\n * Sorting order:\n * 1. Self first\n * 2. Same exercise step (exerciseNumber + stepNumber + type)\n * 3. Same exercise (exerciseNumber)\n * 4. Same workshop (workshopTitle)\n * 5. Same product host\n * 6. Most products logged into\n * 7. Opted-out users last\n */\nfunction scoreUsers(\n\tcurrentUser: { id?: string | null; location: User['location'] },\n\tusers: Array<User>,\n) {\n\tconst { location } = currentUser\n\n\tconst scoredUsers = users.map((user) => {\n\t\t// Calculate score for visual styling (0-1)\n\t\t// Higher score = closer proximity = more prominent display\n\t\tlet score = 0\n\n\t\t// Opted-out users get no score for visual purposes\n\t\tif (user.optOut) {\n\t\t\treturn { user, score: 0 }\n\t\t}\n\n\t\tconst userLocations = getUserLocations(user)\n\n\t\t// Check if any of the user's locations match the current user's location\n\t\tfor (const userLoc of userLocations) {\n\t\t\t// Same workshop title\n\t\t\tif (\n\t\t\t\tlocation?.workshopTitle &&\n\t\t\t\tlocation.workshopTitle === userLoc.workshopTitle\n\t\t\t) {\n\t\t\t\tscore = Math.max(score, 0.4)\n\n\t\t\t\t// Same exercise\n\t\t\t\tif (\n\t\t\t\t\tlocation.exercise?.exerciseNumber != null &&\n\t\t\t\t\tlocation.exercise.exerciseNumber === userLoc.exercise?.exerciseNumber\n\t\t\t\t) {\n\t\t\t\t\tscore = Math.max(score, 0.6)\n\n\t\t\t\t\t// Same step\n\t\t\t\t\tif (\n\t\t\t\t\t\tlocation.exercise.stepNumber != null &&\n\t\t\t\t\t\tlocation.exercise.stepNumber === userLoc.exercise?.stepNumber\n\t\t\t\t\t) {\n\t\t\t\t\t\tscore = Math.max(score, 0.8)\n\n\t\t\t\t\t\t// Same type (problem/solution)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tlocation.exercise.type &&\n\t\t\t\t\t\t\tlocation.exercise.type === userLoc.exercise?.type\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tscore = 1\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tlocation?.productHost &&\n\t\t\t\tlocation.productHost === userLoc.productHost\n\t\t\t) {\n\t\t\t\t// Same product host but different workshop\n\t\t\t\tscore = Math.max(score, 0.2)\n\t\t\t}\n\t\t}\n\n\t\treturn { user, score }\n\t})\n\n\treturn scoredUsers.sort((a, b) => {\n\t\t// Self always first\n\t\tif (a.user.id === currentUser.id) return -1\n\t\tif (b.user.id === currentUser.id) return 1\n\n\t\t// Opted-out users always last\n\t\tif (a.user.optOut && !b.user.optOut) return 1\n\t\tif (!a.user.optOut && b.user.optOut) return -1\n\n\t\t// Same step (exerciseNumber + stepNumber + type match)\n\t\tconst aOnSameStep = userHasSameStep(location, a.user)\n\t\tconst bOnSameStep = userHasSameStep(location, b.user)\n\t\tif (aOnSameStep && !bOnSameStep) return -1\n\t\tif (!aOnSameStep && bOnSameStep) return 1\n\n\t\t// Same exercise (exerciseNumber match)\n\t\tconst aOnSameExercise = userHasSameExercise(location, a.user)\n\t\tconst bOnSameExercise = userHasSameExercise(location, b.user)\n\t\tif (aOnSameExercise && !bOnSameExercise) return -1\n\t\tif (!aOnSameExercise && bOnSameExercise) return 1\n\n\t\t// Same workshop\n\t\tconst aOnSameWorkshop = userHasSameWorkshop(location, a.user)\n\t\tconst bOnSameWorkshop = userHasSameWorkshop(location, b.user)\n\t\tif (aOnSameWorkshop && !bOnSameWorkshop) return -1\n\t\tif (!aOnSameWorkshop && bOnSameWorkshop) return 1\n\n\t\t// Same product host\n\t\tconst aOnSameProductHost = userHasSameProductHost(location, a.user)\n\t\tconst bOnSameProductHost = userHasSameProductHost(location, b.user)\n\t\tif (aOnSameProductHost && !bOnSameProductHost) return -1\n\t\tif (!aOnSameProductHost && bOnSameProductHost) return 1\n\n\t\t// Most products logged into\n\t\tconst aProductCount = a.user.loggedInProductHosts?.length ?? 0\n\t\tconst bProductCount = b.user.loggedInProductHosts?.length ?? 0\n\t\tif (aProductCount !== bProductCount) {\n\t\t\treturn bProductCount - aProductCount\n\t\t}\n\n\t\treturn 0\n\t})\n}\n\nfunction userHasSameStep(\n\tcurrentLocation: User['location'],\n\tuser: User,\n): boolean {\n\tif (!currentLocation?.exercise) return false\n\tconst userLocations = getUserLocations(user)\n\treturn userLocations.some(\n\t\t(loc) =>\n\t\t\tloc.workshopTitle === currentLocation.workshopTitle &&\n\t\t\tloc.exercise?.exerciseNumber ===\n\t\t\t\tcurrentLocation.exercise?.exerciseNumber &&\n\t\t\tloc.exercise?.stepNumber === currentLocation.exercise?.stepNumber &&\n\t\t\tloc.exercise?.type === currentLocation.exercise?.type,\n\t)\n}\n\nfunction userHasSameExercise(\n\tcurrentLocation: User['location'],\n\tuser: User,\n): boolean {\n\tif (!currentLocation?.exercise?.exerciseNumber) return false\n\tconst userLocations = getUserLocations(user)\n\treturn userLocations.some(\n\t\t(loc) =>\n\t\t\tloc.workshopTitle === currentLocation.workshopTitle &&\n\t\t\tloc.exercise?.exerciseNumber === currentLocation.exercise?.exerciseNumber,\n\t)\n}\n\nfunction userHasSameWorkshop(\n\tcurrentLocation: User['location'],\n\tuser: User,\n): boolean {\n\tif (!currentLocation?.workshopTitle) return false\n\tconst userLocations = getUserLocations(user)\n\treturn userLocations.some(\n\t\t(loc) => loc.workshopTitle === currentLocation.workshopTitle,\n\t)\n}\n\nfunction userHasSameProductHost(\n\tcurrentLocation: User['location'],\n\tuser: User,\n): boolean {\n\tif (!currentLocation?.productHost) return false\n\tconst userLocations = getUserLocations(user)\n\treturn userLocations.some(\n\t\t(loc) => loc.productHost === currentLocation.productHost,\n\t)\n}\n\nfunction PresenceOnline({\n\tuser,\n\tchildren,\n}: {\n\tuser?: User | null\n\tchildren: React.ReactNode\n}) {\n\treturn (\n\t\t<PresenceContext.Provider value={usePresenceSocket(user)}>\n\t\t\t{children}\n\t\t</PresenceContext.Provider>\n\t)\n}\n\nfunction PresenceOffline({\n\tuser,\n\tchildren,\n}: {\n\tuser?: User | null\n\tchildren: React.ReactNode\n}) {\n\tconst usersLocation = useUsersLocation()\n\tconst { presence } = useRootLoaderData() ?? {}\n\treturn (\n\t\t<PresenceContext.Provider\n\t\t\tvalue={{\n\t\t\t\tusers: scoreUsers(\n\t\t\t\t\t{ id: user?.id, location: usersLocation },\n\t\t\t\t\tpresence?.users ?? [],\n\t\t\t\t),\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t</PresenceContext.Provider>\n\t)\n}\n\nexport function Presence({\n\tuser,\n\tchildren,\n}: {\n\tuser?: User | null\n\tchildren: React.ReactNode\n}) {\n\tconst isOnline = useIsOnline()\n\tif (isOnline) {\n\t\treturn <PresenceOnline user={user}>{children}</PresenceOnline>\n\t} else {\n\t\treturn <PresenceOffline user={user}>{children}</PresenceOffline>\n\t}\n}\n\nexport function usePresence() {\n\tconst presence = useContext(PresenceContext)\n\tif (!presence) {\n\t\tthrow new Error('usePresence must be used within a PresenceProvider')\n\t}\n\treturn presence\n}\n","import { type getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\n\nexport function getSeoMetaTags({\n\ttitle,\n\tdescription,\n\tinstructor,\n\trequestInfo,\n\togTitle = title,\n\togDescription = description,\n\togImageUrl = requestInfo.domain +\n\t\t'/og?' +\n\t\tnew URLSearchParams({\n\t\t\ttitle: ogTitle,\n\t\t\tsubtitle: ogDescription ?? '',\n\t\t\turlPathname: requestInfo.path,\n\t\t\t// to make cache busting possible, whenever the og image changes, we can change the version\n\t\t\t// note if the inputs change, then the cache will be busted automatically\n\t\t\t// it's only if the image changes that we need to change the version\n\t\t\tversion: 'v4',\n\t\t}).toString(),\n\togImageAlt = title,\n}: {\n\ttitle: string\n\trequestInfo: { domain: string; path: string }\n\tdescription?: string\n\tinstructor: Partial<ReturnType<typeof getWorkshopConfig>['instructor']>\n\togTitle?: string\n\togDescription?: string\n\togImageUrl?: string\n\togImageAlt?: string\n}) {\n\treturn [\n\t\t{ title: title },\n\t\tdescription ? { description } : null,\n\t\tinstructor?.name ? { name: 'author', content: instructor.name } : null,\n\t\t{ name: 'og:site_name', content: title },\n\t\t{ name: 'twitter:card', content: 'summary_large_image' },\n\t\t{ name: 'twitter:creator', content: instructor?.['𝕏'] },\n\t\t{ name: 'og:title', content: ogTitle },\n\t\tdescription ? { name: 'og:description', content: ogDescription } : null,\n\t\t{ name: 'og:type', content: 'website' },\n\t\t{ name: 'og:image:width', content: '1200' },\n\t\t{ name: 'og:image:height', content: '630' },\n\t\t{ name: 'og:image:alt', content: ogImageAlt },\n\t\t{ name: 'og:image', content: ogImageUrl },\n\t].filter(Boolean)\n}\n","import { randomUUID as cuid } from 'crypto'\nimport { createCookieSessionStorage, redirect } from 'react-router'\nimport { z } from 'zod'\nimport { combineHeaders } from './misc.tsx'\n\nexport const toastKey = 'toast'\n\nconst TypeSchema = z.enum(['message', 'success', 'error'])\nconst ToastSchema = z\n\t.object({\n\t\tdescription: z.string(),\n\t\tid: z.string().default(() => cuid()),\n\t\ttitle: z.string().optional(),\n\t\ttype: TypeSchema.default('message'),\n\t})\n\t.transform((toast) => ({\n\t\t...toast,\n\t\ttitle: toast.title ? sanitizeCookieValue(toast.title) : undefined,\n\t\tdescription: sanitizeCookieValue(toast.description),\n\t}))\n\nexport type Toast = z.infer<typeof ToastSchema>\nexport type OptionalToast = Omit<Toast, 'id' | 'type'> & {\n\tid?: string\n\ttype?: z.infer<typeof TypeSchema>\n}\n\nexport const toastSessionStorage = createCookieSessionStorage({\n\tcookie: {\n\t\tname: 'EpicShop_toast',\n\t\tsameSite: 'lax',\n\t\tpath: '/',\n\t\thttpOnly: true,\n\t\tsecrets: ['not-so-secret'],\n\t\tsecure: process.env.NODE_ENV === 'production',\n\t},\n})\n\n/**\n * Sanitizes a string value to ensure it can be safely stored in a cookie.\n * Removes or replaces characters that cannot be converted to ByteString.\n */\nfunction sanitizeCookieValue(value: string): string {\n\t// Remove or replace characters with Unicode values > 255\n\treturn value\n\t\t.split('')\n\t\t.map((char) => {\n\t\t\tconst code = char.charCodeAt(0)\n\t\t\t// If character is > 255, replace with a safe alternative\n\t\t\tif (code > 255) {\n\t\t\t\t// Replace smart quotes with regular quotes\n\t\t\t\tif (code === 8216 || code === 8217) return \"'\" // smart single quote\n\t\t\t\tif (code === 8220 || code === 8221) return '\"' // smart double quote\n\t\t\t\tif (code === 8211 || code === 8212) return '-' // en dash and em dash\n\t\t\t\t// Replace other high Unicode characters with a safe fallback\n\t\t\t\treturn '?'\n\t\t\t}\n\t\t\treturn char\n\t\t})\n\t\t.join('')\n}\n\nexport async function redirectWithToast(\n\turl: string,\n\ttoast: OptionalToast,\n\tinit?: ResponseInit,\n) {\n\treturn redirect(url, {\n\t\t...init,\n\t\theaders: combineHeaders(init?.headers, await createToastHeaders(toast)),\n\t})\n}\n\nexport async function createToastHeaders(optionalToast: OptionalToast) {\n\tconst session = await toastSessionStorage.getSession()\n\tconst toast = ToastSchema.parse(optionalToast)\n\tsession.flash(toastKey, toast)\n\tconst cookie = await toastSessionStorage.commitSession(session)\n\treturn new Headers({ 'set-cookie': cookie })\n}\n\nexport async function getToast(request: Request) {\n\tconst session = await toastSessionStorage.getSession(\n\t\trequest.headers.get('cookie'),\n\t)\n\tconst result = ToastSchema.safeParse(session.get(toastKey))\n\tconst toast = result.success ? result.data : null\n\treturn {\n\t\ttoast,\n\t\theaders: toast\n\t\t\t? new Headers({\n\t\t\t\t\t'set-cookie': await toastSessionStorage.destroySession(session),\n\t\t\t\t})\n\t\t\t: null,\n\t}\n}\n","import path from 'node:path'\nimport { getPresentUsers } from '@epic-web/workshop-presence/presence.server'\nimport { getApps } from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetLoggedInProductHosts,\n\tgetPreferences,\n\tgetMutedNotifications,\n} from '@epic-web/workshop-utils/db.server'\nimport { getEnv } from '@epic-web/workshop-utils/env.server'\nimport {\n\tgetProgress,\n\tgetUserInfo,\n\tuserHasAccessToWorkshop,\n} from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcheckForUpdatesCached,\n\tcheckForExerciseChanges,\n} from '@epic-web/workshop-utils/git.server'\nimport { getUnmutedNotifications } from '@epic-web/workshop-utils/notifications.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport {\n\tgetSetClientIdCookieHeader,\n\tgetUserId,\n} from '@epic-web/workshop-utils/user.server'\nimport { checkConnection } from '@epic-web/workshop-utils/utils.server'\n\nimport * as React from 'react'\nimport {\n\tdata,\n\ttype LinksFunction,\n\tLinks,\n\tMeta,\n\tOutlet,\n\tScripts,\n\tScrollRestoration,\n\tuseLoaderData,\n\tuseNavigation,\n} from 'react-router'\nimport { promiseHash } from 'remix-utils/promise'\nimport { useSpinDelay } from 'spin-delay'\nimport { type Route } from './+types/root.tsx'\nimport { Confetti } from './components/confetti'\nimport { GeneralErrorBoundary } from './components/error-boundary'\nimport { ExerciseWarningBanner } from './components/exercise-warning-banner'\nimport { KeyboardShortcutsDialog } from './components/keyboard-shortcuts-dialog'\nimport { EpicProgress } from './components/progress-bar'\nimport { EpicToaster } from './components/toaster'\nimport { TooltipProvider } from './components/ui/tooltip'\nimport { UpdateToast } from './components/update-repo'\nimport { Notifications } from './routes/admin+/notifications'\nimport { useTheme } from './routes/theme/index'\nimport { getTheme } from './routes/theme/theme-session.server'\nimport appStylesheetUrl from './styles/app.css?url'\nimport tailwindStylesheetUrl from './styles/tailwind.css?url'\nimport { ClientHintCheck, getHints } from './utils/client-hints'\nimport { getConfetti } from './utils/confetti.server'\nimport { cn, combineHeaders, getDomainUrl, useAltDown } from './utils/misc'\nimport { Presence } from './utils/presence'\nimport { getSeoMetaTags } from './utils/seo'\nimport { getToast } from './utils/toast.server'\n\nexport const links: LinksFunction = () => {\n\treturn [\n\t\t{ rel: 'stylesheet', href: '/neogrotesk-font.css' },\n\t\t{\n\t\t\trel: 'stylesheet',\n\t\t\thref: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,200;0,300;0,400;0,500;0,600;1,700&display=swap',\n\t\t},\n\t\t{ rel: 'stylesheet', href: tailwindStylesheetUrl },\n\t\t{ rel: 'stylesheet', href: appStylesheetUrl },\n\t\t{\n\t\t\trel: 'icon',\n\t\t\thref: '/favicon.ico',\n\t\t\tsizes: '48x48',\n\t\t},\n\t\t{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },\n\t]\n}\n\nexport const meta: Route.MetaFunction = ({ loaderData }) => {\n\tif (!loaderData) return []\n\n\treturn getSeoMetaTags({\n\t\tinstructor: loaderData.instructor,\n\t\ttitle: loaderData.workshopTitle,\n\t\tdescription: loaderData.workshopSubtitle,\n\t\trequestInfo: loaderData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('rootLoader')\n\tconst workshopConfig = getWorkshopConfig()\n\tconst {\n\t\ttitle: workshopTitle,\n\t\tsubtitle: workshopSubtitle,\n\t\tinstructor,\n\t} = workshopConfig\n\n\tconst theme = getTheme(request)\n\tconst { confettiId, headers: confettiHeaders } = getConfetti(request)\n\tconst { toast, headers: toastHeaders } = await getToast(request)\n\tconst isOnlinePromise = checkConnection({ request, timings })\n\n\tconst asyncStuff = await promiseHash({\n\t\tuserId: getUserId({ request }),\n\t\tpreferences: getPreferences(),\n\t\tprogress: getProgress({ timings }).catch((e) => {\n\t\t\tconsole.error('Failed to get progress', e)\n\t\t\tconst emptyProgress: Awaited<ReturnType<typeof getProgress>> = []\n\t\t\treturn emptyProgress\n\t\t}),\n\t\tuser: getUserInfo(),\n\t\tuserHasAccess: userHasAccessToWorkshop({ request, timings }),\n\t\tapps: getApps({ request, timings }),\n\t\trepoUpdates: checkForUpdatesCached(),\n\t\tunmutedNotifications: getUnmutedNotifications(),\n\t\texerciseChanges: checkForExerciseChanges(),\n\t\tloggedInProductHosts: getLoggedInProductHosts(),\n\t})\n\n\tconst presentUsers = await getPresentUsers({\n\t\trequest,\n\t\ttimings,\n\t})\n\n\t// Filter out repoUpdates if muted\n\tconst mutedNotifications = await getMutedNotifications()\n\tlet repoUpdates = asyncStuff.repoUpdates\n\tif (\n\t\trepoUpdates &&\n\t\t'remoteCommit' in repoUpdates &&\n\t\trepoUpdates.remoteCommit &&\n\t\tmutedNotifications.includes(`update-repo-${repoUpdates.remoteCommit}`)\n\t) {\n\t\trepoUpdates = { ...repoUpdates, updatesAvailable: false }\n\t}\n\n\treturn data(\n\t\t{\n\t\t\t...asyncStuff,\n\t\t\tworkshopConfig,\n\t\t\tworkshopTitle,\n\t\t\tworkshopSubtitle,\n\t\t\tinstructor,\n\t\t\tapps: asyncStuff.apps.map(({ name, fullPath, relativePath }) => ({\n\t\t\t\tname,\n\t\t\t\tfullPath,\n\t\t\t\trelativePath,\n\t\t\t})),\n\t\t\tENV: getEnv(),\n\t\t\trequestInfo: {\n\t\t\t\tprotocol: new URL(request.url).protocol,\n\t\t\t\thostname: new URL(request.url).hostname,\n\t\t\t\tport: new URL(request.url).port,\n\t\t\t\torigin: new URL(request.url).origin,\n\t\t\t\tdomain: getDomainUrl(request),\n\t\t\t\thints: getHints(request),\n\t\t\t\tpath: new URL(request.url).pathname,\n\t\t\t\tsession: { theme },\n\t\t\t\tseparator: path.sep,\n\t\t\t\tonline: await isOnlinePromise,\n\t\t\t},\n\t\t\ttoast,\n\t\t\tconfettiId,\n\t\t\tpresence: {\n\t\t\t\tusers: presentUsers,\n\t\t\t},\n\t\t\trepoUpdates,\n\t\t\texerciseChanges: asyncStuff.exerciseChanges,\n\t\t},\n\t\t{\n\t\t\theaders: combineHeaders(\n\t\t\t\ttoastHeaders,\n\t\t\t\tconfettiHeaders,\n\t\t\t\t{ 'Server-Timing': timings.toString() },\n\t\t\t\tasyncStuff.userId?.type === 'cookie.randomId'\n\t\t\t\t\t? { 'Set-Cookie': getSetClientIdCookieHeader(asyncStuff.userId.id) }\n\t\t\t\t\t: undefined,\n\t\t\t),\n\t\t},\n\t)\n}\n\nfunction Document({\n\tchildren,\n\tenv = {},\n\tclassName,\n\tstyle,\n}: {\n\tchildren: React.ReactNode\n\tenv?: Record<string, unknown>\n\tclassName: string\n\tstyle?: React.CSSProperties\n}) {\n\treturn (\n\t\t<html lang=\"en\" className={className} style={style}>\n\t\t\t<head>\n\t\t\t\t<ClientHintCheck />\n\t\t\t\t<Meta />\n\t\t\t\t<meta charSet=\"utf-8\" />\n\t\t\t\t<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n\t\t\t\t<Links />\n\t\t\t\t<script\n\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t__html: `window.ENV = ${JSON.stringify(env)}`,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</head>\n\t\t\t<body className=\"bg-background text-foreground scrollbar-thin scrollbar-thumb-scrollbar h-screen-safe\">\n\t\t\t\t{children}\n\t\t\t\t<ScrollRestoration />\n\t\t\t\t<Scripts />\n\t\t\t</body>\n\t\t</html>\n\t)\n}\n\nfunction App() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst navigation = useNavigation()\n\tconst showSpinner = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 400,\n\t\tminDuration: 200,\n\t})\n\tconst altDown = useAltDown()\n\tconst [showKeyboardShortcuts, setShowKeyboardShortcuts] =\n\t\tReact.useState(false)\n\n\tReact.useEffect(() => {\n\t\tconst handleToggle = () => {\n\t\t\tsetShowKeyboardShortcuts((prev) => !prev)\n\t\t}\n\t\twindow.addEventListener('toggle-keyboard-shortcuts', handleToggle)\n\t\treturn () => {\n\t\t\twindow.removeEventListener('toggle-keyboard-shortcuts', handleToggle)\n\t\t}\n\t}, [])\n\n\tconst theme = useTheme()\n\treturn (\n\t\t<Document\n\t\t\tstyle={\n\t\t\t\tdata.preferences?.fontSize\n\t\t\t\t\t? { fontSize: `${data.preferences?.fontSize}px` }\n\t\t\t\t\t: {}\n\t\t\t}\n\t\t\tclassName={cn(\n\t\t\t\t'h-screen-safe antialiased',\n\t\t\t\ttheme,\n\t\t\t\t{ 'cursor-progress': showSpinner },\n\t\t\t\taltDown ? 'alt-down' : null,\n\t\t\t)}\n\t\t\tenv={data.ENV}\n\t\t>\n\t\t\t{data.exerciseChanges &&\n\t\t\t\t!data.preferences?.exerciseWarning?.dismissed && (\n\t\t\t\t\t<ExerciseWarningBanner />\n\t\t\t\t)}\n\t\t\t<Outlet />\n\t\t\t<Confetti id={data.confettiId} />\n\t\t\t<EpicToaster toast={data.toast} />\n\t\t\t<UpdateToast repoUpdates={data.repoUpdates} />\n\t\t\t<EpicProgress />\n\t\t\t<Notifications unmutedNotifications={data.unmutedNotifications} />\n\t\t\t<KeyboardShortcutsDialog\n\t\t\t\topen={showKeyboardShortcuts}\n\t\t\t\tonOpenChange={setShowKeyboardShortcuts}\n\t\t\t/>\n\t\t</Document>\n\t)\n}\n\nexport default function AppWithProviders() {\n\tconst { user } = useLoaderData<typeof loader>()\n\treturn (\n\t\t<Presence user={user}>\n\t\t\t<TooltipProvider>\n\t\t\t\t<App />\n\t\t\t</TooltipProvider>\n\t\t</Presence>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<Document className=\"h-screen-safe\">\n\t\t\t<GeneralErrorBoundary />\n\t\t</Document>\n\t)\n}\n","// This is called a \"splat route\" and as it's in the root `/app/routes/`\n// directory, it's a catchall. If no other routes match, this one will and we\n// can know that the user is hitting a URL that doesn't exist. By throwing a\n// 404 from the loader, we can force the error boundary to render which will\n// ensure the user gets the right status code and we can display a nicer error\n// message for them than the Remix and/or browser default.\n\nimport { type LoaderFunctionArgs, Link, useLocation } from 'react-router'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { Icon } from '#app/components/icons.tsx'\n\nexport async function loader({ params }: LoaderFunctionArgs) {\n\tconst splat = params['*']\n\tconst segments = splat?.split('/') ?? []\n\tif (segments.length > 0 && !isNaN(Number(segments[0]))) {\n\t\tconst newPath = `/exercise/${splat}`\n\t\treturn new Response(null, {\n\t\t\tstatus: 302,\n\t\t\theaders: {\n\t\t\t\tLocation: newPath,\n\t\t\t},\n\t\t})\n\t}\n\n\tthrow new Response('Not found', { status: 404 })\n}\n\nexport default function NotFound() {\n\t// due to the loader, this component will never be rendered, but we'll return\n\t// the error boundary just in case.\n\treturn <ErrorBoundary />\n}\n\nexport function ErrorBoundary() {\n\tconst location = useLocation()\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => (\n\t\t\t\t\t<div className=\"flex flex-col gap-6\">\n\t\t\t\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t\t\t\t<h1>We can't find this page:</h1>\n\t\t\t\t\t\t\t<pre className=\"text-body-lg break-all whitespace-pre-wrap\">\n\t\t\t\t\t\t\t\t{location.pathname}\n\t\t\t\t\t\t\t</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<Link to=\"/\" className=\"text-body-md underline\">\n\t\t\t\t\t\t\t<Icon name=\"ArrowLeft\">Back to home</Icon>\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t</div>\n\t\t\t\t),\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import { useSyncExternalStore } from 'react'\n\nexport function makeMediaQueryStore(\n\tmediaQuery: string,\n\tserverSnapshot: boolean,\n) {\n\tfunction getSnapshot() {\n\t\treturn window.matchMedia(mediaQuery).matches\n\t}\n\n\tfunction subscribe(callback: () => void) {\n\t\tconst mediaQueryList = window.matchMedia(mediaQuery)\n\t\tmediaQueryList.addEventListener('change', callback)\n\t\treturn () => {\n\t\t\tmediaQueryList.removeEventListener('change', callback)\n\t\t}\n\t}\n\n\treturn function useMediaQuery() {\n\t\treturn useSyncExternalStore(subscribe, getSnapshot, () => serverSnapshot)\n\t}\n}\n","import { invariant } from '@epic-web/invariant'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\n\nexport function useWorkshopConfig() {\n\tconst data = useRootLoaderData()\n\tinvariant(data.workshopConfig, 'useWorkshopConfig requires a workshopConfig.')\n\treturn data.workshopConfig\n}\n","import { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useWorkshopConfig } from './workshop-config.tsx'\n\ntype Sizes = 'font' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n\nconst sizeClassName = {\n\tfont: 'w-[1em] h-[1em]',\n\txs: 'w-3 h-3',\n\tsm: 'w-4 h-4',\n\tmd: 'w-5 h-5',\n\tlg: 'w-6 h-6',\n\txl: 'w-7 h-7',\n\t'2xl': 'w-8 h-8',\n} as const\n\nconst childrenSizeClassName = {\n\tfont: 'gap-1.5',\n\txs: 'gap-1.5',\n\tsm: 'gap-1.5',\n\tmd: 'gap-2',\n\tlg: 'gap-2',\n\txl: 'gap-3',\n\t'2xl': 'gap-4',\n} satisfies Record<Sizes, string>\n\nexport function ProductName(props: React.HTMLAttributes<HTMLSpanElement>) {\n\tconst {\n\t\tproduct: { displayName },\n\t} = useWorkshopConfig()\n\treturn <span {...props}>{displayName}</span>\n}\n\nexport function Logo({\n\tsize = 'font',\n\tstyle = 'themed',\n\tclassName,\n\tchildren,\n\t...props\n}: React.SVGProps<SVGSVGElement> & {\n\tsize?: Sizes\n\tstyle?: 'themed' | 'monochrome'\n\tclassName?: string\n\tchildren?: React.ReactNode\n}) {\n\tconst {\n\t\tproduct: { logo, displayName },\n\t} = useWorkshopConfig()\n\tconst theme = useTheme()\n\n\tconst logoElement = logo.includes('.svg') ? (\n\t\t<svg\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t>\n\t\t\t<title>{displayName}</title>\n\t\t\t<use href={`${logo}#${style === 'themed' ? theme : 'monochrome'}`} />\n\t\t</svg>\n\t) : (\n\t\t// @ts-expect-error - svg props can't all be applied to img... meh, probably won't ever be a real issue...\n\t\t<img\n\t\t\tsrc={logo}\n\t\t\talt={displayName}\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t/>\n\t)\n\n\tif (children) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={`inline-flex items-center ${childrenSizeClassName[size]}`}\n\t\t\t>\n\t\t\t\t{logoElement}\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn logoElement\n}\n","import { useEffect, useRef } from 'react'\nimport { useRevalidator } from 'react-router'\nimport { z } from 'zod'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\n\nconst eventSchema = z.object({\n\ttype: z.literal('epicshop:file-change'),\n\tdata: z.object({\n\t\tfilePaths: z.array(z.string()),\n\t}),\n})\n\nfunction useRevalidationWSImpl({ watchPaths }: { watchPaths: Array<string> }) {\n\tconst requestInfo = useRequestInfo()\n\n\tconst revalidator = useRevalidator()\n\tconst latestRevalidatorRef = useRef(revalidator)\n\tuseEffect(() => {\n\t\tlatestRevalidatorRef.current = revalidator\n\t}, [revalidator])\n\n\tconst socketParams = new URLSearchParams()\n\tfor (const path of watchPaths) {\n\t\tsocketParams.append('watch', path)\n\t}\n\tconst socketQuery = socketParams.toString()\n\tconst protocol = requestInfo.protocol === 'https:' ? 'wss:' : 'ws:'\n\tconst host = requestInfo.hostname\n\tconst port = requestInfo.port\n\tconst socketPath = `${protocol}//${host}:${port}/__ws?${socketQuery}`\n\n\tuseEffect(() => {\n\t\tif (!socketQuery) return\n\t\tlet ws: WebSocket | null = null\n\t\tfunction createWebSocket() {\n\t\t\tif (ws) ws.close()\n\n\t\t\ttry {\n\t\t\t\tws = new WebSocket(socketPath)\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('🐨 EpicShop WebSocket failed to connect:', error)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tws.onmessage = (message) => {\n\t\t\t\tconst eventParsed = eventSchema.safeParse(JSON.parse(message.data))\n\t\t\t\tif (!eventParsed.success) return\n\t\t\t\tconst { data: event } = eventParsed\n\t\t\t\tif (event.type !== 'epicshop:file-change') return\n\t\t\t\tconsole.log(\n\t\t\t\t\t'🐨 Revalidating due to file changes:',\n\t\t\t\t\tevent.data.filePaths,\n\t\t\t\t)\n\t\t\t\tvoid latestRevalidatorRef.current.revalidate()\n\t\t\t}\n\n\t\t\tws.onclose = (event) => {\n\t\t\t\tif (event.code === 1006) {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tcreateWebSocket()\n\t\t\t\t\t}, 1000)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tws.onerror = (error) => {\n\t\t\t\tconsole.error('🐨 EpicShop WebSocket error:', error)\n\t\t\t}\n\t\t}\n\n\t\tcreateWebSocket()\n\n\t\t// Cleanup function to close the WebSocket when the component unmounts\n\t\treturn () => {\n\t\t\tws?.close()\n\t\t}\n\t}, [socketQuery, socketPath])\n}\n\nexport const useRevalidationWS = ENV.EPICSHOP_DEPLOYED\n\t? () => null\n\t: useRevalidationWSImpl\n","import { useRootLoaderData } from '#app/utils/root-loader.ts'\n\nexport function useOptionalUser() {\n\tconst data = useRootLoaderData()\n\treturn data.user\n}\n\nexport function useUser() {\n\tconst user = useOptionalUser()\n\tif (!user) {\n\t\tthrow new Error(\n\t\t\t'useUser requires a user. If the user is optional, use useOptionalUser instead.',\n\t\t)\n\t}\n\treturn user\n}\n\nexport function useOptionalDiscordMember() {\n\tconst data = useRootLoaderData()\n\treturn data.user?.discordProfile?.user\n\t\t? {\n\t\t\t\tid: data.user.discordProfile.user.id,\n\t\t\t\tdisplayName:\n\t\t\t\t\tdata.user.discordProfile.nick ??\n\t\t\t\t\tdata.user.discordProfile.user.global_name ??\n\t\t\t\t\tdata.user.name ??\n\t\t\t\t\tdata.user.email,\n\t\t\t\tavatarUrl: data.user.imageUrlLarge,\n\t\t\t}\n\t\t: null\n}\n\nexport function useDiscordMember() {\n\tconst discordMember = useOptionalDiscordMember()\n\tif (!discordMember) {\n\t\tthrow new Error(\n\t\t\t'useDiscordMember requires a discordMember. If the discordMember is optional, use useOptionalDiscordMember instead.',\n\t\t)\n\t}\n\treturn discordMember\n}\n\nexport function useUserHasAccess() {\n\tconst data = useRootLoaderData()\n\treturn data.userHasAccess\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport { requireAuthInfo } from '@epic-web/workshop-utils/db.server'\nimport {\n\tgetProgress,\n\tupdateProgress,\n\ttype Progress,\n} from '@epic-web/workshop-utils/epic-api.server'\nimport clsx from 'clsx'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\nimport {\n\tuseFetcher,\n\tuseFetchers,\n\tuseLocation,\n\tuseNavigation,\n\ttype ActionFunctionArgs,\n} from 'react-router'\nimport { createConfettiHeaders } from '#app/utils/confetti.server.ts'\nimport { combineHeaders, ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nexport function useEpicProgress() {\n\tconst data = useRootLoaderData()\n\tconst progressFetcher = useFetchers().find(\n\t\t(f) => f.formAction === '/progress' && f.formData?.has('complete'),\n\t)\n\tif (!progressFetcher || !data.progress) return data.progress ?? null\n\treturn data.progress.map((p) => {\n\t\tconst optimisticCompleted =\n\t\t\tprogressFetcher.formData?.get('complete') === 'true'\n\t\tconst optimisticLessonSlug = progressFetcher.formData?.get('lessonSlug')\n\t\tif (optimisticLessonSlug === p.epicLessonSlug) {\n\t\t\treturn {\n\t\t\t\t...p,\n\t\t\t\tepicCompletedAt: optimisticCompleted ? Date.now() : null,\n\t\t\t}\n\t\t} else {\n\t\t\treturn p\n\t\t}\n\t})\n}\nexport type SerializedProgress = ReturnType<\n\ttypeof useRequireEpicProgress\n>[number]\nexport function useRequireEpicProgress() {\n\tconst progress = useEpicProgress()\n\tif (!progress) return []\n\treturn progress\n}\n\nexport function useNextExerciseRoute() {\n\tconst currentPathname = useLocation().pathname\n\tconst progress = useEpicProgress()\n\tif (!progress) return null\n\tconst scoreProgress = (a: (typeof progress)[number]) => {\n\t\tif (a.type === 'workshop-instructions') return 0\n\t\tif (a.type === 'workshop-finished') return 10000\n\t\tif (a.type === 'instructions') return a.exerciseNumber * 100\n\t\tif (a.type === 'step') return a.exerciseNumber * 100 + a.stepNumber\n\t\tif (a.type === 'finished') return a.exerciseNumber * 100 + 100\n\n\t\tif (a.type === 'unknown') return 100000\n\t\treturn -1\n\t}\n\tconst sortedProgress = progress.sort((a, b) => {\n\t\treturn scoreProgress(a) - scoreProgress(b)\n\t})\n\tconst nextProgress = sortedProgress.find((p) => !p.epicCompletedAt)\n\tif (!nextProgress) return null\n\n\tif (nextProgress.type === 'unknown') return null\n\tif (nextProgress.type === 'workshop-instructions') return '/'\n\tif (nextProgress.type === 'workshop-finished') return '/finished'\n\n\tconst ex = nextProgress.exerciseNumber.toString().padStart(2, '0')\n\tif (nextProgress.type === 'instructions') return `/exercise/${ex}`\n\tif (nextProgress.type === 'finished') return `/exercise/${ex}/finished`\n\n\tconst st = nextProgress.stepNumber.toString().padStart(2, '0')\n\n\tif (nextProgress.type === 'step') {\n\t\tconst problemRoute = `/exercise/${ex}/${st}/problem`\n\t\tconst solutionRoute = `/exercise/${ex}/${st}/solution`\n\t\tif (currentPathname === problemRoute || currentPathname === solutionRoute) {\n\t\t\treturn solutionRoute\n\t\t}\n\t\treturn problemRoute\n\t}\n\n\treturn null\n}\n\nconst percentageClassNames = {\n\t0: '',\n\t1: 'before:h-[10%]',\n\t2: 'before:h-[20%]',\n\t3: 'before:h-[30%]',\n\t4: 'before:h-[40%]',\n\t5: 'before:h-[50%]',\n\t6: 'before:h-[60%]',\n\t7: 'before:h-[70%]',\n\t8: 'before:h-[80%]',\n\t9: 'before:h-[90%]',\n\t10: 'before:h-[100%]',\n}\n\nexport function useExerciseProgressClassName(exerciseNumber: number) {\n\tconst progress = useEpicProgress()\n\tif (!progress?.length) return null\n\tconst exerciseProgress = progress.filter(\n\t\t(p) =>\n\t\t\t(p.type === 'instructions' ||\n\t\t\t\tp.type === 'step' ||\n\t\t\t\tp.type === 'finished') &&\n\t\t\tp.exerciseNumber === exerciseNumber,\n\t)\n\tif (!exerciseProgress.length) return null\n\n\tconst percentComlete =\n\t\texerciseProgress.reduce(\n\t\t\t(acc, p) => (p.epicCompletedAt ? acc + 1 : acc),\n\t\t\t0,\n\t\t) / exerciseProgress.length\n\n\tconst numerator = Math[percentComlete > 0.1 ? 'floor' : 'ceil'](\n\t\tpercentComlete * 10,\n\t) as 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10\n\n\treturn `relative ${percentageClassNames[numerator]} before:bg-highlight before:absolute before:left-0 before:top-0 before:w-[4px]`\n}\n\nexport function useProgressItemClassName(\n\tprogressItemSearch: ProgressItemSearch,\n) {\n\tconst progressItem = useProgressItem(progressItemSearch)\n\tif (!progressItem?.epicCompletedAt) return null\n\treturn `relative before:h-[100%] before:bg-highlight before:absolute before:left-0 before:top-0 before:w-[4px]`\n}\n\ntype WorkshopProgressType = Extract<\n\tProgress['type'],\n\t'workshop-instructions' | 'workshop-finished'\n>\ntype ExerciseProgressType = Extract<\n\tProgress['type'],\n\t'instructions' | 'finished'\n>\ntype StepProgressType = Extract<Progress['type'], 'step'>\n\nexport type ProgressItemSearch =\n\t| {\n\t\t\texerciseNumber: number\n\t\t\tstepNumber?: never\n\t\t\ttype: ExerciseProgressType\n\t }\n\t| {\n\t\t\texerciseNumber: number\n\t\t\tstepNumber: number\n\t\t\ttype: StepProgressType\n\t }\n\t| {\n\t\t\ttype: WorkshopProgressType\n\t\t\texerciseNumber?: never\n\t\t\tstepNumber?: never\n\t }\n\nexport function useProgressItem({\n\texerciseNumber,\n\tstepNumber,\n\ttype,\n}: ProgressItemSearch) {\n\tconst progress = useEpicProgress()\n\tif (!progress?.length) return null\n\n\tif (type === 'workshop-finished' || type === 'workshop-instructions') {\n\t\treturn progress.find((p) => p.type === type) ?? null\n\t} else if (type === 'instructions' || type === 'finished') {\n\t\treturn (\n\t\t\tprogress.find(\n\t\t\t\t(p) => p.type === type && p.exerciseNumber === exerciseNumber,\n\t\t\t) ?? null\n\t\t)\n\t} else if (type === 'step') {\n\t\treturn (\n\t\t\tprogress.find(\n\t\t\t\t(p) =>\n\t\t\t\t\tp.type === type &&\n\t\t\t\t\tp.exerciseNumber === exerciseNumber &&\n\t\t\t\t\tp.stepNumber === stepNumber,\n\t\t\t) ?? null\n\t\t)\n\t}\n\treturn null\n}\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tawait requireAuthInfo({ request })\n\tconst formData = await request.formData()\n\tconst complete = formData.get('complete') === 'true'\n\tconst lessonSlug = formData.get('lessonSlug')\n\tinvariantResponse(\n\t\ttypeof lessonSlug === 'string' && lessonSlug.length > 0,\n\t\t'lessonSlug must be a string',\n\t\t{ status: 400 },\n\t)\n\tconst beforeProgress = await getProgress({ request }).catch((e) => {\n\t\tconsole.error('Failed to get progress', e)\n\t\treturn []\n\t})\n\tconst result = await updateProgress({ lessonSlug, complete }, { request })\n\n\tconst lessonProgress = beforeProgress.find(\n\t\t(p) => p.epicLessonSlug === lessonSlug,\n\t)\n\tfunction getCompletionAnnouncement() {\n\t\tif (!complete) return null\n\t\tif (!lessonProgress) return null\n\t\tconst allOtherAreFinished = beforeProgress.every(\n\t\t\t(p) =>\n\t\t\t\tp.epicCompletedAt || p.epicLessonSlug === lessonProgress.epicLessonSlug,\n\t\t)\n\t\tif (allOtherAreFinished) return 'You completed the workshop!'\n\n\t\tif (\n\t\t\tlessonProgress.type === 'workshop-instructions' ||\n\t\t\tlessonProgress.type === 'unknown' ||\n\t\t\tlessonProgress.type === 'workshop-finished'\n\t\t) {\n\t\t\treturn null\n\t\t}\n\t\tconst { exerciseNumber } = lessonProgress\n\t\tconst otherExerciseLessons = beforeProgress.filter(\n\t\t\t(p) =>\n\t\t\t\t(p.type === 'step' ||\n\t\t\t\t\tp.type === 'instructions' ||\n\t\t\t\t\tp.type === 'finished') &&\n\t\t\t\tp.exerciseNumber === exerciseNumber &&\n\t\t\t\tp.epicLessonSlug !== lessonSlug,\n\t\t)\n\t\tconst otherAreFinished = otherExerciseLessons.every(\n\t\t\t(p) => p.epicCompletedAt,\n\t\t)\n\t\treturn otherAreFinished ? `You completed exercise ${exerciseNumber}!` : null\n\t}\n\tconst announcement = getCompletionAnnouncement()\n\n\treturn dataWithPE(request, formData, result, {\n\t\theaders: combineHeaders(\n\t\t\tannouncement ? createConfettiHeaders() : null,\n\t\t\tannouncement\n\t\t\t\t? await createToastHeaders({\n\t\t\t\t\t\ttitle: 'Congratulations!',\n\t\t\t\t\t\tdescription: announcement,\n\t\t\t\t\t\ttype: 'success',\n\t\t\t\t\t})\n\t\t\t\t: null,\n\t\t),\n\t})\n}\n\nexport function ProgressToggle({\n\tclassName,\n\t...progressItemSearch\n}: { className?: string } & ProgressItemSearch) {\n\tconst progressFetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst progressItem = useProgressItem(progressItemSearch)\n\tconst animationRef = React.useRef<HTMLDivElement>(null)\n\tconst buttonRef = React.useRef<HTMLButtonElement>(null)\n\n\tconst optimisticCompleted = progressFetcher.formData?.has('complete')\n\t\t? progressFetcher.formData.get('complete') === 'true'\n\t\t: Boolean(progressItem?.epicCompletedAt)\n\n\tconst [startAnimation, setStartAnimation] = React.useState(false)\n\n\tconst location = useLocation()\n\tconst navigation = useNavigation()\n\n\tconst navigationLocationStateFrom = navigation.location?.state?.from\n\tconst navigationLocationPathname = navigation.location?.pathname\n\n\tconst locationPathname = location.pathname\n\tReact.useEffect(() => {\n\t\tif (navigationLocationStateFrom === 'continue next lesson button') {\n\t\t\tif (locationPathname === navigationLocationPathname) {\n\t\t\t\tsetStartAnimation(true)\n\t\t\t\tbuttonRef.current?.focus()\n\t\t\t}\n\t\t}\n\t}, [\n\t\tlocation.key,\n\t\tlocationPathname,\n\t\tnavigationLocationPathname,\n\t\tnavigationLocationStateFrom,\n\t])\n\n\tReact.useEffect(() => {\n\t\tlet latest = true\n\t\tif (!startAnimation) return\n\n\t\t// wait a bit for the animation to start\n\t\tvoid new Promise((resolve) => setTimeout(resolve, 200)).then(async () => {\n\t\t\tif (!latest) return\n\t\t\tif (!animationRef.current) return\n\n\t\t\tconst animationPromises = animationRef.current\n\t\t\t\t.getAnimations()\n\t\t\t\t.map(({ finished }) => finished)\n\n\t\t\treturn Promise.allSettled(animationPromises).then(() => {\n\t\t\t\tif (!latest) return\n\t\t\t\tsetStartAnimation(false)\n\t\t\t})\n\t\t})\n\t\treturn () => {\n\t\t\tlatest = false\n\t\t}\n\t}, [startAnimation])\n\n\tif (ENV.EPICSHOP_DEPLOYED || !progressItem) return null\n\n\treturn (\n\t\t<progressFetcher.Form method=\"POST\" action=\"/progress\">\n\t\t\t{peRedirectInput}\n\t\t\t<input\n\t\t\t\ttype=\"hidden\"\n\t\t\t\tname=\"lessonSlug\"\n\t\t\t\tvalue={progressItem.epicLessonSlug}\n\t\t\t/>\n\t\t\t<input\n\t\t\t\ttype=\"hidden\"\n\t\t\t\tname=\"complete\"\n\t\t\t\tvalue={(!optimisticCompleted).toString()}\n\t\t\t/>\n\n\t\t\t<motion.button\n\t\t\t\tref={buttonRef}\n\t\t\t\tonClick={() => {\n\t\t\t\t\tsetStartAnimation(!optimisticCompleted)\n\t\t\t\t}}\n\t\t\t\ttype=\"submit\"\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'group relative flex w-full items-center justify-between overflow-hidden transition hover:bg-[hsl(var(--foreground)/0.02)] focus:bg-[hsl(var(--foreground)/0.02)]',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{optimisticCompleted ? 'Mark as incomplete' : 'Mark as complete'}\n\t\t\t\t{startAnimation ? (\n\t\t\t\t\t<motion.div\n\t\t\t\t\t\tref={animationRef}\n\t\t\t\t\t\tclassName=\"bg-foreground/20 absolute right-0 h-20 w-20 rounded-full\"\n\t\t\t\t\t\tinitial={{\n\t\t\t\t\t\t\tscale: 0.5,\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\tscale: [0.5, 2],\n\t\t\t\t\t\t\topacity: [0, 1, 0],\n\t\t\t\t\t\t}}\n\t\t\t\t\t\ttransition={{\n\t\t\t\t\t\t\tduration: 1,\n\t\t\t\t\t\t\tease: 'easeInOut',\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t\t<motion.div\n\t\t\t\t\taria-hidden\n\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t'relative flex h-8 w-8 items-center justify-center overflow-hidden rounded-full border transition',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t'bg-foreground text-background duration-1000':\n\t\t\t\t\t\t\t\toptimisticCompleted,\n\t\t\t\t\t\t\t'group-hover:bg-background duration-100': !optimisticCompleted,\n\t\t\t\t\t\t},\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{optimisticCompleted ? (\n\t\t\t\t\t\t'✓'\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"absolute -translate-y-10 opacity-25 transition group-hover:translate-y-0\">\n\t\t\t\t\t\t\t✓\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</motion.div>\n\t\t\t</motion.button>\n\t\t</progressFetcher.Form>\n\t)\n}\n","import {\n\textractNumbersAndTypeFromAppNameOrPath,\n\tgetExercises,\n\tgetPlaygroundAppName,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { clsx } from 'clsx'\nimport { motion, useAnimationControls } from 'framer-motion'\nimport * as React from 'react'\nimport {\n\tLink,\n\tNavLink,\n\tOutlet,\n\tuseLoaderData,\n\tuseParams,\n\tdata,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n} from 'react-router'\nimport { useHydrated } from 'remix-utils/use-hydrated'\nimport { Icon } from '#app/components/icons.tsx'\nimport { makeMediaQueryStore } from '#app/components/media-query.ts'\nimport { Logo } from '#app/components/product.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTrigger,\n} from '#app/components/ui/dialog.tsx'\nimport {\n\tSimpleTooltip,\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from '#app/components/ui/tooltip.tsx'\nimport { useOptionalUser, useUserHasAccess } from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { cn, getExercisePath, getExerciseStepPath } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport {\n\tgetProductHostEmoji,\n\tproductHostEmojis,\n\tusePresence,\n\ttype Location,\n\ttype User,\n} from '#app/utils/presence.tsx'\nimport {\n\tuseExerciseProgressClassName,\n\tuseNextExerciseRoute,\n\tuseProgressItemClassName,\n\ttype ProgressItemSearch,\n} from '../progress.tsx'\nimport { ThemeSwitch } from '../theme/index.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('appLayoutLoader')\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst [exercises, playgroundAppName] = await Promise.all([\n\t\tgetExercises({ request, timings }),\n\t\tgetPlaygroundAppName(),\n\t])\n\n\tconst playgroundNumbersAndType = extractNumbersAndTypeFromAppNameOrPath(\n\t\tplaygroundAppName ?? '',\n\t)\n\tconst playground = {\n\t\tappName: playgroundAppName,\n\t\texerciseNumber: Number(playgroundNumbersAndType?.exerciseNumber),\n\t\tstepNumber: Number(playgroundNumbersAndType?.stepNumber),\n\t\ttype: playgroundNumbersAndType?.type,\n\t}\n\n\tconst result = data(\n\t\t{\n\t\t\tworkshopTitle,\n\t\t\texercises: exercises.map((e) => ({\n\t\t\t\texerciseNumber: e.exerciseNumber,\n\t\t\t\ttitle: e.title,\n\t\t\t\tsolutions: e.solutions.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tproblems: e.problems.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tsteps: e.steps.map(({ stepNumber, problem, solution }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle: problem?.title ?? solution?.title ?? 'Unknown',\n\t\t\t\t\tname: problem?.name ?? solution?.name ?? 'Unknown',\n\t\t\t\t\tproblem: problem\n\t\t\t\t\t\t? { name: problem.name, title: problem.title }\n\t\t\t\t\t\t: null,\n\t\t\t\t\tsolution: solution\n\t\t\t\t\t\t? { name: solution.name, title: solution.title }\n\t\t\t\t\t\t: null,\n\t\t\t\t})),\n\t\t\t})),\n\t\t\tplayground,\n\t\t\tisMenuOpened:\n\t\t\t\trequest.headers.get('cookie')?.includes('es_menu_open=true') ?? false,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\tVary: 'Cookie',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n\treturn result\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\tVary: 'Cookie',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst opacities = ['opacity-70', 'opacity-80', 'opacity-90', 'opacity-100']\nconst shadows = [\n\t'shadow-[0_0_2px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_4px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_7px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_10px_0_rgba(0,0,0,0.3)]',\n]\nfunction getScoreClassNames(score: number) {\n\tconst opacityNumber = Math.round(score * opacities.length - 1)\n\tconst shadowNumber = Math.round(score * shadows.length - 1)\n\treturn cn(\n\t\t'shadow-purple-700 hover:opacity-100 focus:opacity-100 dark:shadow-purple-200',\n\t\topacities[opacityNumber] ?? 'opacity-60',\n\t\tshadows[shadowNumber] ?? 'shadow-none',\n\t\tscore === 1 ? 'animate-pulse hover:animate-none focus:animate-none' : null,\n\t)\n}\n\nfunction FacePile({ isMenuOpened }: { isMenuOpened: boolean }) {\n\tconst loggedInUser = useOptionalUser()\n\tconst { users } = usePresence()\n\tconst {\n\t\tproduct: { displayNameShort },\n\t} = useWorkshopConfig()\n\tconst limit = isMenuOpened ? 17 : 0\n\tconst numberOverLimit = users.length - limit\n\tconst shouldShowNumberOverLimit = numberOverLimit > (isMenuOpened ? 1 : 0)\n\n\tif (!users.length) return null\n\n\tconst tiffany =\n\t\tisMenuOpened && users.length === 1 ? (\n\t\t\t<Link\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tto=\"https://www.youtube.com/watch?v=w6Q3mHyzn78\"\n\t\t\t>\n\t\t\t\t<img\n\t\t\t\t\talt=\"Tiffany Tunes\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\tgetScoreClassNames(1),\n\t\t\t\t\t)}\n\t\t\t\t\tsrc=\"/img/tiffany.png\"\n\t\t\t\t/>\n\t\t\t</Link>\n\t\t) : null\n\tconst overLimitLabel = `${numberOverLimit}${\n\t\tisMenuOpened ? ' more ' : ' '\n\t}${displayNameShort} Dev${numberOverLimit === 1 ? '' : 's'} working now`\n\treturn (\n\t\t<div className=\"flex flex-wrap items-center gap-2\">\n\t\t\t<TooltipProvider>\n\t\t\t\t{(shouldShowNumberOverLimit ? users.slice(0, limit) : users).map(\n\t\t\t\t\t({ user, score }) => {\n\t\t\t\t\t\tconst scoreClassNames = getScoreClassNames(score)\n\t\t\t\t\t\tconst locations = getUserLocations(user)\n\t\t\t\t\t\tconst imageUrl = user.imageUrlSmall || user.avatarUrl\n\t\t\t\t\t\tconst hasAccess = user.hasAccess\n\t\t\t\t\t\tconst local = locations.some((loc) =>\n\t\t\t\t\t\t\tloc.origin?.includes('localhost'),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst productHostEmojis = getUniqueProductHostEmojis(locations)\n\t\t\t\t\t\tconst loggedInEmojis = getLoggedInProductEmojis(\n\t\t\t\t\t\t\tuser.loggedInProductHosts,\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\t// Handle opted-out users\n\t\t\t\t\t\tif (user.optOut) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Tooltip key={user.id}>\n\t\t\t\t\t\t\t\t\t<TooltipTrigger asChild tabIndex={0}>\n\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"relative\"\n\t\t\t\t\t\t\t\t\t\t\taria-label=\"Anonymous user (opted out)\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-muted flex h-8 w-8 items-center justify-center rounded-full border opacity-50',\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t\t\t<span className=\"flex flex-col items-center justify-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t{loggedInEmojis ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-xs\">{loggedInEmojis}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\tAnonymous (opted out of sharing)\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet doingLabel: string\n\t\t\t\t\t\tif (hasAccess) {\n\t\t\t\t\t\t\tdoingLabel = local ? 'working' : 'referencing'\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdoingLabel = local ? 'previewing' : 'reviewing'\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Tooltip key={user.id}>\n\t\t\t\t\t\t\t\t<TooltipTrigger asChild tabIndex={0}>\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tclassName=\"relative\"\n\t\t\t\t\t\t\t\t\t\taria-label={user.name || `${displayNameShort} Dev`}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{imageUrl ? (\n\t\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\t\talt={user.name || displayNameShort}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tsrc={imageUrl}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'flex h-8 w-8 items-center justify-center rounded-full border',\n\t\t\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t{productHostEmojis ? (\n\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"absolute -top-1 -left-1 text-xs leading-none\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Workshop products\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{productHostEmojis}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t\t<span className=\"flex flex-col items-center justify-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t\t\t\t\t\t\t{loggedInEmojis ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-xs\">{loggedInEmojis}</span>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t{user.name || `${displayNameShort} Dev`}\n\t\t\t\t\t\t\t\t\t\t\t{locations.length > 0\n\t\t\t\t\t\t\t\t\t\t\t\t? ` is ${doingLabel} ${\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tscore === 1 && loggedInUser?.id !== user.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'with you'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t\t\t\t\t\t\t} on`\n\t\t\t\t\t\t\t\t\t\t\t\t: null}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t{locations.map((loc, index) => {\n\t\t\t\t\t\t\t\t\t\t\tconst locationLabel = getLocationLabel(loc)\n\t\t\t\t\t\t\t\t\t\t\tif (!locationLabel) return null\n\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\t\tkey={`${loc.workshopTitle}-${index}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'flex flex-col items-center',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlocations.length > 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'border-border mt-1 border-t pt-1 first:mt-0 first:border-t-0 first:pt-0'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{locationLabel.line1 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{getProductHostEmoji(loc.productHost)}{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{locationLabel.line1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{locationLabel.line2 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{locationLabel.line2}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t)}\n\t\t\t\t{tiffany}\n\t\t\t\t{shouldShowNumberOverLimit ? (\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild tabIndex={0}>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\taria-label={overLimitLabel}\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'bg-accent text-accent-foreground flex items-center justify-center rounded-full border text-xs',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'h-8 w-8' : 'h-6 w-6',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t'pointer-events-none overflow-hidden text-center text-ellipsis whitespace-nowrap',\n\t\t\t\t\t\t\t\t\t\tisMenuOpened ? 'w-8' : 'w-6',\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? `+${numberOverLimit}` : numberOverLimit}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>{overLimitLabel}</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t) : null}\n\t\t\t</TooltipProvider>\n\t\t</div>\n\t)\n}\n\nfunction getLoggedInProductEmojis(\n\thosts: string[] | null | undefined,\n): string | null {\n\tif (!hosts || hosts.length === 0) return null\n\treturn hosts\n\t\t.map((host) => productHostEmojis[host])\n\t\t.filter(Boolean)\n\t\t.join(' ')\n}\n\nfunction getUserLocations(user: User): Location[] {\n\tif (user.locations && user.locations.length > 0) {\n\t\treturn user.locations.filter(Boolean) as Location[]\n\t}\n\tif (user.location) {\n\t\treturn [user.location]\n\t}\n\treturn []\n}\n\nfunction getUniqueProductHostEmojis(locations: Location[]): string | null {\n\tconst uniqueHosts = new Set<string>()\n\tfor (const loc of locations) {\n\t\tif (loc.productHost) {\n\t\t\tuniqueHosts.add(loc.productHost)\n\t\t}\n\t}\n\tif (uniqueHosts.size === 0) return null\n\treturn Array.from(uniqueHosts)\n\t\t.map((host) => getProductHostEmoji(host))\n\t\t.filter(Boolean)\n\t\t.join('')\n}\n\nconst useIsWide = makeMediaQueryStore('(min-width: 640px)', true)\n\nexport default function App() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst isWide = useIsWide()\n\tconst isHydrated = useHydrated()\n\n\tconst [isMenuOpened, setMenuOpenedState] = React.useState(data.isMenuOpened)\n\tuseRevalidationWS({ watchPaths: ['./exercises/README.mdx'] })\n\n\tfunction setMenuOpened(value: boolean) {\n\t\tsetMenuOpenedState(value)\n\t\tdocument.cookie = `es_menu_open=${value.toString()}; path=/; SameSite=Lax;`\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col\">\n\t\t\t{user ? null : <NoUserBanner />}\n\t\t\t{/*\n\t\t\t\tthis isn't placed in a conditional with isWide because the server render\n\t\t\t\tdoesn't know whether it should be around or not so we just use CSS to hide it\n\t\t\t\tif it's not supposed to show up.\n\n\t\t\t\tWe don't just use media queries for the wider screen nav because we want\n\t\t\t\tto avoid running all the logic in there unnecessarily.\n\t\t\t*/}\n\t\t\t{isHydrated && isWide ? null : (\n\t\t\t\t<MobileNavigation\n\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\tonMenuOpenChange={setMenuOpened}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\t// this nonsense is here because we want the panels to be scrollable rather\n\t\t\t\t// than having the entire page be scrollable (at least on wider screens)\n\t\t\t\tclassName={cn('flex grow flex-col sm:flex-row', {\n\t\t\t\t\t'h-[calc(100vh-128px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\t!user,\n\t\t\t\t\t'h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\tuser,\n\t\t\t\t\t'h-[unset]': !isWide && isMenuOpened,\n\t\t\t\t})}\n\t\t\t>\n\t\t\t\t{isWide ? (\n\t\t\t\t\t<Navigation\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tonMenuOpenChange={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-full w-full max-w-full sm:max-w-[calc(100%-56px)]',\n\t\t\t\t\t\tisMenuOpened ? 'hidden md:block' : '',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Outlet />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction getLocationLabel(location: User['location']) {\n\tif (!location) return null\n\n\tconst { exercise } = location\n\n\tconst exercisePortion = [\n\t\texercise\n\t\t\t? [exercise.exerciseNumber, exercise.stepNumber]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.map((s) => s.toString().padStart(2, '0'))\n\t\t\t\t\t.join('/')\n\t\t\t: null,\n\t\texercise?.type,\n\t]\n\t\t.filter(Boolean)\n\t\t.join(' - ')\n\treturn { line1: location.workshopTitle, line2: exercisePortion }\n}\n\nfunction NoUserBanner() {\n\tconst isWide = useIsWide()\n\tconst {\n\t\tproduct: { host, displayName },\n\t} = useWorkshopConfig()\n\tconst userHasAccess = useUserHasAccess()\n\tconst details = (\n\t\t<div>\n\t\t\t{ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t<div>\n\t\t\t\t\t{`This is the deployed version. `}\n\t\t\t\t\t<>\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tto={ENV.EPICSHOP_GITHUB_REPO}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tRun locally\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t{` for full experience.`}\n\t\t\t\t\t</>{' '}\n\t\t\t\t</div>\n\t\t\t) : userHasAccess ? (\n\t\t\t\t<div>\n\t\t\t\t\t<Link to=\"/login\" className=\"underline\">\n\t\t\t\t\t\tLogin\n\t\t\t\t\t</Link>{' '}\n\t\t\t\t\tor{' '}\n\t\t\t\t\t<a href={`https://${host}/login`} className=\"underline\">\n\t\t\t\t\t\tjoin for free\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\tfor the full experience.\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t)\n\treturn (\n\t\t<div className=\"z-10 flex h-16 items-center justify-between border-b bg-linear-to-tr from-blue-500 to-indigo-500 pl-4 text-white\">\n\t\t\t{isWide ? (\n\t\t\t\t<>\n\t\t\t\t\t<div className=\"hidden flex-1 flex-wrap items-center gap-4 sm:flex\">\n\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t<div className=\"flex flex-1 flex-wrap items-center\">\n\t\t\t\t\t\t\t<p className=\"mr-2\">\n\t\t\t\t\t\t\t\tWelcome to the{' '}\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{displayName}\n\t\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\t\tWorkshop app!\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t{details}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{userHasAccess ? null : (\n\t\t\t\t\t\t<div className=\"hidden h-full flex-col items-center sm:flex md:flex-row\">\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Join {displayName}</span>\n\t\t\t\t\t\t\t\t<span>↗︎</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={ENV.EPICSHOP_DEPLOYED ? `https://${host}/login` : '/login'}\n\t\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"User\" size=\"lg\" />\n\t\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Login</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<div className=\"flex flex-1 flex-wrap items-center gap-4 sm:hidden\">\n\t\t\t\t\t\t<a href={`https://${host}`}>\n\t\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<Dialog>\n\t\t\t\t\t\t\t<DialogTrigger>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" size=\"lg\" className=\"animate-pulse\" />\n\t\t\t\t\t\t\t</DialogTrigger>\n\t\t\t\t\t\t\t<DialogContent>\n\t\t\t\t\t\t\t\t<DialogHeader>\n\t\t\t\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t\t\t\t<span className=\"text-lg font-semibold\">{displayName}</span>\n\t\t\t\t\t\t\t\t</DialogHeader>\n\t\t\t\t\t\t\t\t<DialogDescription>\n\t\t\t\t\t\t\t\t\tWelcome to the{' '}\n\t\t\t\t\t\t\t\t\t<Link to={`https://${host}`} className=\"underline\">\n\t\t\t\t\t\t\t\t\t\t{displayName}\n\t\t\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\t\t\tWorkshop app!\n\t\t\t\t\t\t\t\t</DialogDescription>\n\t\t\t\t\t\t\t\t{details}\n\t\t\t\t\t\t\t</DialogContent>\n\t\t\t\t\t\t</Dialog>\n\t\t\t\t\t</div>\n\t\t\t\t\t{userHasAccess ? null : (\n\t\t\t\t\t\t<div className=\"flex h-full items-center\">\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Join</span>\n\t\t\t\t\t\t\t\t<span>↗︎</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={ENV.EPICSHOP_DEPLOYED ? `https://${host}/login` : '/login'}\n\t\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"User\" size=\"lg\" />\n\t\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Login</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n\nconst itemVariants = {\n\thidden: { opacity: 0, x: -20 },\n\tvisible: { opacity: 1, x: 0 },\n}\nfunction NavigationExerciseListItem({\n\texerciseNumber,\n\tchildren,\n}: {\n\texerciseNumber: number\n\tchildren: React.ReactNode\n}) {\n\tconst progressClassName = useExerciseProgressClassName(exerciseNumber)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"inline-block pl-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nfunction NavigationExerciseStepListItem({\n\tchildren,\n\t...progressItemSearch\n}: {\n\tchildren: React.ReactNode\n} & ProgressItemSearch) {\n\tconst progressClassName = useProgressItemClassName(progressItemSearch)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"inline-block pl-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nfunction MobileNavigation({\n\tisMenuOpened,\n\tonMenuOpenChange: setMenuOpened,\n}: {\n\tisMenuOpened: boolean\n\tonMenuOpenChange: (change: boolean) => void\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst nextExerciseRoute = useNextExerciseRoute()\n\tconst params = useParams()\n\tconst isOnline = useIsOnline()\n\tconst { users } = usePresence()\n\n\t// items\n\tconst listVariants = {\n\t\tvisible: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tduration: 0.05,\n\t\t\t\twhen: 'beforeChildren',\n\t\t\t\tstaggerChildren: 0.03,\n\t\t\t},\n\t\t},\n\t\thidden: {\n\t\t\topacity: 0,\n\t\t},\n\t}\n\n\treturn (\n\t\t<nav className=\"flex w-full border-b sm:hidden\">\n\t\t\t<div className=\"w-full\">\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn('flex items-center', {\n\t\t\t\t\t\t'flex-col': isMenuOpened,\n\t\t\t\t\t\t'h-14': !isMenuOpened,\n\t\t\t\t\t})}\n\t\t\t\t>\n\t\t\t\t\t<NavToggle\n\t\t\t\t\t\ttitle={data.workshopTitle}\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tsetMenuOpened={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t\t{isMenuOpened && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\tclassName=\"scrollbar-thin scrollbar-thumb-scrollbar flex w-full grow flex-col justify-between overflow-x-auto p-6\"\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\tto=\"/\"\n\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 text-2xl font-bold whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{data.exercises.map(({ exerciseNumber, title, steps }) => {\n\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber) === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst showPlayground =\n\t\t\t\t\t\t\t\t\t\t!isActive &&\n\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber === exerciseNumber\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<NavigationExerciseListItem\n\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1 text-2xl font-bold\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t{showPlayground ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.type,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t🛝\n\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"mt-2 ml-4 flex flex-col\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"instructions\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background relative px-2 py-0.5 pr-3 text-xl font-medium whitespace-nowrap outline-none after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!params.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntro\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{steps\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map(({ stepNumber, title, problem, solution }) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-0.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"leading-tight font-semibold\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{stepNumber.toString().padStart(2, '0')}.{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mt-0.5 ml-3 flex gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{problem && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'problem',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tProblem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{problem.name ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? ' 🛝'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{solution && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'solution',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSolution\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{solution.name ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? ' 🛝'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber, 'finished')}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background relative px-2 py-0.5 pr-3 text-base font-medium whitespace-nowrap outline-none after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background': isActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t📝 Elaboration\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t</NavigationExerciseListItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t<div className=\"mt-6\">\n\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\tto=\"/finished\"\n\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t'relative text-lg font-bold whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background bg-black text-white after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"]':\n\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t📝 Workshop Feedback\n\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div className=\"grow\" />\n\t\t\t\t\t{isOnline ? null : (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'You are offline'}>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex h-14 animate-pulse items-center justify-start p-4',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'w-full border-t' : 'border-l',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\tname=\"WifiNoConnection\"\n\t\t\t\t\t\t\t\t\tclassName=\"text-foreground-destructive\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? 'You are offline' : null}\n\t\t\t\t\t\t\t\t</Icon>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex items-center justify-start p-4',\n\t\t\t\t\t\t\tisMenuOpened && users.length > 4 ? 'min-h-14' : 'h-14',\n\t\t\t\t\t\t\tisMenuOpened ? 'w-full border-t' : 'border-l',\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<FacePile isMenuOpened={isMenuOpened} />\n\t\t\t\t\t</div>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user ? (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'Your account'}>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex h-14 shrink-0 items-center justify-start space-x-3 px-4 py-4 text-center no-underline hover:underline',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t'border-l': !isMenuOpened,\n\t\t\t\t\t\t\t\t\t\t'w-full border-t': isMenuOpened,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tto=\"/account\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{user.imageUrlSmall ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\talt={user.name ?? user.email}\n\t\t\t\t\t\t\t\t\t\tsrc={user.imageUrlSmall}\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-full rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Icon name=\"User\" className=\"shrink-0\" size=\"lg\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tYour Account\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Your account</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user && nextExerciseRoute ? (\n\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\tcontent={isMenuOpened ? null : 'Continue to next lesson'}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={nextExerciseRoute}\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex h-14 w-full items-center space-x-3 border-l px-4 py-4 pl-[18px] no-underline hover:underline',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstate={{ from: 'continue next lesson button' }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"FastForward\" className=\"shrink-0\" size=\"md\" />\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tContinue to next lesson\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Continue to next lesson</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex h-14 w-14 items-center justify-center self-start p-4 sm:mb-4 sm:w-full',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t'w-full border-t': isMenuOpened,\n\t\t\t\t\t\t\t\t'border-l': !isMenuOpened,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ThemeSwitch />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</nav>\n\t)\n}\n\nconst OPENED_MENU_WIDTH = 400\n\nfunction Navigation({\n\tisMenuOpened,\n\tonMenuOpenChange: setMenuOpened,\n}: {\n\tisMenuOpened: boolean\n\tonMenuOpenChange: (change: boolean) => void\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst nextExerciseRoute = useNextExerciseRoute()\n\tconst params = useParams()\n\tconst isOnline = useIsOnline()\n\tconst { users } = usePresence()\n\n\tconst exercise = data.exercises.find(\n\t\t(e) => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tconst app =\n\t\tparams.type === 'solution'\n\t\t\t? exercise?.solutions.find(\n\t\t\t\t\t(s) => s.stepNumber === Number(params.stepNumber),\n\t\t\t\t)\n\t\t\t: params.type === 'problem'\n\t\t\t\t? exercise?.problems.find(\n\t\t\t\t\t\t(p) => p.stepNumber === Number(params.stepNumber),\n\t\t\t\t\t)\n\t\t\t\t: null\n\n\t// container\n\tconst menuControls = useAnimationControls()\n\tconst menuVariants = {\n\t\tclose: { width: 56 },\n\t\topen: { width: OPENED_MENU_WIDTH },\n\t}\n\n\t// items\n\tconst listVariants = {\n\t\tvisible: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tduration: 0.05,\n\t\t\t\twhen: 'beforeChildren',\n\t\t\t\tstaggerChildren: 0.03,\n\t\t\t},\n\t\t},\n\t\thidden: {\n\t\t\topacity: 0,\n\t\t},\n\t}\n\n\treturn (\n\t\t<nav className=\"hidden border-r sm:flex\">\n\t\t\t<motion.div\n\t\t\t\tinitial={isMenuOpened ? 'open' : 'close'}\n\t\t\t\tvariants={menuVariants}\n\t\t\t\tanimate={menuControls}\n\t\t\t>\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t\t<NavToggle\n\t\t\t\t\t\ttitle={data.workshopTitle}\n\t\t\t\t\t\tmenuControls={menuControls}\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tsetMenuOpened={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t\t{isMenuOpened && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\tstyle={{ width: OPENED_MENU_WIDTH }}\n\t\t\t\t\t\t\tclassName=\"scrollbar-thin scrollbar-thumb-scrollbar flex grow flex-col justify-between overflow-y-auto p-6\"\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\tto=\"/\"\n\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 text-2xl font-bold whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{data.exercises.map(({ exerciseNumber, title, steps }) => {\n\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber) === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst showPlayground =\n\t\t\t\t\t\t\t\t\t\t!isActive &&\n\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber === exerciseNumber\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<NavigationExerciseListItem\n\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1 text-2xl font-bold\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t{showPlayground ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.type,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t🛝\n\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"mt-2 ml-4 flex flex-col\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"instructions\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background relative px-2 py-0.5 pr-3 text-xl font-medium whitespace-nowrap outline-none after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!params.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntro\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{steps\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map(({ stepNumber, title, problem, solution }) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-0.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"leading-tight font-semibold\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{stepNumber.toString().padStart(2, '0')}.{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mt-0.5 ml-3 flex gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{problem && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'problem',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tProblem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{problem.name ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? ' 🛝'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{solution && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'solution',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSolution\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{solution.name ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? ' 🛝'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber, 'finished')}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background relative px-2 py-0.5 pr-3 text-base font-medium whitespace-nowrap outline-none after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background': isActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t📝 Elaboration\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t</NavigationExerciseListItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t<div className=\"mt-6\">\n\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\tto=\"/finished\"\n\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t'relative text-lg font-bold whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background bg-black text-white after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"]':\n\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t📝 Workshop Feedback\n\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t)}\n\t\t\t\t\t{!isMenuOpened && (\n\t\t\t\t\t\t<div className=\"flex grow flex-col justify-center\">\n\t\t\t\t\t\t\t<div className=\"orientation-sideways w-full font-mono text-sm leading-none font-medium uppercase\">\n\t\t\t\t\t\t\t\t{exercise?.title ? (\n\t\t\t\t\t\t\t\t\t<Link to={getExercisePath(Number(params.exerciseNumber))}>\n\t\t\t\t\t\t\t\t\t\t{exercise.title}\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{exercise?.title && app?.title ? ' — ' : null}\n\t\t\t\t\t\t\t\t{app?.title ? (\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber),\n\t\t\t\t\t\t\t\t\t\t\tapp.stepNumber,\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{app.title}\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{isOnline ? null : (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'You are offline'}>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex w-full animate-pulse items-center border-t p-4',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'justify-start' : 'justify-center',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\tname=\"WifiNoConnection\"\n\t\t\t\t\t\t\t\t\tclassName=\"text-foreground-destructive\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"whitespace-nowrap\">You are offline</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</Icon>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex w-full items-center justify-start border-t p-4 transition-[height]',\n\t\t\t\t\t\t\tisMenuOpened && users.length > 4 ? 'h-28' : 'h-14',\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstyle={isMenuOpened ? { width: OPENED_MENU_WIDTH } : {}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<FacePile isMenuOpened={isMenuOpened} />\n\t\t\t\t\t</div>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user ? (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'Your account'}>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName=\"flex h-14 w-full shrink-0 items-center justify-start space-x-3 border-t px-4 py-4 text-center no-underline hover:underline\"\n\t\t\t\t\t\t\t\tto=\"/account\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{user.imageUrlSmall ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\talt={user.name ?? user.email}\n\t\t\t\t\t\t\t\t\t\tsrc={user.imageUrlSmall}\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-full rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Icon name=\"User\" className=\"shrink-0\" size=\"lg\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tYour Account\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Your account</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user && nextExerciseRoute ? (\n\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\tcontent={isMenuOpened ? null : 'Continue to next lesson'}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={nextExerciseRoute}\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex h-14 w-full items-center space-x-3 border-t px-4 py-4 pl-[18px] no-underline hover:underline',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstate={{ from: 'continue next lesson button' }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"FastForward\" className=\"shrink-0\" size=\"md\" />\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tContinue to next lesson\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Continue to next lesson</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"mb-4 w-full self-start border-t pt-[15px] pl-3\">\n\t\t\t\t\t\t<ThemeSwitch />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</motion.div>\n\t\t</nav>\n\t)\n}\n\nfunction NavToggle({\n\ttitle,\n\tisMenuOpened,\n\tsetMenuOpened,\n\tmenuControls,\n}: {\n\ttitle: string\n\tisMenuOpened: boolean\n\tsetMenuOpened: (value: boolean) => void\n\tmenuControls?: ReturnType<typeof useAnimationControls>\n}) {\n\tconst initialOpenRef = React.useRef(isMenuOpened)\n\tconst menuButtonRef = React.useRef<HTMLButtonElement>(null)\n\tconst path01Variants = {\n\t\topen: { d: 'M3.06061 2.99999L21.0606 21' },\n\t\tclosed: { d: 'M0 9.5L24 9.5' },\n\t}\n\tconst path02Variants = {\n\t\topen: { d: 'M3.00006 21.0607L21 3.06064' },\n\t\tmoving: { d: 'M0 14.5L24 14.5' },\n\t\tclosed: { d: 'M0 14.5L15 14.5' },\n\t}\n\tconst path01Controls = useAnimationControls()\n\tconst path02Controls = useAnimationControls()\n\n\tasync function toggleMenu() {\n\t\tvoid menuControls?.start(isMenuOpened ? 'close' : 'open')\n\t\tsetMenuOpened(!isMenuOpened)\n\t\tif (isMenuOpened) {\n\t\t\tvoid path01Controls.start(path01Variants.closed)\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path02Controls.start(path02Variants.closed)\n\t\t} else {\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path01Controls.start(path01Variants.open)\n\t\t\tvoid path02Controls.start(path02Variants.open)\n\t\t}\n\t}\n\n\tReact.useEffect(() => {\n\t\tif (!isMenuOpened) return\n\n\t\tfunction handleKeyUp(event: KeyboardEvent) {\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\tmenuButtonRef.current?.click()\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('keyup', handleKeyUp)\n\t\treturn () => document.removeEventListener('keyup', handleKeyUp)\n\t}, [isMenuOpened])\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'relative inline-flex h-14 shrink-0 items-center justify-between overflow-hidden border-r sm:w-full sm:border-r-0 sm:border-b',\n\t\t\t\t{\n\t\t\t\t\t'w-full': isMenuOpened,\n\t\t\t\t},\n\t\t\t)}\n\t\t>\n\t\t\t<button\n\t\t\t\tref={menuButtonRef}\n\t\t\t\tclassName=\"flex h-14 w-14 items-center justify-center\"\n\t\t\t\taria-label=\"Open Navigation menu\"\n\t\t\t\tonClick={toggleMenu}\n\t\t\t>\n\t\t\t\t<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path01Variants[initialOpenRef.current ? 'open' : 'closed']}\n\t\t\t\t\t\tanimate={path01Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path02Variants[initialOpenRef.current ? 'open' : 'closed']}\n\t\t\t\t\t\tanimate={path02Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t</button>\n\t\t\t{isMenuOpened && (\n\t\t\t\t<motion.p\n\t\t\t\t\ttransition={{ delay: 0.2 }}\n\t\t\t\t\tinitial={{ opacity: 0, y: 5 }}\n\t\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\t\tclassName=\"absolute right-5 font-mono text-sm whitespace-nowrap uppercase\"\n\t\t\t\t>\n\t\t\t\t\t<Link to=\"/\">{title}</Link>\n\t\t\t\t</motion.p>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n","import { clsx } from 'clsx'\nimport { Link } from 'react-router'\nimport { cn } from '#app/utils/misc.tsx'\n\nfunction PendingState() {\n\treturn <span className=\"inline-block animate-spin\">🌀</span>\n}\n\nfunction SuccessState() {\n\treturn <span>✅</span>\n}\n\nfunction ErrorState() {\n\treturn <span>❌</span>\n}\n\nexport function getButtonClassName({\n\tvarient,\n\tclip = true,\n}: {\n\tvarient: 'primary' | 'big' | 'mono'\n\tclip?: boolean\n}) {\n\tconst baseClassName =\n\t\t'inline-flex bg-foreground text-background outline-none hover:bg-background hover:text-foreground focus:bg-background focus:text-foreground'\n\tconst primaryClassName = 'px-8 py-4 font-bold'\n\tconst bigClassName = 'px-8 py-4 text-xl font-bold'\n\tconst monoClassName = 'px-8 py-4 font-mono text-sm uppercase'\n\tconst className = clsx(baseClassName, {\n\t\t'clip-path-button': clip,\n\t\t[primaryClassName]: varient === 'primary',\n\t\t[bigClassName]: varient === 'big',\n\t\t[monoClassName]: varient === 'mono',\n\t})\n\treturn className\n}\n\nexport function Button({\n\tvarient,\n\tstatus = 'idle',\n\t...props\n}: React.ComponentPropsWithoutRef<'button'> &\n\tParameters<typeof getButtonClassName>[0] & {\n\t\tstatus?: 'pending' | 'success' | 'error' | 'idle'\n\t}) {\n\tconst companion = {\n\t\tpending: <PendingState />,\n\t\tsuccess: <SuccessState />,\n\t\terror: <ErrorState />,\n\t\tidle: null,\n\t}[status]\n\treturn (\n\t\t<div className=\"clip-path-button-outer border-foreground bg-foreground w-fit border-2\">\n\t\t\t<button\n\t\t\t\t{...props}\n\t\t\t\tclassName={clsx(\n\t\t\t\t\tprops.className,\n\t\t\t\t\tgetButtonClassName({ varient }),\n\t\t\t\t\t'flex justify-center gap-4',\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<div>{props.children}</div>\n\t\t\t\t{companion}\n\t\t\t</button>\n\t\t</div>\n\t)\n}\n\nexport function ButtonLink({\n\tvarient,\n\t...props\n}: React.ComponentPropsWithoutRef<typeof Link> &\n\tParameters<typeof getButtonClassName>[0]) {\n\treturn (\n\t\t<div className=\"clip-path-button-outer border-foreground bg-foreground w-fit border-2\">\n\t\t\t<Link\n\t\t\t\t{...props}\n\t\t\t\tclassName={clsx(props.className, getButtonClassName({ varient }))}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\nexport function LinkButton({\n\tclassName,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'>) {\n\treturn <button {...props} className={clsx('underline', className)} />\n}\n\nexport const iconButtonClassName = `inline-flex h-8 w-8 items-center justify-center rounded border focus:outline-none focus:ring-2 focus:ring-ring`\nexport function IconButton({\n\tchildren,\n\tclassName = '',\n\t...props\n}: React.ComponentPropsWithoutRef<'button'>) {\n\treturn (\n\t\t<button {...props} className={cn(iconButtonClassName, className)}>\n\t\t\t{children}\n\t\t</button>\n\t)\n}\n","import { deleteCache } from '@epic-web/workshop-utils/cache.server'\nimport {\n\tlogout,\n\trequireAuthInfo,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { redirect, type LoaderFunctionArgs, Form, Link } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport {\n\tuseOptionalDiscordMember,\n\tuseUser,\n\tuseUserHasAccess,\n} from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { cn, ensureUndeployed } from '#app/utils/misc.tsx'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tawait requireAuthInfo({ request })\n\treturn {}\n}\n\nexport async function action({ request }: { request: Request }) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tif (intent === 'logout') {\n\t\tawait logout()\n\t\tawait deleteCache()\n\t\treturn redirectWithToast('/login', {\n\t\t\ttype: 'success',\n\t\t\ttitle: 'Logged out',\n\t\t\tdescription: 'Goodbye! Come back soon!',\n\t\t})\n\t} else if (intent === 'presence-opt-out') {\n\t\tconst optOut = formData.get('optOut') === 'true'\n\t\tawait setPreferences({ presence: { optOut } })\n\t\treturn redirectWithToast('/account', {\n\t\t\ttitle: optOut ? 'Opted out' : 'Opted in',\n\t\t\tdescription: `You are now ${optOut ? 'invisible' : 'visible'}.`,\n\t\t\ttype: 'success',\n\t\t})\n\t}\n\n\treturn redirect('/account')\n}\n\nfunction useConnectDiscordURL() {\n\tconst {\n\t\tproduct: { host },\n\t} = useWorkshopConfig()\n\treturn `https://${host}/discord`\n}\n\nexport default function Account() {\n\tconst user = useUser()\n\tconst config = useWorkshopConfig()\n\tconst discordMember = useOptionalDiscordMember()\n\tconst connectDiscordURL = useConnectDiscordURL()\n\tconst userHasAccess = useUserHasAccess()\n\n\treturn (\n\t\t<main className=\"container flex h-full w-full max-w-3xl grow flex-col items-center justify-center gap-4\">\n\t\t\t{user.imageUrlLarge ? (\n\t\t\t\t<img\n\t\t\t\t\tclassName=\"h-36 w-36 rounded-full\"\n\t\t\t\t\talt={discordMember?.displayName ?? user.name ?? user.email}\n\t\t\t\t\tsrc={user.imageUrlLarge}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<Icon name=\"User\" className=\"shrink-0\" size=\"lg\" />\n\t\t\t)}\n\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<h1 className=\"mb-1 text-2xl\">Your Account</h1>\n\t\t\t\t{config.product.slug ? (\n\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\tcontent={\n\t\t\t\t\t\t\tuserHasAccess\n\t\t\t\t\t\t\t\t? 'You have access to this workshop'\n\t\t\t\t\t\t\t\t: 'You do not have full access to this workshop'\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\tname={userHasAccess ? 'Success' : 'Error'}\n\t\t\t\t\t\t\tsize=\"lg\"\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\tuserHasAccess\n\t\t\t\t\t\t\t\t\t? 'bg-success text-success-foreground'\n\t\t\t\t\t\t\t\t\t: 'bg-warning text-warning-foreground',\n\t\t\t\t\t\t\t\t'rounded-full p-1',\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t) : null}\n\t\t\t</div>\n\n\t\t\t{!userHasAccess && config.product.slug ? (\n\t\t\t\t<div className=\"prose\">\n\t\t\t\t\t<callout-warning className=\"notification\">\n\t\t\t\t\t\tPlease{' '}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={`https://${config.product.host}/workshops/${config.product.slug}`}\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tupgrade\n\t\t\t\t\t\t</a>{' '}\n\t\t\t\t\t\tyour account to get full access to this workshop.\n\t\t\t\t\t</callout-warning>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<p className=\"text-center text-gray-700 dark:text-gray-300\">\n\t\t\t\t{user.name\n\t\t\t\t\t? `Hi ${\n\t\t\t\t\t\t\tdiscordMember?.displayName ?? user.name\n\t\t\t\t\t\t}, your device is logged in with ${user.email}.`\n\t\t\t\t\t: `Your device is logged in with ${user.email}.`}\n\t\t\t</p>\n\t\t\t{discordMember ? (\n\t\t\t\t<>\n\t\t\t\t\t<p className=\"text-center text-gray-700 dark:text-gray-300\">\n\t\t\t\t\t\tAnd you are connected to discord as{' '}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={`https://discord.com/users/${discordMember.id}`}\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{discordMember.displayName}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t.\n\t\t\t\t\t</p>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<Link\n\t\t\t\t\t\tto={connectDiscordURL}\n\t\t\t\t\t\tclassName=\"inline-flex items-center gap-2 underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Discord\" size=\"lg\" />\n\t\t\t\t\t\tConnect Discord\n\t\t\t\t\t</Link>\n\t\t\t\t\t<SimpleTooltip content=\"This will give you access to the exclusive Discord channels for Epic Web\">\n\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<Form method=\"post\">\n\t\t\t\t\t<Button varient=\"mono\" name=\"intent\" value=\"logout\">\n\t\t\t\t\t\tLog device out\n\t\t\t\t\t</Button>\n\t\t\t\t</Form>\n\t\t\t\t<SimpleTooltip\n\t\t\t\t\tcontent={\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\tNote: it is your <i className=\"italic\">device</i> that's logged\n\t\t\t\t\t\t\tin, not your browser.\n\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\tSo all browsers on this device will be logged in with the same\n\t\t\t\t\t\t\taccount on this device.\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t</SimpleTooltip>\n\t\t\t</div>\n\t\t\t<hr className=\"w-full\" />\n\t\t\t<ul className=\"flex list-inside list-disc flex-col gap-2 self-start\">\n\t\t\t\t<li>\n\t\t\t\t\t<Link\n\t\t\t\t\t\tto={`https://${config.product.host}/profile`}\n\t\t\t\t\t\tclassName=\"inline-flex gap-1 underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<span>Manage your account</span>\n\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t</Link>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<Link to=\"/preferences\" className=\"underline\">\n\t\t\t\t\t\tManage your preferences\n\t\t\t\t\t</Link>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<Link to=\"/support\" className=\"underline\">\n\t\t\t\t\t\tGet support\n\t\t\t\t\t</Link>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</main>\n\t)\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { type CacheEntry } from '@epic-web/cachified'\nimport { getAppFromFile } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcachified,\n\tcompiledCodeCache,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getDirModifiedTime } from '@epic-web/workshop-utils/modified-time.server'\nimport { type Timings } from '@epic-web/workshop-utils/timing.server'\nimport * as esbuild from 'esbuild'\n\nasync function getForceFresh(\n\tfilePath: string,\n\tcacheEntry:\n\t\t| CacheEntry\n\t\t| null\n\t\t| undefined\n\t\t| Promise<CacheEntry | null | undefined>,\n) {\n\tcacheEntry = await cacheEntry\n\tif (!cacheEntry) return true\n\tconst app = await getAppFromFile(filePath)\n\tif (!app) return true\n\tconst appModified = await getDirModifiedTime(app.fullPath)\n\tconst cacheModified = cacheEntry.metadata.createdTime\n\treturn !cacheModified || appModified > cacheModified || undefined\n}\n\nexport async function compileTs(\n\tfilePath: string,\n\tfullPath: string,\n\t{\n\t\tesbuildOptions,\n\t\tforceFresh,\n\t\trequest,\n\t\ttimings,\n\t}: {\n\t\tforceFresh?: boolean\n\t\trequest?: Request\n\t\ttimings?: Timings\n\t\tesbuildOptions?: esbuild.BuildOptions\n\t} = {},\n) {\n\tconst key = `${filePath}::${fullPath}`\n\treturn cachified({\n\t\tkey,\n\t\trequest,\n\t\ttimings,\n\t\tforceFresh:\n\t\t\tforceFresh ||\n\t\t\t(await getForceFresh(filePath, compiledCodeCache.get(key))) ||\n\t\t\t(await getForceFresh(fullPath, compiledCodeCache.get(key))),\n\t\tcache: compiledCodeCache,\n\t\tgetFreshValue: async () => {\n\t\t\tconst result = await esbuild.build({\n\t\t\t\tstdin: {\n\t\t\t\t\tcontents: await fs.promises.readFile(filePath, 'utf-8'),\n\t\t\t\t\t// NOTE: if the fileAppName is specified, then we're resolving to a different\n\t\t\t\t\t// app than the one we're serving the file from. We do this so the tests\n\t\t\t\t\t// can live in the solution directory, but be run against the problem\n\t\t\t\t\tresolveDir: fullPath,\n\t\t\t\t\tsourcefile: path.basename(filePath),\n\t\t\t\t\tloader: 'tsx',\n\t\t\t\t},\n\t\t\t\tdefine: {\n\t\t\t\t\t'process.env': JSON.stringify({ NODE_ENV: 'development' }),\n\t\t\t\t},\n\t\t\t\tbundle: true,\n\t\t\t\twrite: false,\n\t\t\t\tformat: 'esm',\n\t\t\t\tplatform: 'browser',\n\t\t\t\tjsx: 'automatic',\n\t\t\t\tminify: false,\n\t\t\t\tsourcemap: 'inline',\n\t\t\t\t...esbuildOptions,\n\t\t\t})\n\t\t\treturn result\n\t\t},\n\t})\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport {\n\tgetAppByName,\n\tgetApps,\n\tisPlaygroundApp,\n\tisProblemApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { type Timings } from '@epic-web/workshop-utils/timing.server'\nimport fsExtra from 'fs-extra'\nimport { type Params } from 'react-router'\n\nfunction parseAppNameFromReferer(request: Request) {\n\ttry {\n\t\tconst url = new URL(request.headers.get('referer') ?? '')\n\t\tconst appName = url.pathname.split('/').pop()\n\t\treturn appName ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nexport async function resolveApps({\n\trequest,\n\tparams,\n\ttimings,\n}: {\n\trequest: Request\n\tparams: Params\n\ttimings: Timings\n}) {\n\tconst appName = params.appName ?? parseAppNameFromReferer(request)\n\n\tinvariantResponse(appName, 'appName param required')\n\tconst app = await getAppByName(appName, { request, timings })\n\n\tlet fileAppName: string | null = app?.name ?? null\n\tif (isProblemApp(app)) {\n\t\tfileAppName = isProblemApp(app) ? app.solutionName : null\n\t}\n\tif (isPlaygroundApp(app)) {\n\t\tconst appBasis = await getAppByName(app.appName)\n\t\tfileAppName = isProblemApp(appBasis) ? appBasis.solutionName : null\n\t}\n\tif (fileAppName) {\n\t\tconst apps = await getApps({ request, timings })\n\t\tconst fileApp = fileAppName\n\t\t\t? apps.find((app) => app.name === fileAppName)\n\t\t\t: app\n\t\treturn { app, fileApp }\n\t} else {\n\t\treturn { app, fileApp: app }\n\t}\n}\n\nfunction unique<ItemType>(\n\tvalue: ItemType,\n\tindex: number,\n\tself: Array<ItemType>,\n) {\n\treturn self.indexOf(value) === index\n}\n\nexport async function firstExisting(...files: Array<string>) {\n\tfor (const file of files.filter(unique)) {\n\t\tif (await fsExtra.pathExists(file)) {\n\t\t\treturn file\n\t\t}\n\t}\n\treturn null\n}\n","import path from 'path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport etag from 'etag'\nimport fsExtra from 'fs-extra'\nimport mimeTypes from 'mime-types'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\nimport { compileTs } from '#app/utils/compile-app.server.ts'\nimport {\n\tcombineHeaders,\n\tensureUndeployed,\n\tgetBaseUrl,\n} from '#app/utils/misc.tsx'\nimport { firstExisting, resolveApps } from './__utils.ts'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('app-file')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.dev.type === 'script') {\n\t\treturn redirect(getBaseUrl({ request, port: app.dev.portNumber }))\n\t}\n\tconst splat = params['*']\n\tinvariantResponse(splat, 'splat required')\n\n\tconst filePath = await firstExisting(\n\t\tpath.join(app.fullPath, splat),\n\t\tpath.join(fileApp.fullPath, splat),\n\t)\n\tif (!filePath) {\n\t\tthrow new Response('File not found', { status: 404 })\n\t}\n\tif (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {\n\t\t// compile ts/tsx files\n\t\tconst { outputFiles, errors } = await compileTs(filePath, app.fullPath, {\n\t\t\trequest,\n\t\t\ttimings,\n\t\t})\n\t\tif (errors.length) {\n\t\t\tconsole.error(`Failed to compile file \"${filePath}\"`)\n\t\t\tconsole.error(errors)\n\t\t\tthrow new Response(errors.join('\\n'), { status: 500 })\n\t\t}\n\t\tif (!outputFiles?.[0]) {\n\t\t\tthrow new Response('Failed to compile file', { status: 500 })\n\t\t}\n\t\tconst file = outputFiles[0].text\n\t\treturn getFileResponse(file, { 'Content-Type': 'text/javascript' })\n\t} else {\n\t\tconst file = await fsExtra.readFile(filePath)\n\t\tconst mimeType = mimeTypes.lookup(filePath) || 'text/plain'\n\t\treturn getFileResponse(file, { 'Content-Type': mimeType })\n\t}\n\n\tfunction getFileResponse(file: Buffer | string, headers: HeadersInit = {}) {\n\t\tconst etagValue = etag(file)\n\t\tconst ifNoneMatch = request.headers.get('if-none-match')\n\t\tif (ifNoneMatch === etagValue) {\n\t\t\treturn new Response(null, { status: 304 })\n\t\t}\n\t\t// @ts-ignore 🤷‍♂️ CLI doesn't like this but editor is fine 🙃\n\t\treturn new Response(file, {\n\t\t\theaders: combineHeaders(\n\t\t\t\t{\n\t\t\t\t\t'Content-Length': Buffer.byteLength(file).toString(),\n\t\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t\t\tETag: etagValue,\n\t\t\t\t},\n\t\t\t\theaders,\n\t\t\t),\n\t\t})\n\t}\n}\n","import path from 'node:path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport fsExtra from 'fs-extra'\nimport {\n\tredirect,\n\ttype ActionFunctionArgs,\n\ttype LoaderFunctionArgs,\n} from 'react-router'\nimport { z } from 'zod'\nimport { compileTs } from '#app/utils/compile-app.server.ts'\nimport { ensureUndeployed, getBaseUrl } from '#app/utils/misc.tsx'\nimport { resolveApps } from './__utils'\n\nexport async function loader(args: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst api = await getApiModule(args)\n\tinvariantResponse(\n\t\tapi.mod.loader,\n\t\t'Attempted to make a GET request to the api endpoint but the api module does not export a loader function',\n\t\t{ status: 405 },\n\t)\n\ttry {\n\t\tconst result = await api.mod.loader(args)\n\t\treturn result\n\t} catch (error) {\n\t\tapi.cleanupError(error)\n\t}\n}\n\nexport async function action(args: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst api = await getApiModule(args)\n\tinvariantResponse(\n\t\tapi.mod.action,\n\t\t'Attempted to make a non-GET request to the api endpoint but the api module does not export an action function',\n\t\t{ status: 405 },\n\t)\n\ttry {\n\t\tconst result = await api.mod.action(args)\n\t\treturn result\n\t} catch (error) {\n\t\tapi.cleanupError(error)\n\t}\n}\n\nconst ApiModuleSchema = z.object({\n\tloader: z.function().optional(),\n\taction: z.function().optional(),\n})\n\nasync function getApiModule({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('app-api')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.dev.type === 'script') {\n\t\tthrow redirect(getBaseUrl({ request, port: app.dev.portNumber }))\n\t}\n\n\tconst apiFiles = (await fsExtra.readdir(app.fullPath))\n\t\t.filter((file: string) => /^api\\.server\\.(ts|tsx|js|jsx)$/.test(file))\n\t\t.map((f) => path.join(app.fullPath, f))\n\tconst apiFile = apiFiles[0]\n\tif (!apiFile) {\n\t\tthrow new Response(\n\t\t\t`No api.server.(ts|tsx|js|jsx) file found in \"${app.fullPath}\"`,\n\t\t\t{ status: 404 },\n\t\t)\n\t}\n\tif (apiFiles.length > 1) {\n\t\tthrow new Response(\n\t\t\t`Only one api.server.(ts|tsx|js|jsx) file is allowed, found ${apiFiles.join(', ')}`,\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\n\tconst { outputFiles, errors } = await compileTs(apiFile, app.fullPath, {\n\t\tesbuildOptions: {\n\t\t\tplatform: 'node',\n\t\t\t// packages external causes issues in Node 20 because Node tries to resolve the package.json from the data URL 🤷‍♂️\n\t\t\t// packages: 'external', // figure out how to turn this on in the future...\n\t\t\t// just adds noise to errors and doesn't appear to help with debugging\n\t\t\tsourcemap: false,\n\t\t\t// remove the process.env define\n\t\t\tdefine: {},\n\t\t},\n\t\trequest,\n\t\ttimings,\n\t})\n\tif (errors.length) {\n\t\tconsole.error(`Failed to compile file \"${apiFile}\"`)\n\t\tconsole.error(errors)\n\t\tthrow new Response(errors.join('\\n'), { status: 500 })\n\t}\n\tif (!outputFiles?.[0]) {\n\t\tthrow new Response(`Failed to compile file \"${apiFile}\"`, { status: 500 })\n\t}\n\tconst apiCode = outputFiles[0].text\n\tconst dataUrl = `data:text/javascript;base64,${Buffer.from(apiCode).toString('base64')}`\n\tconst mod = await import(/* @vite-ignore */ dataUrl).catch(cleanupError)\n\tconst apiModule = ApiModuleSchema.safeParse(mod)\n\tif (!apiModule.success) {\n\t\tthrow new Response(\n\t\t\t`Invalid api module. It should export a loader and/or action: ${apiModule.error.message}`,\n\t\t\t{ status: 500 },\n\t\t)\n\t}\n\treturn {\n\t\tmod: apiModule.data,\n\t\tcleanupError,\n\t}\n\n\tfunction cleanupError(error: unknown) {\n\t\tif (apiFile && error instanceof Error && error.stack) {\n\t\t\terror.stack = error.stack.replace(dataUrl, apiFile)\n\t\t}\n\t\tthrow error\n\t}\n}\n","import { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\nimport { ensureUndeployed, getBaseUrl } from '#app/utils/misc.tsx'\nimport { resolveApps } from './__utils.ts'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('epic_ws script')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.dev.type === 'script') {\n\t\treturn redirect(getBaseUrl({ request, port: app.dev.portNumber }))\n\t}\n\tconst relevantPaths = Array.from(new Set([app.fullPath, fileApp.fullPath]))\n\tconst watchParams = new URLSearchParams()\n\tfor (const path of relevantPaths) {\n\t\twatchParams.append('watch', path)\n\t}\n\n\tconst js = /* javascript */ `\n\tfunction epicLiveReloadConnect(config) {\n\t\tconst protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n\t\tconst host = location.hostname;\n\t\tconst port = location.port;\n\t\tconst socketPath = protocol + \"//\" + host + \":\" + port + \"/__ws?\" + ${JSON.stringify(watchParams.toString())};\n\t\tconst ws = new WebSocket(socketPath);\n\t\tws.onmessage = (message) => {\n\t\t\tconst event = JSON.parse(message.data);\n\t\t\tif (event.type !== 'epicshop:file-change') return;\n\t\t\tconst { filePaths } = event.data;\n\t\t\tconsole.log(\n\t\t\t\t['🐨 Reloading', window.frameElement?.getAttribute('title'), 'due to file changes:']\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(' '),\n\t\t\t\tfilePaths\n\t\t\t);\n\t\t\twindow.location.reload();\n\t\t};\n\t\tws.onopen = () => {\n\t\t\tif (config && typeof config.onOpen === \"function\") {\n\t\t\t\tconfig.onOpen();\n\t\t\t}\n\t\t};\n\t\tws.onclose = (event) => {\n\t\t\tif (event.code === 1006) {\n\t\t\t\tconsole.log(\"EpicShop dev server web socket closed. Reconnecting...\");\n\t\t\t\tsetTimeout(\n\t\t\t\t\t() =>\n\t\t\t\t\t\tepicLiveReloadConnect({\n\t\t\t\t\t\t\tonOpen: () => window.location.reload(),\n\t\t\t\t\t\t}),\n\t\t\t\t\t1000\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\t\tws.onerror = (error) => {\n\t\t\tconsole.log(\"EpicShop dev server web socket error:\");\n\t\t\tconsole.error(error);\n\t\t};\n\t}\n\tepicLiveReloadConnect();\n\t`\n\treturn new Response(js, {\n\t\theaders: {\n\t\t\t'Content-Length': Buffer.byteLength(js).toString(),\n\t\t\t'Content-Type': 'text/javascript',\n\t\t},\n\t})\n}\n","import path from 'path'\nimport {\n\tgetAppByName,\n\tgetExercise,\n\tisExampleApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\tisProblemApp,\n\tisSolutionApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport fsExtra from 'fs-extra'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\nimport { ensureUndeployed, getBaseUrl } from '#app/utils/misc.tsx'\nimport { resolveApps } from './__utils.ts'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('app')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tconst baseApp = isPlaygroundApp(app) ? await getAppByName(app.appName) : app\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.dev.type === 'script') {\n\t\treturn redirect(getBaseUrl({ request, port: app.dev.portNumber }), {\n\t\t\theaders: { 'Server-Timing': getServerTimeHeader(timings) },\n\t\t})\n\t}\n\tif (app.dev.type !== 'browser') {\n\t\tthrow new Response(\n\t\t\t`App \"${app.name}\" is not a browser app, its dev type is: \"${app.dev.type}\"`,\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\tconst htmlFile = path.join(app.fullPath, 'index.html')\n\tconst hasHtml = await fsExtra.pathExists(htmlFile)\n\tif (hasHtml) {\n\t\tconst html = await fsExtra.readFile(htmlFile)\n\t\treturn new Response(html, {\n\t\t\theaders: {\n\t\t\t\t'Content-Length': Buffer.byteLength(html).toString(),\n\t\t\t\t'Content-Type': 'text/html',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t})\n\t}\n\tconst indexFiles = (await fsExtra.readdir(app.fullPath)).filter(\n\t\t(file: string) => file.startsWith('index.'),\n\t)\n\tconst indexCss = indexFiles.find((file: string) => file.endsWith('index.css'))\n\tconst indexJs = indexFiles.find((file: string) => file.endsWith('index.js'))\n\tconst indexTs = indexFiles.find((file: string) => file.endsWith('index.ts'))\n\tconst indexTsx = indexFiles.find((file: string) => file.endsWith('index.tsx'))\n\tconst scripts = [indexJs, indexTs, indexTsx].filter(Boolean)\n\tif (scripts.length > 1) {\n\t\tthrow new Response(\n\t\t\t`Only one index.(js|ts|tsx) file is allowed, found ${scripts.join(', ')}`,\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\tconst appTitle = app.title\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst baseAppTitle = isExerciseStepApp(baseApp)\n\t\t? [\n\t\t\t\t`${baseApp.stepNumber.toString().padStart(2, '0')}. ${baseApp.title}`,\n\t\t\t\t`${baseApp.exerciseNumber.toString().padStart(2, '0')}. ${\n\t\t\t\t\t(await getExercise(baseApp.exerciseNumber, { request, timings }))\n\t\t\t\t\t\t?.title ?? 'Unknown'\n\t\t\t\t}`,\n\t\t\t\tworkshopTitle,\n\t\t\t]\n\t\t: [baseApp?.title ?? 'N/A']\n\tconst title = (\n\t\tisExerciseStepApp(app)\n\t\t\t? [\n\t\t\t\t\tisProblemApp(app) ? '💪' : isSolutionApp(app) ? '🏁' : null,\n\t\t\t\t\t...baseAppTitle,\n\t\t\t\t]\n\t\t\t: isPlaygroundApp(app)\n\t\t\t\t? ['🛝', ...baseAppTitle]\n\t\t\t\t: isExampleApp(app)\n\t\t\t\t\t? ['📚', ...baseAppTitle]\n\t\t\t\t\t: [appTitle]\n\t)\n\t\t.filter(Boolean)\n\t\t.join(' | ')\n\tconst html = /* html */ `\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<base href=\"${app.dev.pathname}\" />\n\t\t<meta charset=\"utf-8\">\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t\t<title>${title}</title>\n\t\t<link rel=\"stylesheet\" href=\"/app-default.css\">\n\t\t${indexCss ? `<link rel=\"stylesheet\" href=\"${indexCss}\">` : ''}\n\t</head>\n\t<body>\n\t\t${scripts\n\t\t\t.map((script) => `<script type=\"module\" src=\"${script}\"></script>`)\n\t\t\t.join('\\n')}\n\t\t<script type=\"module\" src=\"epic_ws.js\"></script>\n\t</body>\n</html>\n`\n\treturn new Response(html, {\n\t\theaders: {\n\t\t\t'Content-Length': Buffer.byteLength(html).toString(),\n\t\t\t'Content-Type': 'text/html',\n\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t},\n\t})\n}\n","import path from 'path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport {\n\tgetExercise,\n\tisExerciseStepApp,\n\tisProblemApp,\n\tisSolutionApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { userHasAccessToWorkshop } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport fsExtra from 'fs-extra'\nimport { type LoaderFunctionArgs } from 'react-router'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\nimport { resolveApps } from './__utils.ts'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('app_test_loader')\n\tconst userHasAccess = await userHasAccessToWorkshop({\n\t\trequest,\n\t})\n\tconst { testName } = params\n\tinvariantResponse(testName, 'Test name is required')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.test.type !== 'browser' || app.dev.type !== 'browser') {\n\t\treturn redirectWithToast(\n\t\t\t'/',\n\t\t\t{\n\t\t\t\ttype: 'error',\n\t\t\t\ttitle: 'Unsupported',\n\t\t\t\tdescription: `Cannot load this app's tests in the browser`,\n\t\t\t},\n\t\t\t{ headers: { 'Server-Timing': getServerTimeHeader(timings) } },\n\t\t)\n\t}\n\n\tconst testFile = app.test.testFiles.find((file) => file === testName)\n\tif (!testFile) {\n\t\tthrow new Response(`Test \"${testName}\" not found`, {\n\t\t\tstatus: 404,\n\t\t\theaders: { 'Server-Timing': getServerTimeHeader(timings) },\n\t\t})\n\t}\n\tif (!/(js|ts|tsx)$/.test(testFile)) {\n\t\t// TODO: support other test file types?\n\t\tthrow new Response(`Test \"${testName}\" is not a script`, {\n\t\t\tstatus: 400,\n\t\t\theaders: { 'Server-Timing': getServerTimeHeader(timings) },\n\t\t})\n\t}\n\n\tconst testScriptPath = `${app.dev.pathname}${testFile}`\n\tconst testScriptSrc = /* javascript */ `\nfunction logStatus(message) {\n\tif (window.parent !== window) {\n\t\twindow.parent.postMessage(\n\t\t\t{ type: 'epicshop:test-status-update', ...message },\n\t\t\t'*',\n\t\t)\n\t} else {\n\t\tif (message.status === 'fail') {\n\t\t\tconsole.error(message)\n\t\t} else if (message.status === 'pending') {\n\t\t\tconsole.info(message)\n\t\t} else if (message.status === 'pass') {\n\t\t\tconsole.log(message)\n\t\t}\n\t}\n}\nconst testFile = ${JSON.stringify(testFile)}\nlogStatus({status: 'pending', timestamp: Date.now()})\nimport(${JSON.stringify(testScriptPath)}).then(\n\t() => {\n\t\tlogStatus({ status: 'pass', timestamp: Date.now() })\n\t},\n\terror => {\n\t\tlogStatus({\n\t\t\tstatus: 'fail',\n\t\t\terror:\n\t\t\t\ttypeof error === 'string'\n\t\t\t\t\t? error\n\t\t\t\t\t: typeof error === 'object' && error && 'message' in error\n\t\t\t\t\t? error.message\n\t\t\t\t\t: 'unknown error',\n\t\t\ttimestamp: Date.now(),\n\t\t})\n\t\tthrow error\n\t},\n)\n`\n\n\tconst testScriptTag = userHasAccess\n\t\t? `<script type=\"module\">${testScriptSrc}</script>`\n\t\t: `<h1>Access Denied</h1><p>You must login or register for the workshop to run the tests</p>`\n\n\tconst htmlFile = path.join(app.fullPath, 'index.html')\n\tconst hasHtml = await fsExtra.pathExists(htmlFile)\n\tif (hasHtml) {\n\t\tconst html = (await fsExtra.readFile(htmlFile)).toString()\n\t\tconst testableHtml = html.includes('</body/>')\n\t\t\t? html.replace(`</body>`, `\\n${testScriptTag}\\n</body>`)\n\t\t\t: `${html}\\n${testScriptTag}`\n\t\treturn new Response(testableHtml, {\n\t\t\theaders: {\n\t\t\t\t'Content-Length': Buffer.byteLength(testableHtml).toString(),\n\t\t\t\t'Content-Type': 'text/html',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t})\n\t}\n\n\tconst indexFiles = (await fsExtra.readdir(app.fullPath)).filter(\n\t\t(file: string) => file.startsWith('index.'),\n\t)\n\tconst indexCss = indexFiles.find((file: string) => file.endsWith('index.css'))\n\n\tconst appTitle = app.title\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst title = (\n\t\tisExerciseStepApp(app)\n\t\t\t? [\n\t\t\t\t\tisProblemApp(app) ? '🧪💪' : isSolutionApp(app) ? '🧪🏁' : null,\n\t\t\t\t\t`${app.stepNumber.toString().padStart(2, '0')}. ${app.title}`,\n\t\t\t\t\t`${app.exerciseNumber.toString().padStart(2, '0')}. ${\n\t\t\t\t\t\t(await getExercise(app.exerciseNumber, { request, timings }))\n\t\t\t\t\t\t\t?.title ?? 'Unknown'\n\t\t\t\t\t}`,\n\t\t\t\t\tworkshopTitle,\n\t\t\t\t]\n\t\t\t: ['🧪', appTitle]\n\t)\n\t\t.filter(Boolean)\n\t\t.join(' | ')\n\tconst html = /* html */ `\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<base href=\"${app.dev.pathname}\" />\n\t\t<meta charset=\"utf-8\">\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t\t<title>${title}</title>\n\t\t<link rel=\"stylesheet\" href=\"/app-default.css\">\n\t\t${indexCss ? `<link rel=\"stylesheet\" href=\"${indexCss}\">` : ''}\n\t</head>\n\t<body>\n\t\t${testScriptTag}\n\t\t<script type=\"module\" src=\"epic_ws.js\"></script>\n\t</body>\n</html>\n`\n\treturn new Response(html, {\n\t\theaders: {\n\t\t\t'Content-Length': Buffer.byteLength(html).toString(),\n\t\t\t'Content-Type': 'text/html',\n\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t},\n\t})\n}\n","import { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { Link } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport {\n\tuseOptionalDiscordMember,\n\tuseOptionalUser,\n} from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nfunction useConnectDiscordURL() {\n\tconst {\n\t\tproduct: { host },\n\t} = useWorkshopConfig()\n\treturn `https://${host}/discord`\n}\n\nexport function useDiscordCTALink() {\n\tconst user = useOptionalUser()\n\tconst discordMember = useOptionalDiscordMember()\n\tconst connectDiscordURL = useConnectDiscordURL()\n\n\tif (!user) {\n\t\treturn '/login'\n\t}\n\tif (!discordMember) {\n\t\treturn connectDiscordURL\n\t}\n\n\treturn 'https://discord.com/channels/715220730605731931/1161045224907341972'\n}\n\nexport function DiscordCTA() {\n\tconst user = useOptionalUser()\n\tconst discordMember = useOptionalDiscordMember()\n\tconst connectDiscordURL = useConnectDiscordURL()\n\tif (!user) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-wrap items-center justify-center gap-2 text-xl\">\n\t\t\t\t<Link to=\"/login\" className=\"inline-flex items-center gap-2 underline\">\n\t\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t\t\tLogin\n\t\t\t\t</Link>{' '}\n\t\t\t\t<span>\n\t\t\t\t\tto get access to the exclusive{' '}\n\t\t\t\t\t<Link to=\"/discord\" className=\"underline\">\n\t\t\t\t\t\tdiscord channel\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t)\n\t}\n\tif (!discordMember) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-wrap items-center justify-center gap-2 text-xl\">\n\t\t\t\t<Link\n\t\t\t\t\tto={connectDiscordURL}\n\t\t\t\t\tclassName=\"flex items-center gap-2 underline\"\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t\t\tConnect Discord\n\t\t\t\t</Link>{' '}\n\t\t\t\t<span>\n\t\t\t\t\tto get access to the exclusive{' '}\n\t\t\t\t\t<Link to=\"/discord\" className=\"underline\">\n\t\t\t\t\t\tdiscord channel\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<div className=\"flex items-center justify-center gap-2 text-xl underline\">\n\t\t\t<Link to=\"discord://discord.com/channels/715220730605731931/1161045224907341972\">\n\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t</Link>\n\t\t\t<Link\n\t\t\t\tto=\"https://discord.com/channels/715220730605731931/1161045224907341972\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t>\n\t\t\t\tOpen Discord\n\t\t\t</Link>\n\t\t</div>\n\t)\n}\n\nexport default function DiscordRoute() {\n\treturn (\n\t\t<div className=\"container flex h-full max-w-3xl flex-col items-center justify-center gap-4 p-12\">\n\t\t\t<DiscordCTA />\n\t\t\t<p>\n\t\t\t\tThe{' '}\n\t\t\t\t<Link\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\tto=\"https://kentcdodds.com/discord\"\n\t\t\t\t>\n\t\t\t\t\tEpic Web Community on Discord\n\t\t\t\t</Link>{' '}\n\t\t\t\tis a great place to hang out with other developers who are working\n\t\t\t\tthrough this workshop. You can ask questions, get help, and solidify\n\t\t\t\twhat you're learning by helping others.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<small className=\"text-sm\">\n\t\t\t\t\tIf you've not joined the Epic Web Community on Discord yet, you'll be\n\t\t\t\t\trequired to go through a short onboarding process first. A friendly\n\t\t\t\t\tbot will explain the process when you{' '}\n\t\t\t\t\t<Link\n\t\t\t\t\t\tto=\"https://kcd.im/discord\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\tjoin\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</small>\n\t\t\t</p>\n\t\t</div>\n\t)\n}\n","import { getExercises } from '@epic-web/workshop-utils/apps.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { Outlet } from 'react-router'\nimport { serverOnly$ } from 'vite-env-only/macros'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: serverOnly$(async (request) => {\n\t\tconst exercises = await getExercises({ request })\n\t\treturn exercises.flatMap((e) => [\n\t\t\t{ route: `/exercise/${e.exerciseNumber.toString().padStart(2, '0')}` },\n\t\t\t...e.steps.flatMap((s) =>\n\t\t\t\t['problem', 'solution'].map((type) => ({\n\t\t\t\t\troute: `/exercise/${e.exerciseNumber.toString().padStart(2, '0')}/${s.stepNumber.toString().padStart(2, '0')}/${type}`,\n\t\t\t\t})),\n\t\t\t),\n\t\t\t{\n\t\t\t\troute: `/exercise/${e.exerciseNumber.toString().padStart(2, '0')}/finished`,\n\t\t\t},\n\t\t])\n\t}),\n}\n\nexport default function ExercisesLayout() {\n\treturn (\n\t\t<div className=\"flex h-full grow\">\n\t\t\t<Outlet />\n\t\t</div>\n\t)\n}\n","import {\n\tPlayerPreferencesSchema,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport RealMuxPlayer, {\n\ttype MuxPlayerRefAttributes,\n\tMinResolution,\n\tMaxResolution,\n} from '@mux/mux-player-react'\nimport * as React from 'react'\nimport {\n\tdata,\n\ttype ActionFunctionArgs,\n\tuseFetcher,\n\tuseFetchers,\n} from 'react-router'\nimport { z } from 'zod'\nimport { useDebounce } from '#app/utils/misc.tsx'\nimport './mux-player.css'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\n\nconst PlaybackTimeSchema = z\n\t.object({\n\t\ttime: z.number(),\n\t\texpiresAt: z.string(),\n\t})\n\t.transform((data) => {\n\t\treturn { time: Number(data.time), expiresAt: new Date(data.expiresAt) }\n\t})\n\nexport function usePlayerPreferences() {\n\tconst rootData = useRootLoaderData()\n\tconst fetchers = useFetchers()\n\tconst pendingPreferencesFetcher = fetchers.find(\n\t\t(f) => f.formAction === '/video-player',\n\t)\n\tif (pendingPreferencesFetcher && pendingPreferencesFetcher.state !== 'idle') {\n\t\tconst submittingData = pendingPreferencesFetcher.json\n\t\tif (submittingData) {\n\t\t\tconst optimisticPlayerPrefs = {\n\t\t\t\t...rootData.preferences?.player,\n\t\t\t\t...(submittingData as z.input<typeof PlayerPreferencesSchema>),\n\t\t\t} as z.input<typeof PlayerPreferencesSchema>\n\t\t\treturn optimisticPlayerPrefs\n\t\t}\n\t}\n\treturn rootData.preferences?.player ?? null\n}\n\ntype MuxPlayerProps = React.ComponentProps<typeof RealMuxPlayer>\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tconst result = PlayerPreferencesSchema.safeParse(await request.json())\n\tif (!result.success) {\n\t\treturn data({ status: 'error', error: result.error.flatten() } as const, {\n\t\t\tstatus: 400,\n\t\t})\n\t}\n\tawait setPreferences({ player: result.data })\n\treturn { status: 'success' } as const\n}\n\nfunction useLatest<Value>(value: Value) {\n\tconst ref = React.useRef(value)\n\tReact.useEffect(() => {\n\t\tref.current = value\n\t}, [value])\n\treturn ref\n}\n\nexport function MuxPlayer({\n\tmuxPlayerRef,\n\t...props\n}: MuxPlayerProps & {\n\tmuxPlayerRef: React.RefObject<MuxPlayerRefAttributes | null>\n}) {\n\tconst playerPreferences = usePlayerPreferences()\n\tconst playerPreferencesFetcher = useFetcher<typeof action>()\n\tconst [metadataLoaded, setMetadataLoaded] = React.useState(false)\n\tconst currentTimeSessionKey = `${props.playbackId}:currentTime`\n\tconst [currentTime, setCurrentTime] = React.useState(0)\n\n\tconst fetcherRef = useLatest(playerPreferencesFetcher)\n\tconst playerPreferencesRef = useLatest(playerPreferences)\n\n\tReact.useEffect(() => {\n\t\tif (typeof document === 'undefined') return\n\t\tconst stored = sessionStorage.getItem(currentTimeSessionKey)\n\t\tif (!stored) return\n\t\ttry {\n\t\t\tconst { time, expiresAt } = PlaybackTimeSchema.parse(JSON.parse(stored))\n\t\t\tif (expiresAt.getTime() < Date.now()) throw new Error('Time expired')\n\t\t\tsetCurrentTime(time)\n\t\t} catch {\n\t\t\tsessionStorage.removeItem(currentTimeSessionKey)\n\t\t}\n\t}, [currentTimeSessionKey])\n\n\tconst updatePreferences = useDebounce(() => {\n\t\tconst player = muxPlayerRef.current\n\t\tif (!player) return\n\t\tconst subs = Array.from(player.textTracks ?? []).find(\n\t\t\t(t) => t.kind === 'subtitles',\n\t\t)\n\t\tconst newPrefs = {\n\t\t\tplaybackRate: player.playbackRate,\n\t\t\tvolumeRate: player.volume,\n\t\t\tsubtitle: subs\n\t\t\t\t? { id: subs.id, mode: subs.mode }\n\t\t\t\t: { id: null, mode: 'disabled' },\n\t\t} satisfies z.input<typeof PlayerPreferencesSchema>\n\n\t\t// don't update the preferences if there's no change...\n\t\tif (isDeepEqual(newPrefs, playerPreferencesRef.current)) return\n\n\t\tvoid fetcherRef.current.submit(newPrefs, {\n\t\t\tmethod: 'POST',\n\t\t\taction: '/video-player',\n\t\t\tencType: 'application/json',\n\t\t})\n\t}, 300)\n\n\tReact.useEffect(() => {\n\t\t// as the video player gets loaded, mux fires a bunch of change events which\n\t\t// we don't want. So we wait until the metadata is loaded before we start\n\t\t// listening to the events.\n\t\tif (!metadataLoaded) return\n\n\t\tconst textTracks = muxPlayerRef.current?.textTracks\n\t\tif (!textTracks) return\n\n\t\tconst subtitlePref = playerPreferencesRef.current?.subtitle\n\t\tif (subtitlePref?.id) {\n\t\t\tconst preferredTextTrack = textTracks.getTrackById(subtitlePref.id)\n\t\t\tif (preferredTextTrack) {\n\t\t\t\tpreferredTextTrack.mode = subtitlePref.mode ?? 'hidden'\n\t\t\t}\n\t\t}\n\n\t\ttextTracks.addEventListener('change', updatePreferences)\n\t\treturn () => {\n\t\t\ttextTracks.removeEventListener('change', updatePreferences)\n\t\t}\n\t}, [metadataLoaded, muxPlayerRef, playerPreferencesRef, updatePreferences])\n\n\treturn (\n\t\t<div className=\"flex aspect-video flex-col\">\n\t\t\t<RealMuxPlayer\n\t\t\t\tref={muxPlayerRef}\n\t\t\t\tplaybackRates={[\n\t\t\t\t\t0.5, 0.75, 0.8, 0.9, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 3.5,\n\t\t\t\t\t// lol, someone really asked for this and I think it's funny so let's do it\n\t\t\t\t\t// https://x.com/zackerydev/status/1710840197879918840\n\t\t\t\t\t4,\n\t\t\t\t]}\n\t\t\t\tvolume={playerPreferences?.volumeRate ?? 1}\n\t\t\t\tplaybackRate={playerPreferences?.playbackRate ?? 1}\n\t\t\t\tthumbnailTime={currentTime}\n\t\t\t\tonRateChange={updatePreferences}\n\t\t\t\tonVolumeChange={updatePreferences}\n\t\t\t\tstreamType=\"on-demand\"\n\t\t\t\tdefaultHiddenCaptions={true}\n\t\t\t\tcurrentTime={currentTime}\n\t\t\t\tonTimeUpdate={() =>\n\t\t\t\t\tsessionStorage.setItem(\n\t\t\t\t\t\tcurrentTimeSessionKey,\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\ttime: muxPlayerRef.current?.currentTime,\n\t\t\t\t\t\t\texpiresAt: new Date(Date.now() + 1000 * 60 * 30).toISOString(),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\taccentColor=\"#427cf0\"\n\t\t\t\ttargetLiveWindow={NaN} // this has gotta be a bug. Without this prop, we get SSR warnings 🤷‍♂️\n\t\t\t\tminResolution={getMinResolutionValue(playerPreferences?.minResolution)}\n\t\t\t\tmaxResolution={getMaxResolutionValue(playerPreferences?.maxResolution)}\n\t\t\t\tonLoadedMetadata={() => setMetadataLoaded(true)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\nfunction isDeepEqual(obj1: unknown, obj2: unknown) {\n\tif (obj1 === obj2) return true\n\tif (typeof obj1 !== typeof obj2) return false\n\tif (typeof obj1 !== 'object' || typeof obj2 !== 'object') return false\n\tif (obj1 === null || obj2 === null) return false\n\tif (Array.isArray(obj1) !== Array.isArray(obj2)) return false\n\tif (Array.isArray(obj1) && Array.isArray(obj2)) {\n\t\tif (obj1.length !== obj2.length) return false\n\t\tfor (let i = 0; i < obj1.length; i++) {\n\t\t\tif (!isDeepEqual(obj1[i], obj2[i])) return false\n\t\t}\n\t\treturn true\n\t}\n\tconst keys1 = Object.keys(obj1)\n\tconst keys2 = Object.keys(obj2)\n\tif (keys1.length !== keys2.length) return false\n\tfor (const key of keys1) {\n\t\t// @ts-expect-error 🤷‍♂️ it's fine\n\t\tif (!isDeepEqual(obj1[key], obj2[key])) return false\n\t}\n\treturn true\n}\n\nfunction getMinResolutionValue(resolution: number | undefined) {\n\tif (!resolution) return undefined\n\tif (resolution <= 480) return MinResolution.noLessThan480p\n\tif (resolution <= 540) return MinResolution.noLessThan540p\n\tif (resolution <= 720) return MinResolution.noLessThan720p\n\tif (resolution <= 1080) return MinResolution.noLessThan1080p\n\tif (resolution <= 1440) return MinResolution.noLessThan1440p\n\treturn MinResolution.noLessThan2160p\n}\n\nfunction getMaxResolutionValue(resolution: number | undefined) {\n\tif (!resolution) return undefined\n\tif (resolution <= 720) return MaxResolution.upTo720p\n\tif (resolution <= 1080) return MaxResolution.upTo1080p\n\tif (resolution <= 1440) return MaxResolution.upTo1440p\n\treturn MaxResolution.upTo2160p\n}\n","// originally this was based on baffle-react, but it was unnecessarily bloated\n// and very out-dated. I've replaced it with a simple Characters component that\n// does the same thing we were using baffle-react for\nimport { useEffect, useRef, useState } from 'react'\nimport { useHints } from '#app/utils/client-hints.tsx'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport function Loading({\n\tclassName,\n\tchildren = 'Loading',\n}: {\n\tclassName?: string\n\tchildren?: React.ReactNode\n}) {\n\tconst { reducedMotion } = useHints()\n\tif (reducedMotion === 'reduce') {\n\t\treturn <div className=\"animate-pulse\">{children}</div>\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex items-center gap-2 font-mono text-sm font-medium uppercase',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\trole=\"status\"\n\t\t>\n\t\t\t<div aria-hidden=\"true\">\n\t\t\t\t<Characters />\n\t\t\t</div>\n\t\t\t{children}\n\t\t\t<div aria-hidden=\"true\">\n\t\t\t\t<Characters />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nconst characters = '█<▓█ ▒░/▒░ █░>▒▓/ █▒▒ ▓▒▓/█<░▒ ▓/░>'\nconst randomCharacter = () =>\n\tcharacters[Math.floor(Math.random() * characters.length)]\nexport function Characters() {\n\tconst [char1, setChar1] = useState(characters[0])\n\tconst [char2, setChar2] = useState(characters[1])\n\n\tuseInterval(() => {\n\t\tsetChar1(randomCharacter())\n\t\tsetChar2(randomCharacter())\n\t}, 80)\n\n\treturn (\n\t\t<span>\n\t\t\t{char1}\n\t\t\t{char2}\n\t\t</span>\n\t)\n}\n\nfunction useInterval(callback: () => void, delay: number | null = 1000) {\n\tconst savedCallback = useRef<() => void>(null)\n\n\t// Remember the latest function.\n\tuseEffect(() => {\n\t\tsavedCallback.current = callback\n\t}, [callback])\n\n\t// Set up the interval.\n\tuseEffect(() => {\n\t\tfunction tick() {\n\t\t\tsavedCallback.current?.()\n\t\t}\n\t\tif (delay !== null) {\n\t\t\tconst id = setInterval(tick, delay)\n\t\t\treturn () => clearInterval(id)\n\t\t}\n\t}, [delay])\n}\n","import { type EpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport { type MuxPlayerRefAttributes } from '@mux/mux-player-react'\nimport * as React from 'react'\nimport { Await, Link } from 'react-router'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { MuxPlayer } from '#app/routes/video-player/index.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { Icon } from './icons.tsx'\nimport { Loading } from './loading.tsx'\nimport { useOptionalUser } from './user.tsx'\nimport { useWorkshopConfig } from './workshop-config.tsx'\n\nconst EpicVideoInfoContext = React.createContext<\n\tPromise<EpicVideoInfos> | null | undefined\n>(null)\n\nexport function EpicVideoInfoProvider({\n\tchildren,\n\tepicVideoInfosPromise,\n}: {\n\tchildren: React.ReactNode\n\tepicVideoInfosPromise?: Promise<EpicVideoInfos> | null\n}) {\n\treturn (\n\t\t<EpicVideoInfoContext.Provider value={epicVideoInfosPromise}>\n\t\t\t{children}\n\t\t</EpicVideoInfoContext.Provider>\n\t)\n}\n\nfunction extractEpicTitle(urlString: string) {\n\tlet url: URL = new URL('https://epicweb.dev')\n\ttry {\n\t\turl = new URL(urlString)\n\t} catch (error) {\n\t\tconsole.error(error)\n\t\treturn 'Epic Video'\n\t}\n\tconst urlSegments = url.pathname.split('/').filter(Boolean)\n\tconst isSolution = urlSegments.includes('solution')\n\tlet titleSegment = urlSegments.pop()\n\tconst nonTitles = ['problem', 'solution', 'embed', 'exercise']\n\tconst isTitleSegment = (str?: string) => str && !nonTitles.includes(str)\n\twhile (!isTitleSegment(titleSegment)) titleSegment = urlSegments.pop()\n\n\tif (!titleSegment) return 'Epic Video'\n\n\t// Chop off anything after ~ if no spaces follow anywhere after the ~\n\t// that's common for EpicAI videos\n\ttitleSegment = titleSegment.replace(/~[^ ]*$/, '')\n\n\tconst titleWords = titleSegment.split('-')\n\t// prettier-ignore\n\tconst lowerCaseWords = [\n\t\t'the', 'a', 'an', 'and', 'but', 'or', 'for', 'nor', 'on', 'at', 'to',\n\t\t'from', 'by', 'of', 'in', 'with', 'as', 'npm', 'git', 'ssh', 'cli'\n\t]\n\t// prettier-ignore\n\tconst literalWords = [\n\t\t'OAuth', 'UI', 'UX', 'API', 'CSS', 'HTML', 'JS', 'TS', 'SVG', 'AI', 'CSRF',\n\t\t'CORS', 'HTTP', 'HTTPS', 'URL', 'URI', 'DB', 'SQL', 'JSON', 'YAML', 'YML',\n\n\t\t'useActionData', 'useAsyncError', 'useAsyncValue', 'useBeforeUnload',\n\t\t'useFetcher', 'useFetchers', 'useFormAction', 'useHref', 'useLoaderData',\n\t\t'useLocation', 'useMatches', 'useNavigate', 'useNavigation',\n\t\t'useNavigationType', 'useOutlet', 'useOutletContext', 'useParams',\n\t\t'useResolvedPath', 'useRevalidator', 'useRouteError', 'useRouteLoaderData',\n\t\t'useSearchParams', 'useSubmit', 'useCallback', 'useContext',\n\t\t'useDebugValue', 'useDeferredValue', 'useEffect', 'useId',\n\t\t'useImperativeHandle', 'useInsertionEffect', 'useLayoutEffect', 'useMemo',\n\t\t'useReducer', 'useRef', 'useState', 'useSyncExternalStore', 'useTransition',\n\t\t'useForm','useFieldset', 'useFieldList', 'useEventSource', 'useHydrated',\n\t\t'useAuthenticityToken', 'useShouldHydrate', 'useGlobalNavigationState',\n\t\t'useLocales', 'useDelegatedAnchors', 'useDebounceFetcher', 'useFetcherType',\n\t]\n\tconst title = titleWords\n\t\t.filter(Boolean)\n\t\t.map((word, index) => {\n\t\t\tconst lowerWord = word.toLowerCase()\n\t\t\tconst literalWord = literalWords.find(\n\t\t\t\t(w) => w.toLowerCase() === lowerWord,\n\t\t\t)\n\t\t\tif (literalWord) return literalWord\n\t\t\tif (lowerCaseWords.includes(lowerWord) && index > 0) {\n\t\t\t\treturn lowerWord\n\t\t\t}\n\t\t\treturn lowerWord[0]?.toUpperCase() + lowerWord.slice(1)\n\t\t})\n\t\t.join(' ')\n\tif (isSolution) {\n\t\treturn `${title} (🏁 solution)`\n\t}\n\treturn title\n}\n\nexport function VideoEmbed({\n\turl,\n\ttitle = 'Video Embed',\n\tloadingContent = (\n\t\t<Loading>\n\t\t\t<span>Loading \"{title}\"</span>\n\t\t</Loading>\n\t),\n}: {\n\turl: string\n\ttitle?: string\n\tloadingContent?: React.ReactNode\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"relative aspect-video w-full shrink-0 shadow-lg\">\n\t\t\t\t<div className=\"not-prose text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center p-8\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{'Unable to load the video '}\n\t\t\t\t\t\t\t<a href={url} className=\"underline\">\n\t\t\t\t\t\t\t\t{`\"${title ?? url}\"`}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{' when offline'}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<div className=\"relative aspect-video w-full shrink-0 shadow-lg\">\n\t\t\t{iframeLoaded ? null : (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center p-8\">\n\t\t\t\t\t{loadingContent}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\tsrc={url}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\ttitle={title}\n\t\t\t\tsandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n\t\t\t\tallowFullScreen\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\nfunction VideoLink({\n\turl,\n\ttitle,\n\tduration,\n\tdurationEstimate,\n}: {\n\turl: string\n\ttitle: string\n\tduration?: number | null\n\tdurationEstimate?: number | null\n}) {\n\treturn (\n\t\t<span className=\"flex items-center gap-1 text-base\">\n\t\t\t{duration ? (\n\t\t\t\t<span className=\"opacity-70\">{formatDuration(duration)}</span>\n\t\t\t) : durationEstimate ? (\n\t\t\t\t<span className=\"opacity-70\">~{formatDuration(durationEstimate)}</span>\n\t\t\t) : null}\n\t\t\t<a\n\t\t\t\thref={url}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\tclassName=\"flex items-center gap-1 no-underline opacity-70 transition hover:underline hover:opacity-100\"\n\t\t\t\trel=\"noreferrer\"\n\t\t\t>\n\t\t\t\t<Icon className=\"shrink-0\" name=\"Video\" size=\"lg\" />\n\t\t\t\t{title} <span aria-hidden>↗︎</span>\n\t\t\t</a>\n\t\t</span>\n\t)\n}\nexport function DeferredEpicVideo({\n\turl,\n\ttitle: providedTitle,\n}: {\n\turl: string\n\ttitle?: string\n}) {\n\t// we need to distinguish between the provided title and the fallback because the priority is:\n\t// 1. provided title\n\t// 2. title from the api\n\t// 3. fallback title\n\tconst title = providedTitle ?? extractEpicTitle(url)\n\tconst {\n\t\tproduct: { host, displayName },\n\t} = useWorkshopConfig()\n\tconst user = useOptionalUser()\n\tconst epicVideoInfosPromise = React.useContext(EpicVideoInfoContext)\n\tconst linkUI = <VideoLink url={url} title={title} />\n\treturn (\n\t\t<div>\n\t\t\t<React.Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"flex aspect-video w-full items-center justify-center\">\n\t\t\t\t\t\t\t<Loading>{title}</Loading>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t<div className=\"h-[32px]\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await\n\t\t\t\t\terrorElement={\n\t\t\t\t\t\t<div>Sorry, failed loading videos. Check the terminal output?</div>\n\t\t\t\t\t}\n\t\t\t\t\tresolve={epicVideoInfosPromise}\n\t\t\t\t>\n\t\t\t\t\t{(epicVideoInfos) => {\n\t\t\t\t\t\tconst epicVideoInfo = epicVideoInfos?.[url]\n\t\t\t\t\t\tconst transcriptUI = ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<Link to={ENV.EPICSHOP_GITHUB_REPO} className=\"underline\">\n\t\t\t\t\t\t\t\t\tRun locally\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t{' for transcripts'}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<Link to=\"/login\" className=\"underline\">\n\t\t\t\t\t\t\t\t\t{user ? 'Upgrade' : 'Login'}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t{' for transcripts'}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif (!epicVideoInfo) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t{transcriptUI}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst info = epicVideoInfo\n\t\t\t\t\t\tif (info.status === 'success') {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<EpicVideo\n\t\t\t\t\t\t\t\t\turl={url}\n\t\t\t\t\t\t\t\t\ttitle={providedTitle ?? info.title ?? title}\n\t\t\t\t\t\t\t\t\tmuxPlaybackId={info.muxPlaybackId}\n\t\t\t\t\t\t\t\t\ttranscript={info.transcript}\n\t\t\t\t\t\t\t\t\tduration={info.duration}\n\t\t\t\t\t\t\t\t\tdurationEstimate={info.durationEstimate}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else if (info.type === 'region-restricted') {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<div className=\"flex aspect-video min-h-full min-w-full flex-col items-center justify-start gap-2 overflow-y-scroll border-2 p-4 lg:justify-center lg:gap-4 lg:text-xl\">\n\t\t\t\t\t\t\t\t\t\t<div className=\"!text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\tError: Region Restricted\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t\t\tWe've detected you're connecting from{' '}\n\t\t\t\t\t\t\t\t\t\t\t{info.requestCountry} but your license has restricted\n\t\t\t\t\t\t\t\t\t\t\taccess to {info.restrictedCountry}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t\t\tTo continue watching uninterrupted, please{' '}\n\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\thref={`https://${host}/products`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\tupgrade your {displayName} license\n\t\t\t\t\t\t\t\t\t\t\t</a>{' '}\n\t\t\t\t\t\t\t\t\t\t\tto a full Pro license.\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={`https://${host}/products`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\tUpgrade\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{' for transcripts'}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else if (info.statusCode === 401) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t{transcriptUI}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else if (info.statusCode === 403) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={`https://${host}/products`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\tUpgrade\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{' for transcripts'}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else if (info.statusCode === 404) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t<div>Transcripts not found</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.error(info)\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t<div className=\"!text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\tUnknown error (check console)\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t</Await>\n\t\t\t</React.Suspense>\n\t\t</div>\n\t)\n}\n\nfunction EpicVideo({\n\turl: urlString,\n\ttitle = extractEpicTitle(urlString),\n\tmuxPlaybackId,\n\ttranscript,\n\tduration,\n\tdurationEstimate,\n}: {\n\turl: string\n\ttitle?: string\n\tmuxPlaybackId: string\n\ttranscript: string\n\tduration?: number | null\n\tdurationEstimate?: number | null\n}) {\n\tconst muxPlayerRef = React.useRef<MuxPlayerRefAttributes>(null)\n\tconst timestampRegex = /(\\d+:\\d+)/g\n\t// turn the transcript into an array of React elements\n\tconst transcriptElements: Array<React.ReactNode> = []\n\tlet match\n\tlet prevIndex = 0\n\twhile ((match = timestampRegex.exec(transcript))) {\n\t\tconst timestamp = match[1]\n\t\tif (!timestampRegex.lastIndex || !timestamp) break\n\n\t\tconst timestampIndexStart = match.index\n\t\tconst timestampIndexEnd = timestampRegex.lastIndex\n\t\tconst textBeforeTimestamp = transcript.slice(\n\t\t\tprevIndex + 1,\n\t\t\ttimestampIndexStart - 1,\n\t\t)\n\t\ttranscriptElements.push(\n\t\t\t<span key={`span-${timestampIndexStart}`}>{textBeforeTimestamp}</span>,\n\t\t)\n\t\ttranscriptElements.push(\n\t\t\t<button\n\t\t\t\tkey={`button-${timestampIndexStart}`}\n\t\t\t\tclassName=\"underline\"\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\tif (muxPlayerRef.current) {\n\t\t\t\t\t\tmuxPlayerRef.current.currentTime = hmsToSeconds(timestamp)\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tvoid muxPlayerRef.current.play().catch(() => {})\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmuxPlayerRef.current.scrollIntoView({\n\t\t\t\t\t\t\tbehavior: 'smooth',\n\t\t\t\t\t\t\tinline: 'center',\n\t\t\t\t\t\t\tblock: 'start',\n\t\t\t\t\t\t})\n\t\t\t\t\t\tevent.currentTarget.blur()\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{timestamp}\n\t\t\t</button>,\n\t\t)\n\t\tprevIndex = timestampIndexEnd\n\t}\n\ttranscriptElements.push(\n\t\t<span key={transcript.length}>\n\t\t\t{transcript.slice(prevIndex + 1, transcript.length)}\n\t\t</span>,\n\t)\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"shadow-lg\">\n\t\t\t\t<MuxPlayer\n\t\t\t\t\tplaybackId={muxPlaybackId}\n\t\t\t\t\tmuxPlayerRef={muxPlayerRef}\n\t\t\t\t\ttitle={title}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t<VideoLink\n\t\t\t\t\turl={urlString}\n\t\t\t\t\ttitle={title}\n\t\t\t\t\tduration={duration}\n\t\t\t\t\tdurationEstimate={durationEstimate}\n\t\t\t\t/>\n\t\t\t\t<details>\n\t\t\t\t\t<summary>Transcript</summary>\n\t\t\t\t\t<div className=\"bg-accent text-accent-foreground rounded-md p-2 whitespace-pre-line\">\n\t\t\t\t\t\t{transcriptElements}\n\t\t\t\t\t</div>\n\t\t\t\t</details>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction hmsToSeconds(str: string) {\n\tconst p = str.split(':')\n\tlet s = 0\n\tlet m = 1\n\n\twhile (p.length > 0) {\n\t\ts += m * parseInt(p.pop() ?? '0', 10)\n\t\tm *= 60\n\t}\n\treturn s\n}\n\nfunction formatDuration(seconds: number): string {\n\tconst hours = Math.floor(seconds / 3600)\n\tconst minutes = Math.floor((seconds % 3600) / 60)\n\tconst secs = Math.floor(seconds % 60)\n\n\tif (hours > 0) {\n\t\treturn `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`\n\t}\n\treturn `${minutes}:${secs.toString().padStart(2, '0')}`\n}\n\nfunction EpicVideoEmbed({\n\turl: urlString,\n\ttitle,\n}: {\n\turl: string\n\ttitle: string\n}) {\n\tconst theme = useTheme()\n\tlet url: URL = new URL('https://epicweb.dev')\n\ttry {\n\t\turl = new URL(urlString)\n\t} catch (error) {\n\t\tconsole.error(error)\n\t\treturn <div>Invalid URL: \"{urlString}\"</div>\n\t}\n\turl.pathname = url.pathname.endsWith('/')\n\t\t? `${url.pathname}embed`\n\t\t: `${url.pathname}/embed`\n\turl.searchParams.set('theme', theme)\n\t// special case for epicai.pro videos\n\tif (\n\t\turl.host === 'www.epicai.pro' &&\n\t\t!url.pathname.startsWith('/workshops/')\n\t) {\n\t\turl.pathname = `/posts/${url.pathname}`\n\t}\n\treturn (\n\t\t<VideoEmbed\n\t\t\turl={url.toString()}\n\t\t\ttitle={title}\n\t\t\tloadingContent={\n\t\t\t\t<Loading>\n\t\t\t\t\t<span>\n\t\t\t\t\t\t{'Loading \"'}\n\t\t\t\t\t\t<a className=\"underline\" href={urlString}>\n\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t{'\"'}\n\t\t\t\t\t</span>\n\t\t\t\t</Loading>\n\t\t\t}\n\t\t/>\n\t)\n}\n","import path from 'path'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport { launchEditor } from '@epic-web/workshop-utils/launch-editor.server'\nimport fsExtra from 'fs-extra'\nimport { useEffect } from 'react'\nimport { Link, useFetcher, type ActionFunctionArgs } from 'react-router'\nimport { z, type ZodTypeAny } from 'zod'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { cn, ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { useApps, useRequestInfo } from '#app/utils/root-loader.ts'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nfunction getFileDescriptorSchema<AppFile extends ZodTypeAny>(appFile: AppFile) {\n\treturn z.union([\n\t\tz.object({\n\t\t\ttype: z.literal('file'),\n\t\t\tfile: z.string(),\n\t\t}),\n\t\tz.object({\n\t\t\ttype: z.literal('appFile'),\n\t\t\tappFile,\n\t\t\tappName: z.string(),\n\t\t}),\n\t])\n}\n\nconst LaunchSchema = z.intersection(\n\tz.object({\n\t\tline: z.coerce.number().optional(),\n\t\tcolumn: z.coerce.number().optional(),\n\t\tsyncTo: getFileDescriptorSchema(z.string()).optional(),\n\t}),\n\tgetFileDescriptorSchema(z.array(z.string())),\n)\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst syncTo = {\n\t\ttype: formData.get('syncTo.type') ?? undefined,\n\t\tfile: formData.get('syncTo.file') ?? undefined,\n\t\tworkshopFile: formData.get('syncTo.workshopFile') ?? undefined,\n\t\tappFile: formData.getAll('syncTo.appFile'),\n\t\tappName: formData.get('syncTo.appName') ?? undefined,\n\t}\n\tconst syncToIsProvided = Object.values(syncTo).some((v) =>\n\t\tArray.isArray(v) ? v.length : v,\n\t)\n\tconst rawData = {\n\t\ttype: formData.get('type'),\n\t\tfile: formData.get('file'),\n\t\tworkshopFile: formData.get('workshopFile'),\n\t\tappFile: formData.getAll('appFile'),\n\t\tappName: formData.get('appName'),\n\t\tline: formData.get('line') ?? undefined,\n\t\tcolumn: formData.get('column') ?? undefined,\n\t\tsyncTo: syncToIsProvided\n\t\t\t? {\n\t\t\t\t\ttype: formData.get('syncTo.type'),\n\t\t\t\t\tfile: formData.get('syncTo.file'),\n\t\t\t\t\tworkshopFile: formData.get('syncTo.workshopFile'),\n\t\t\t\t\tappFile: formData.getAll('syncTo.appFile'),\n\t\t\t\t\tappName: formData.get('syncTo.appName'),\n\t\t\t\t}\n\t\t\t: undefined,\n\t}\n\tconst form = LaunchSchema.parse(rawData)\n\n\tasync function getFiles(\n\t\tfileDescriptor:\n\t\t\t| ({ line?: number; colum?: number } & {\n\t\t\t\t\ttype: 'file'\n\t\t\t\t\tfile: string\n\t\t\t\t\tappName?: never\n\t\t\t\t\tappFile?: never\n\t\t\t })\n\t\t\t| {\n\t\t\t\t\ttype: 'appFile'\n\t\t\t\t\tfile?: never\n\t\t\t\t\tappName: string\n\t\t\t\t\tappFile: string | Array<string>\n\t\t\t },\n\t): Promise<Array<{ filepath: string; line?: number; column?: number }>> {\n\t\tif (fileDescriptor.type === 'file') {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tfilepath: fileDescriptor.file,\n\t\t\t\t\tline: fileDescriptor.line,\n\t\t\t\t\tcolumn: fileDescriptor.colum,\n\t\t\t\t},\n\t\t\t]\n\t\t} else {\n\t\t\tconst fileDescriptorApp = await getAppByName(fileDescriptor.appName)\n\t\t\tif (!fileDescriptorApp) {\n\t\t\t\tthrow new Response(`App \"${fileDescriptor.appName}\" Not found`, {\n\t\t\t\t\tstatus: 404,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst appFile = Array.isArray(fileDescriptor.appFile)\n\t\t\t\t? fileDescriptor.appFile\n\t\t\t\t: [fileDescriptor.appFile]\n\t\t\treturn appFile.map((file) => {\n\t\t\t\tconst [filePath, line = '1', column = '1'] = file.split(',')\n\t\t\t\tif (!filePath) {\n\t\t\t\t\tthrow new Response(\n\t\t\t\t\t\t`appFile missing file path: ${fileDescriptor.appFile}`,\n\t\t\t\t\t\t{ status: 400 },\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tfilepath: path.join(fileDescriptorApp.fullPath, filePath),\n\t\t\t\t\tline: Number(line),\n\t\t\t\t\tcolumn: Number(column),\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\n\tconst filesToOpen = await getFiles(form)\n\tif ('syncTo' in form && form.syncTo) {\n\t\tconst originFiles = await getFiles(form.syncTo)\n\t\tfor (let index = 0; index < originFiles.length; index++) {\n\t\t\tconst originFile = originFiles[index]\n\t\t\tif (!originFile) continue\n\t\t\tconst destFile = filesToOpen[index]\n\t\t\tif (!destFile) {\n\t\t\t\tthrow new Response(\n\t\t\t\t\t`Trying to sync to a file that does not appear at index ${index}`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tawait fsExtra.ensureDir(path.dirname(destFile.filepath))\n\t\t\tawait fsExtra.promises.copyFile(originFile.filepath, destFile.filepath)\n\t\t}\n\t}\n\tconst results: Array<\n\t\t{ status: 'success' } | { status: 'error'; message: string }\n\t> = []\n\tfor (const file of filesToOpen) {\n\t\tresults.push(await launchEditor(file.filepath, file.line, file.column))\n\t}\n\n\tif (results.every((r) => r.status === 'success')) {\n\t\treturn dataWithPE(request, formData, { status: 'success' } as const)\n\t} else {\n\t\tconst messages = results\n\t\t\t.map((r, index, array) =>\n\t\t\t\tr.status === 'error'\n\t\t\t\t\t? array.length > 1\n\t\t\t\t\t\t? `${index}. ${r.message}`\n\t\t\t\t\t\t: r.message\n\t\t\t\t\t: null,\n\t\t\t)\n\t\t\t.filter(Boolean)\n\t\t\t.join('\\n')\n\t\tconsole.error('Launch editor error:', messages)\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ status: 'error', message: messages } as const,\n\t\t\t{\n\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\ttitle: 'Launch Editor Error',\n\t\t\t\t\tdescription: messages,\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t}\n}\n\ntype FileDescriptorProps<AppFile> =\n\t| {\n\t\t\tfile: string\n\t\t\tappFile?: never\n\t\t\tappName?: never\n\t }\n\t| {\n\t\t\tfile?: never\n\t\t\tappFile: AppFile\n\t\t\tappName: string\n\t }\n\ntype LaunchEditorProps = {\n\tclassName?: string\n\tline?: number\n\tcolumn?: number\n\tsyncTo?: FileDescriptorProps<string>\n\tchildren: React.ReactNode\n\tonUpdate?: (state: string) => void\n} & FileDescriptorProps<string | string[]>\n\nfunction useLaunchFetcher(onUpdate?: ((state: string) => void) | undefined) {\n\tconst fetcher = useFetcher<typeof action>()\n\n\tuseEffect(() => {\n\t\tif (fetcher.state === 'idle' && fetcher.data != null) {\n\t\t\tonUpdate?.('fetcher-done')\n\t\t}\n\t}, [fetcher, onUpdate])\n\n\treturn fetcher\n}\n\nfunction LaunchEditorImpl({\n\tclassName,\n\tfile,\n\tappFile,\n\tappName,\n\tsyncTo,\n\tline,\n\tcolumn,\n\tchildren,\n\tonUpdate,\n}: LaunchEditorProps) {\n\tconst fetcher = useLaunchFetcher(onUpdate)\n\tconst peRedirectInput = usePERedirectInput()\n\n\tif (!file && !appFile) {\n\t\tconsole.error('LaunchEditor: requires either \"file\" or \"appFile\" prop.')\n\t\treturn null\n\t}\n\tconst fileList = typeof appFile === 'string' ? [appFile] : appFile\n\tconst type = file ? 'file' : 'appFile'\n\tconst syncToType = syncTo?.file ? 'file' : syncTo?.appFile ? 'appFile' : ''\n\n\treturn (\n\t\t<fetcher.Form\n\t\t\taction=\"/launch-editor\"\n\t\t\tmethod=\"POST\"\n\t\t\tclassName=\"flex items-center\"\n\t\t>\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input\n\t\t\t\ttype=\"hidden\"\n\t\t\t\tname=\"line\"\n\t\t\t\tvalue={typeof line === 'number' ? line : undefined}\n\t\t\t/>\n\t\t\t<input type=\"hidden\" name=\"column\" value={column} />\n\t\t\t<input type=\"hidden\" name=\"type\" value={type} />\n\t\t\t<input type=\"hidden\" name=\"file\" value={file} />\n\t\t\t<input type=\"hidden\" name=\"appName\" value={appName} />\n\t\t\t{fileList?.map((file) => (\n\t\t\t\t<input type=\"hidden\" name=\"appFile\" key={file} value={file} />\n\t\t\t))}\n\t\t\t{syncTo ? (\n\t\t\t\t<>\n\t\t\t\t\t<input type=\"hidden\" name=\"syncTo.type\" value={syncToType} />\n\t\t\t\t\t<input type=\"hidden\" name=\"syncTo.file\" value={syncTo.file} />\n\t\t\t\t\t<input type=\"hidden\" name=\"syncTo.appName\" value={syncTo.appName} />\n\t\t\t\t\t<input type=\"hidden\" name=\"syncTo.appFile\" value={syncTo.appFile} />\n\t\t\t\t</>\n\t\t\t) : null}\n\t\t\t<button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'launch_button',\n\t\t\t\t\tfetcher.state === 'idle' ? null : 'cursor-progress',\n\t\t\t\t\tfetcher.data?.status === 'error' ? 'cursor-not-allowed' : null,\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</button>\n\t\t</fetcher.Form>\n\t)\n}\n\nfunction LaunchGitHub({\n\tclassName,\n\tfile,\n\tappFile,\n\tappName,\n\tline,\n\tchildren,\n}: LaunchEditorProps) {\n\tconst apps = useApps()\n\tconst requestInfo = useRequestInfo()\n\tif (Array.isArray(appFile)) {\n\t\treturn <div>Cannot open more than one file</div>\n\t}\n\tif (file) {\n\t\tconst safePath = (s: string) => s.replace(/\\\\/g, '/')\n\t\t// Convert tree to blob for individual files\n\t\tconst githubFileRoot = ENV.EPICSHOP_GITHUB_ROOT.replace('/tree/', '/blob/')\n\t\treturn (\n\t\t\t<a\n\t\t\t\tclassName=\"launch_button !no-underline\"\n\t\t\t\thref={\n\t\t\t\t\tsafePath(file).replace(\n\t\t\t\t\t\tsafePath(ENV.EPICSHOP_CONTEXT_CWD),\n\t\t\t\t\t\tgithubFileRoot,\n\t\t\t\t\t) + (line ? `#L${line}` : '')\n\t\t\t\t}\n\t\t\t\trel=\"noreferrer\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</a>\n\t\t)\n\t}\n\tconst app = apps.find((a) => a.name === appName)\n\t// Convert tree to blob for individual files\n\tconst githubFileRoot = ENV.EPICSHOP_GITHUB_ROOT.replace('/tree/', '/blob/')\n\n\t// Parse appFile to extract filename and line number (format: \"filename,line,column\")\n\tconst [filename, appFileLine] = appFile ? appFile.split(',') : ['', '']\n\tconst lineNumber = line || (appFileLine ? Number(appFileLine) : undefined)\n\n\tconst path = [\n\t\t...(app?.relativePath.split(requestInfo.separator) ?? []),\n\t\tfilename,\n\t].join('/')\n\treturn (\n\t\t<a\n\t\t\tclassName={cn('launch_button !no-underline', className)}\n\t\t\thref={`${githubFileRoot}/${path}${lineNumber ? `#L${lineNumber}` : ''}`}\n\t\t\trel=\"noreferrer\"\n\t\t\ttarget=\"_blank\"\n\t\t>\n\t\t\t{children}\n\t\t</a>\n\t)\n}\n\nexport function EditFileOnGitHub({\n\tappFile = 'README.mdx',\n\tappName,\n\tfile,\n\trelativePath,\n\tcompact = false,\n}: {\n\tappFile?: string\n\trelativePath: string\n\tcompact?: boolean\n} & (\n\t| {\n\t\t\tfile: string\n\t\t\tappName?: never\n\t }\n\t| {\n\t\t\tfile?: never\n\t\t\tappName: string\n\t }\n)) {\n\tconst fetcher = useLaunchFetcher()\n\n\tconst handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {\n\t\tif (!e.altKey || ENV.EPICSHOP_DEPLOYED) return\n\t\te.preventDefault()\n\t\tconst formData = new FormData()\n\t\tconst type = file ? 'file' : 'appFile'\n\t\tformData.append(type, file ?? appFile)\n\t\tformData.append('type', type)\n\t\tif (appName) {\n\t\t\tformData.append('appName', appName)\n\t\t}\n\t\tvoid fetcher.submit(formData, { method: 'POST', action: '/launch-editor' })\n\t}\n\n\tconst githubPath = ENV.EPICSHOP_GITHUB_ROOT.replace(\n\t\t/\\/tree\\/|\\/blob\\//,\n\t\t'/edit/',\n\t)\n\n\treturn (\n\t\t<Link\n\t\t\tclassName=\"self-center font-mono text-sm\"\n\t\t\tonClick={handleClick}\n\t\t\ttarget=\"_blank\"\n\t\t\tto={`${githubPath}/${relativePath}`.replace(/\\\\/g, '/')}\n\t\t>\n\t\t\t{compact ? (\n\t\t\t\t<span>Edit</span>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<span className=\"block md:hidden\">Edit on GitHub</span>\n\t\t\t\t\t<span className=\"hidden md:block\">Edit this page on GitHub</span>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</Link>\n\t)\n}\n\nexport const LaunchEditor = ENV.EPICSHOP_DEPLOYED\n\t? LaunchGitHub\n\t: LaunchEditorImpl\n","import { useEffect, useId, useRef } from 'react'\n\nexport function Mermaid({\n\tcode,\n\tonSvg,\n}: {\n\tcode: string\n\tonSvg?: (svg: string) => void\n}) {\n\tconst id = `mermaid-svg-${useId()}`\n\tconst ref = useRef<HTMLDivElement>(null)\n\tconst latestOnSvg = useRef(onSvg)\n\tuseEffect(() => {\n\t\tlatestOnSvg.current = onSvg\n\t}, [onSvg])\n\n\tuseEffect(() => {\n\t\tif (!ref.current) return\n\t\tlet cancelled = false\n\t\tvoid import('mermaid').then((mermaid) => {\n\t\t\tmermaid.default.initialize({ startOnLoad: false })\n\t\t\tmermaid.default\n\t\t\t\t.render(id, code)\n\t\t\t\t.then(({ svg }) => {\n\t\t\t\t\tif (!cancelled && ref.current) {\n\t\t\t\t\t\tref.current.innerHTML = svg\n\t\t\t\t\t\tlatestOnSvg.current?.(svg)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tif (!cancelled && ref.current) {\n\t\t\t\t\t\tref.current.innerHTML = `<pre style='color:red'>${String(err)}</pre>`\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t})\n\t\treturn () => {\n\t\t\tcancelled = true\n\t\t}\n\t}, [code, id])\n\treturn (\n\t\t<div className=\"mermaid not-prose\">\n\t\t\t<div ref={ref} />\n\t\t</div>\n\t)\n}\n","import { clsx } from 'clsx'\nimport { LRUCache } from 'lru-cache'\nimport { type MDXContentProps } from 'mdx-bundler/client'\nimport * as mdxBundler from 'mdx-bundler/client'\nimport { useEffect, useMemo, useState } from 'react'\nimport { Link, useLoaderData } from 'react-router'\nimport { toast } from 'sonner'\nimport { DeferredEpicVideo, VideoEmbed } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Mermaid } from '#app/components/mermaid.tsx'\nimport { type loader } from '#app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/_layout.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { AnchorOrLink, Heading, cn } from './misc.tsx'\n\nconst safePath = (s: string) => s.replace(/\\\\/g, '/')\n\nfunction getRelativePath(file: string, separator: string, type?: string) {\n\tconst [, relativePath] = file\n\t\t.replace(/\\\\|\\//g, separator)\n\t\t.split(`${type === 'playground' ? 'example' : 'exercises'}${separator}`)\n\treturn relativePath\n}\n\nconst buttonClassName =\n\t'border-border bg-[var(--shiki-background)] hover:bg-foreground/20 active:bg-foreground/30 box-content block rounded border-2 px-2 py-0.5 font-mono text-xs font-semibold outline-none transition duration-300 ease-in-out'\n\ntype DataProps = {\n\t'data-buttons'?: string\n\t'data-filename'?: string\n\t'data-fullpath'?: string\n\t'data-nocopy'?: string\n\t'data-sep'?: string\n\t'data-start'?: string\n\t'data-type'?: string\n}\n\nfunction OpenInEditor({\n\t'data-buttons': buttons,\n\t'data-filename': filename,\n\t'data-fullpath': fullPath,\n\t'data-sep': separator = '/',\n\t'data-start': start,\n\t'data-type': type,\n}: DataProps) {\n\tconst data = useLoaderData<typeof loader>()\n\n\tif (type === 'other' || !buttons || !filename || !fullPath) return null\n\n\tconst currentAppFullPath = safePath(data[data.type]?.fullPath ?? '')\n\tconst isFileFromDifferentApp = !fullPath.startsWith(currentAppFullPath)\n\tconst validButtons = ENV.EPICSHOP_DEPLOYED\n\t\t? (['problem', 'solution'] as const)\n\t\t: (['problem', 'solution', 'playground'] as const)\n\tconst buttonList = buttons.split(',')\n\tconst apps = validButtons.filter((button) => buttonList.includes(button))\n\n\treturn (\n\t\t<>\n\t\t\t{apps.map((type) => {\n\t\t\t\tconst app = data[type]\n\t\t\t\tif (type === 'playground') {\n\t\t\t\t\tconst isDifferentApp =\n\t\t\t\t\t\tdata.playground && data.playground.appName !== data.problem?.name\n\t\t\t\t\tif (!app || isDifferentApp || isFileFromDifferentApp) {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tkey={type}\n\t\t\t\t\t\t\t\tclassName={clsx(buttonClassName, 'cursor-not-allowed')}\n\t\t\t\t\t\t\t\ttitle={\n\t\t\t\t\t\t\t\t\tisDifferentApp\n\t\t\t\t\t\t\t\t\t\t? 'Playground is not set to the right app'\n\t\t\t\t\t\t\t\t\t\t: isFileFromDifferentApp\n\t\t\t\t\t\t\t\t\t\t\t? 'This file is from different app'\n\t\t\t\t\t\t\t\t\t\t\t: \"You must 'Set to Playground' before opening a file\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"uppercase\">Open</span> in {type}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!app || !app.fullPath) {\n\t\t\t\t\t// unexpected\n\t\t\t\t\treturn null\n\t\t\t\t}\n\n\t\t\t\tconst file = [safePath(app.fullPath), safePath(filename)].join(\n\t\t\t\t\tseparator,\n\t\t\t\t)\n\t\t\t\tconst fixedTitle = getRelativePath(file, separator, type)\n\t\t\t\treturn (\n\t\t\t\t\t<LaunchEditor key={type} file={file} line={Number(start ?? 1)}>\n\t\t\t\t\t\t<span title={fixedTitle} className={buttonClassName}>\n\t\t\t\t\t\t\t<span className=\"uppercase\">Open</span> in {type}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</LaunchEditor>\n\t\t\t\t)\n\t\t\t})}\n\t\t</>\n\t)\n}\n\nfunction CopyButton(): React.ReactNode {\n\tconst [copied, setCopied] = useState(false)\n\n\tuseEffect(() => {\n\t\tif (copied) {\n\t\t\tconst timeoutId = setTimeout(() => setCopied(false), 1500)\n\t\t\treturn () => clearTimeout(timeoutId)\n\t\t}\n\t}, [copied])\n\n\treturn (\n\t\t<button\n\t\t\tclassName={cn(buttonClassName, 'w-12 uppercase')}\n\t\t\tonClick={async (event) => {\n\t\t\t\tif (navigator.clipboard) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst button = event.currentTarget\n\t\t\t\t\t\tconst code =\n\t\t\t\t\t\t\tbutton.parentElement?.parentElement?.querySelector('pre')\n\t\t\t\t\t\t\t\t?.textContent || ''\n\t\t\t\t\t\tawait navigator.clipboard.writeText(code)\n\t\t\t\t\t\tsetCopied(true)\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconsole.error('Failed to copy to clipboard:', error)\n\t\t\t\t\t\ttoast.error('Failed to copy to clipboard', {\n\t\t\t\t\t\t\tdescription: 'Please try again or copy the code manually.',\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttoast.error(\n\t\t\t\t\t\t'Copying is only available in secure contexts (HTTPS or localhost).',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t'Please access the workshop via localhost instead of an IP address to enable this feature.',\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}}\n\t\t>\n\t\t\t{copied ? 'copied' : 'copy'}\n\t\t</button>\n\t)\n}\n\nexport function PreWithButtons({ children, ...props }: any) {\n\tconst {\n\t\t'data-buttons': buttons,\n\t\t'data-filename': filename,\n\t\t'data-fullpath': fullPath,\n\t\t'data-nocopy': hideCopyButton,\n\t\t'data-sep': separator,\n\t} = props as DataProps\n\tconst showCopyButton = hideCopyButton === undefined\n\n\tfunction updateFilename() {\n\t\tif (fullPath && separator) {\n\t\t\tif (!filename || filename.includes('..')) {\n\t\t\t\treturn { 'data-filename': getRelativePath(fullPath, separator) }\n\t\t\t} else {\n\t\t\t\treturn { 'data-filename': filename.replace(/\\//g, separator) }\n\t\t\t}\n\t\t}\n\t}\n\n\treturn (\n\t\t<div className=\"group relative\">\n\t\t\t<div className=\"absolute top-0 right-0 z-50 m-2 flex items-baseline justify-end gap-4 opacity-0 transition duration-300 ease-in-out group-hover:opacity-100 focus-within:opacity-100\">\n\t\t\t\t{buttons ? <OpenInEditor {...props} /> : null}\n\t\t\t\t{showCopyButton ? <CopyButton /> : null}\n\t\t\t</div>\n\t\t\t<pre\n\t\t\t\t{...props}\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'scrollbar-thin scrollbar-thumb-scrollbar',\n\n\t\t\t\t\tprops.className ?? '',\n\t\t\t\t)}\n\t\t\t\t{...updateFilename()}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</pre>\n\t\t</div>\n\t)\n}\n\nexport const mdxComponents = {\n\th1: (props: any) => <Heading {...props} as=\"h1\" />,\n\th2: (props: any) => <Heading {...props} as=\"h2\" />,\n\th3: (props: any) => <Heading {...props} as=\"h3\" />,\n\th4: (props: any) => <Heading {...props} as=\"h4\" />,\n\th5: (props: any) => <Heading {...props} as=\"h5\" />,\n\th6: (props: any) => <Heading {...props} as=\"h6\" />,\n\ta: AnchorOrLink,\n\t// you can't put a <form> inside a <p> so we'll just use a div\n\t// if this is a problem, then render the form outside of the MDX and update <LaunchEditor /> to reference that one instead or something.\n\tp: (props: any) => <div {...props} />,\n\tpre: (props: any) => (\n\t\t<pre\n\t\t\t{...props}\n\t\t\tclassName={clsx(\n\t\t\t\t'scrollbar-thin scrollbar-thumb-scrollbar',\n\n\t\t\t\tprops.className ?? '',\n\t\t\t)}\n\t\t/>\n\t),\n\tLaunchEditor,\n\tVideoEmbed,\n\tEpicVideo: DeferredEpicVideo,\n\tMermaid,\n}\n\n/**\n * This should be rendered within a useMemo\n * @param code the code to get the component from\n * @returns the component\n */\nfunction getMdxComponent(code: string) {\n\tconst Component = mdxBundler.getMDXComponent(code)\n\tfunction EpicMdxComponent({\n\t\tcomponents: externalComponents,\n\t\t...rest\n\t}: Parameters<typeof Component>['0']) {\n\t\tconst components = useMemo(\n\t\t\t() => ({ ...mdxComponents, ...externalComponents }),\n\t\t\t[externalComponents],\n\t\t)\n\t\treturn <Component components={components} {...rest} />\n\t}\n\treturn EpicMdxComponent\n}\n\n// This exists so we don't have to call new Function for the given code\n// for every request for a given blog post/mdx file.\nconst mdxComponentCache = new LRUCache<\n\tstring,\n\tReturnType<typeof getMdxComponent>\n>({ max: 1000 })\n\nexport function useMdxComponent(code: string) {\n\treturn useMemo(() => {\n\t\tif (mdxComponentCache.has(code)) {\n\t\t\treturn mdxComponentCache.get(code)!\n\t\t}\n\t\tconst component = getMdxComponent(code)\n\t\tmdxComponentCache.set(code, component)\n\t\treturn component\n\t}, [code])\n}\n\nexport function Mdx({\n\tcode,\n\tcomponents: externalComponents,\n}: {\n\tcode: string\n\tcomponents?: MDXContentProps['components']\n}) {\n\tconst Component = useMdxComponent(code)\n\tconst components = useMemo(\n\t\t() => ({ Icon, pre: PreWithButtons, Link, ...externalComponents }),\n\t\t[externalComponents],\n\t)\n\treturn <Component components={components} />\n}\n","import { getExercises } from '@epic-web/workshop-utils/apps.server'\nimport type z from 'zod'\nimport { type error404Schema } from './error-boundary.tsx'\n\nexport async function getStep404Data({\n\texerciseNumber: exerciseNumberString,\n}: {\n\texerciseNumber: string\n}) {\n\t// Get exercise info for the 404 error\n\tconst exerciseNumber = Number(exerciseNumberString)\n\tlet exerciseTitle = 'Untitled Exercise'\n\tconst availableSteps: Array<{\n\t\tstepNumber: number\n\t\ttitle: string\n\t\thasProblem: boolean\n\t\thasSolution: boolean\n\t}> = []\n\n\ttry {\n\t\tconst exercises = await getExercises()\n\t\tconst exercise = exercises.find((e) => e.exerciseNumber === exerciseNumber)\n\t\tif (!exercise) {\n\t\t\treturn getExercise404Data({ exercises })\n\t\t}\n\t\texerciseTitle = exercise.title\n\t\tfor (const step of exercise.steps) {\n\t\t\tif (!step.problem && !step.solution) continue\n\n\t\t\tavailableSteps.push({\n\t\t\t\tstepNumber: step.stepNumber,\n\t\t\t\ttitle: step.problem?.title ?? step.solution?.title ?? 'Untitled Step',\n\t\t\t\thasProblem: Boolean(step.problem),\n\t\t\t\thasSolution: Boolean(step.solution),\n\t\t\t})\n\t\t}\n\t} catch {}\n\n\treturn {\n\t\ttype: 'step-not-found',\n\t\tsteps: availableSteps.sort((a, b) => a.stepNumber - b.stepNumber),\n\t\texerciseNumber,\n\t\texerciseTitle,\n\t} satisfies z.infer<typeof error404Schema>\n}\n\nexport function getExercise404Data({\n\texercises,\n}: {\n\texercises: Array<\n\t\tPick<\n\t\t\tAwaited<ReturnType<typeof getExercises>>[number],\n\t\t\t'title' | 'exerciseNumber'\n\t\t>\n\t>\n}) {\n\treturn {\n\t\ttype: 'exercise-not-found',\n\t\texercises: exercises.map((e) => ({\n\t\t\ttitle: e.title,\n\t\t\tnumber: e.exerciseNumber,\n\t\t})),\n\t} satisfies z.infer<typeof error404Schema>\n}\n","import { href, Link, type ErrorResponse } from 'react-router'\nimport z from 'zod'\n\nexport const error404Schema = z.discriminatedUnion('type', [\n\tz.object({\n\t\ttype: z.literal('step-not-found'),\n\t\tsteps: z.array(\n\t\t\tz.object({\n\t\t\t\tstepNumber: z.number(),\n\t\t\t\ttitle: z.string(),\n\t\t\t\thasProblem: z.boolean(),\n\t\t\t\thasSolution: z.boolean(),\n\t\t\t}),\n\t\t),\n\t\texerciseNumber: z.number(),\n\t\texerciseTitle: z.string(),\n\t}),\n\tz.object({\n\t\ttype: z.literal('exercise-not-found'),\n\t\texercises: z.array(\n\t\t\tz.object({\n\t\t\t\ttitle: z.string(),\n\t\t\t\tnumber: z.number(),\n\t\t\t}),\n\t\t),\n\t}),\n])\n\nexport function Exercise404ErrorBoundary({\n\terror,\n\tparams,\n}: {\n\terror: ErrorResponse\n\tparams: Record<string, string | undefined>\n}) {\n\tconsole.log(error)\n\tconst validationResult = error404Schema.safeParse(error.data)\n\tconst label = [params.exerciseNumber, params.stepNumber, params.type]\n\t\t.filter(Boolean)\n\t\t.join('.')\n\n\tif (!validationResult.success) {\n\t\tconsole.error(\n\t\t\t'Invalid 404 error response data',\n\t\t\tvalidationResult.error,\n\t\t\terror,\n\t\t)\n\t\treturn <p className=\"text-2xl font-bold\">\"{label}\" not found</p>\n\t}\n\tconst { data } = validationResult\n\tif (data.type === 'step-not-found') {\n\t\tconst { steps, exerciseNumber } = data\n\n\t\treturn (\n\t\t\t<div className=\"prose\">\n\t\t\t\t<p className=\"text-2xl font-bold\">Step not found for \"{label}\"</p>\n\t\t\t\t{steps.length > 0 ? (\n\t\t\t\t\t<div className=\"text-lg\">\n\t\t\t\t\t\t<p id=\"available-steps-heading\">Available Steps:</p>\n\t\t\t\t\t\t<ul\n\t\t\t\t\t\t\tclassName=\"m-0 list-inside list-none pl-4\"\n\t\t\t\t\t\t\taria-labelledby=\"available-steps-heading\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{steps.map((step) => (\n\t\t\t\t\t\t\t\t<li key={step.stepNumber} className=\"mb-2\">\n\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">\n\t\t\t\t\t\t\t\t\t\t{step.stepNumber}. {step.title}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t<div className=\"ml-4 flex gap-4\">\n\t\t\t\t\t\t\t\t\t\t{step.hasProblem ? (\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={href(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'/exercise/:exerciseNumber/:stepNumber/:type',\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber: String(exerciseNumber).padStart(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber: String(step.stepNumber).padStart(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t💪 Problem\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t{step.hasSolution ? (\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={href(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'/exercise/:exerciseNumber/:stepNumber/:type',\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber: String(exerciseNumber).padStart(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber: String(step.stepNumber).padStart(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t🏁 Solution\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t) : (\n\t\t\t\t\t<p>\n\t\t\t\t\t\tNo steps are available for this exercise.{' '}\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tto={href('/exercise/:exerciseNumber', {\n\t\t\t\t\t\t\t\texerciseNumber: String(exerciseNumber).padStart(2, '0'),\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tView Exercise\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t)\n\t} else if (data.type === 'exercise-not-found') {\n\t\tconst { exercises } = data\n\t\treturn (\n\t\t\t<div className=\"prose\">\n\t\t\t\t<p className=\"text-2xl font-bold\">Exercise not found for \"{label}\"</p>\n\t\t\t\t<div className=\"text-lg\">\n\t\t\t\t\t<p id=\"available-exercises-heading\">Available Exercises:</p>\n\t\t\t\t\t<ul\n\t\t\t\t\t\tclassName=\"m-0 list-inside list-none pl-4\"\n\t\t\t\t\t\taria-labelledby=\"available-exercises-heading\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{exercises.map((exercise) => (\n\t\t\t\t\t\t\t<li key={exercise.number}>\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={href('/exercise/:exerciseNumber', {\n\t\t\t\t\t\t\t\t\t\texerciseNumber: String(exercise.number).padStart(2, '0'),\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{exercise.number}. {exercise.title}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\tthrow new Error(`Unknown error type: ${(data as any).type}`)\n\t}\n}\n","import path from 'path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopRoot,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { type Route } from './+types/$exerciseNumber.tsx'\nimport { getExercise404Data } from './__shared/error-boundary.server.ts'\nimport { Exercise404ErrorBoundary } from './__shared/error-boundary.tsx'\n\nexport const meta: Route.MetaFunction = ({ loaderData, matches }) => {\n\tconst number = loaderData?.exercise.exerciseNumber.toString().padStart(2, '0')\n\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!loaderData || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `📝 | ${number}. ${loaderData.exercise.title} | ${rootData?.workshopTitle}`,\n\t\tdescription: `Introduction for ${number}. ${loaderData.exercise.title}`,\n\t\togTitle: loaderData.exercise.title,\n\t\togDescription: `Introduction for exercise ${Number(number)}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('exerciseNumberLoader')\n\tinvariantResponse(params.exerciseNumber, 'exerciseNumber is required')\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst exercises = await time(() => getExercises({ request, timings }), {\n\t\ttimings,\n\t\ttype: 'getExercises',\n\t\tdesc: 'getExercises in $exerciseNumber.tsx',\n\t})\n\tconst exercise = exercises.find(\n\t\t(e) => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tif (!exercise) {\n\t\tthrow Response.json(getExercise404Data({ exercises }), { status: 404 })\n\t}\n\n\tconst readmeFilepath = path.join(\n\t\tgetWorkshopRoot(),\n\t\t'exercises',\n\t\texercise.dirName,\n\t\t'README.mdx',\n\t)\n\n\tconst firstStep = exercise.steps.find(Boolean)\n\n\tconst articleId = `workshop-${slugify(workshopTitle)}-${\n\t\texercise.exerciseNumber\n\t}-instructions`\n\n\treturn data(\n\t\t{\n\t\t\tarticleId,\n\t\t\texercise,\n\t\t\texerciseNumber: exercise.exerciseNumber,\n\t\t\texerciseReadme: {\n\t\t\t\tfile: readmeFilepath,\n\t\t\t\trelativePath: `exercises/${exercise.dirName}/README.mdx`,\n\t\t\t},\n\t\t\texerciseTitle: exercise.title,\n\t\t\tfirstStep,\n\t\t\tfirstType: firstStep?.problem ? 'problem' : 'solution',\n\t\t\ttitle: workshopTitle,\n\t\t\tepicVideoInfosPromise: getEpicVideoInfos(\n\t\t\t\texercise.instructionsEpicVideoEmbeds,\n\t\t\t\t{ request },\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\n// we'll render the title ourselves thank you\nconst mdxComponents = { h1: () => null }\n\nexport default function ExerciseNumberRoute({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tuseRevalidationWS({\n\t\twatchPaths: [data.exerciseReadme.file],\n\t})\n\n\tconst firstStepNumber = String(data.firstStep?.stepNumber ?? '01').padStart(\n\t\t2,\n\t\t'0',\n\t)\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tkey={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold\">\n\t\t\t\t\t\t{data.exercise.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t{data.exercise.instructionsCode ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.exercise.instructionsCode}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No instructions yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration\n\t\t\t\telementQuery={`#${data.articleId}`}\n\t\t\t\tkey={`scroll-${data.articleId}`}\n\t\t\t/>\n\t\t\t<ProgressToggle\n\t\t\t\ttype=\"instructions\"\n\t\t\t\texerciseNumber={data.exerciseNumber}\n\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t/>\n\t\t\t<div className=\"flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t<div />\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.exerciseReadme.file}\n\t\t\t\t\trelativePath={data.exerciseReadme.relativePath}\n\t\t\t\t/>\n\t\t\t\t<Link\n\t\t\t\t\tto={`${firstStepNumber}/${data.firstType}`}\n\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\tclassName=\"bg-foreground text-background flex h-full items-center justify-center px-7\"\n\t\t\t\t\tdata-keyboard-action=\"g+n\"\n\t\t\t\t>\n\t\t\t\t\tStart Learning\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tclassName=\"container flex items-center justify-center\"\n\t\t\tstatusHandlers={{\n\t\t\t\t404: Exercise404ErrorBoundary,\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import { Link, type LinkProps } from 'react-router'\nimport { Icon } from './icons.tsx'\n\nexport function NavChevrons({\n\tprev,\n\tnext,\n}: {\n\tprev?: LinkProps | null\n\tnext?: LinkProps | null\n}) {\n\treturn (\n\t\t<div className=\"relative flex h-full overflow-hidden\">\n\t\t\t{prev ? (\n\t\t\t\t<Link\n\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t{...prev}\n\t\t\t\t\tdata-keyboard-action=\"g+p\"\n\t\t\t\t\tclassName=\"group flex h-full items-center justify-center border-l px-7\"\n\t\t\t\t\tchildren={\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"ChevronLeft\"\n\t\t\t\t\t\t\t\tclassName=\"absolute opacity-100 transition duration-300 ease-in-out group-hover:translate-y-10 group-hover:opacity-0\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"ChevronLeft\"\n\t\t\t\t\t\t\t\tclassName=\"absolute -translate-y-10 opacity-0 transition duration-300 ease-in-out group-hover:translate-y-0 group-hover:opacity-100\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t{next ? (\n\t\t\t\t<Link\n\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t{...next}\n\t\t\t\t\tdata-keyboard-action=\"g+n\"\n\t\t\t\t\tclassName=\"group flex h-full items-center justify-center border-l px-7\"\n\t\t\t\t\tchildren={\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"ChevronRight\"\n\t\t\t\t\t\t\t\tclassName=\"absolute opacity-100 transition duration-300 ease-in-out group-hover:translate-y-10 group-hover:opacity-0\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"ChevronRight\"\n\t\t\t\t\t\t\t\tclassName=\"absolute -translate-y-10 opacity-0 transition duration-300 ease-in-out group-hover:translate-y-0 group-hover:opacity-100\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t</div>\n\t)\n}\n","import {\n\tgetAppByName,\n\tgetApps,\n\tisPlaygroundApp,\n\tisProblemApp,\n\tisSolutionApp,\n\tsetPlayground,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport * as Select from '@radix-ui/react-select'\nimport { clsx } from 'clsx'\nimport { type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { z } from 'zod'\nimport { Icon } from '#app/components/icons.tsx'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { ensureUndeployed, getErrorMessage } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nconst SetPlaygroundSchema = z.object({\n\tappName: z.string(),\n\treset: z\n\t\t.string()\n\t\t.nullable()\n\t\t.optional()\n\t\t.transform((v) => v === 'true'),\n})\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst rawData = {\n\t\tappName: formData.get('appName'),\n\t\tredirectTo: formData.get('redirectTo'),\n\t}\n\tconst result = SetPlaygroundSchema.safeParse(rawData)\n\tif (!result.success) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ status: 'error', error: result.error.message } as const,\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\tconst form = result.data\n\tconst app = await getAppByName(form.appName)\n\tif (!app) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ status: 'error', error: `App ${form.appName} not found` } as const,\n\t\t\t{ status: 404 },\n\t\t)\n\t}\n\tconst converseApp =\n\t\tisProblemApp(app) && app.solutionName\n\t\t\t? await getAppByName(app.solutionName)\n\t\t\t: isSolutionApp(app) && app.problemName\n\t\t\t\t? await getAppByName(app.problemName)\n\t\t\t\t: undefined\n\ttry {\n\t\tawait setPlayground(app.fullPath, { reset: form.reset })\n\t} catch (error: unknown) {\n\t\tconst message = getErrorMessage(error)\n\t\tconsole.error('Error setting playground', message)\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ status: 'error', error: message } as const,\n\t\t\t{\n\t\t\t\tstatus: 500,\n\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\ttitle: 'Error',\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'There was an error setting the playground. Check the terminal for details.',\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t}\n\tconst apps = await getApps({ forceFresh: true })\n\tconst playground = apps.find(isPlaygroundApp)\n\tif (playground && converseApp) {\n\t\tvoid getDiffCode(playground, converseApp, { forceFresh: true })\n\t}\n\treturn dataWithPE(request, formData, { status: 'success' } as const)\n}\n\nexport function SetPlayground({\n\tappName,\n\treset = false,\n\ttooltipText,\n\t...buttonProps\n}: {\n\tappName: string\n\ttooltipText?: string\n\treset?: boolean\n} & React.ComponentProps<'button'>) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\n\tconst submitButton = (\n\t\t<button\n\t\t\ttype=\"submit\"\n\t\t\t{...buttonProps}\n\t\t\tclassName={clsx(\n\t\t\t\tbuttonProps.className,\n\t\t\t\tfetcher.state !== 'idle' ? 'cursor-progress' : null,\n\t\t\t\tfetcher.data?.status === 'error' ? 'cursor-not-allowed' : null,\n\t\t\t)}\n\t\t/>\n\t)\n\treturn (\n\t\t<fetcher.Form\n\t\t\taction=\"/set-playground\"\n\t\t\tmethod=\"POST\"\n\t\t\tclassName=\"inline-flex items-center justify-center\"\n\t\t>\n\t\t\t{peRedirectInput}\n\t\t\t<input type=\"hidden\" name=\"appName\" value={appName} />\n\t\t\t{reset ? <input type=\"hidden\" name=\"reset\" value=\"true\" /> : null}\n\t\t\t{showProgressBarField}\n\t\t\t{tooltipText ? (\n\t\t\t\t<SimpleTooltip content={tooltipText}>{submitButton}</SimpleTooltip>\n\t\t\t) : (\n\t\t\t\tsubmitButton\n\t\t\t)}\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function PlaygroundChooser({\n\tplaygroundAppName,\n\tallApps,\n}: {\n\tplaygroundAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\treturn (\n\t\t<Select.Root\n\t\t\tname=\"appName\"\n\t\t\tvalue={playgroundAppName}\n\t\t\tonValueChange={(appName) => {\n\t\t\t\tvoid fetcher.submit(\n\t\t\t\t\t{ appName },\n\t\t\t\t\t{ method: 'POST', action: '/set-playground' },\n\t\t\t\t)\n\t\t\t}}\n\t\t>\n\t\t\t<Select.Trigger\n\t\t\t\taria-label=\"Select app for playground\"\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'radix-placeholder:text-gray-500 flex h-full w-full items-center justify-between text-left focus-visible:outline-none',\n\t\t\t\t\tfetcher.state !== 'idle' ? 'cursor-progress' : null,\n\t\t\t\t\tfetcher.data?.status === 'error' ? 'cursor-not-allowed' : null,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<span className=\"scrollbar-thin scrollbar-thumb-scrollbar w-80 flex-1 overflow-hidden text-ellipsis whitespace-nowrap\">\n\t\t\t\t\t<Select.Value\n\t\t\t\t\t\tplaceholder=\"Select current app\"\n\t\t\t\t\t\tclassName=\"inline-block w-40 text-ellipsis\"\n\t\t\t\t\t/>\n\t\t\t\t</span>\n\t\t\t\t<Select.Icon>\n\t\t\t\t\t<Icon name=\"TriangleDownSmall\" />\n\t\t\t\t</Select.Icon>\n\t\t\t</Select.Trigger>\n\t\t\t<Select.Portal>\n\t\t\t\t<Select.Content\n\t\t\t\t\tposition=\"popper\"\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]\"\n\t\t\t\t>\n\t\t\t\t\t<Select.ScrollUpButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronUp\" />\n\t\t\t\t\t</Select.ScrollUpButton>\n\t\t\t\t\t<Select.Viewport className=\"p-3\">\n\t\t\t\t\t\t<Select.Group>\n\t\t\t\t\t\t\t<Select.Label className=\"px-5 pb-3 font-mono uppercase\">\n\t\t\t\t\t\t\t\tApp\n\t\t\t\t\t\t\t</Select.Label>\n\t\t\t\t\t\t\t{allApps\n\t\t\t\t\t\t\t\t.filter((app) => app.name !== 'playground')\n\t\t\t\t\t\t\t\t.map((app) => {\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<SelectItem key={app.name} value={app.name}>\n\t\t\t\t\t\t\t\t\t\t\t{app.displayName}\n\t\t\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</Select.Group>\n\t\t\t\t\t</Select.Viewport>\n\t\t\t\t\t<Select.ScrollDownButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronDown\" />\n\t\t\t\t\t</Select.ScrollDownButton>\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Portal>\n\t\t</Select.Root>\n\t)\n}\n\nfunction SelectItem({\n\tvalue,\n\tchildren,\n}: {\n\tvalue: string\n\tchildren: React.ReactNode\n}) {\n\treturn (\n\t\t<Select.Item\n\t\t\tvalue={value}\n\t\t\tclassName=\"radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100 relative flex cursor-pointer items-center rounded px-10 py-2 leading-none opacity-80 select-none\"\n\t\t>\n\t\t\t<Select.ItemText>{children}</Select.ItemText>\n\t\t\t<Select.ItemIndicator className=\"absolute left-0 inline-flex w-[25px] items-center justify-center\">\n\t\t\t\t<Icon name=\"CheckSmall\" />\n\t\t\t</Select.ItemIndicator>\n\t\t</Select.Item>\n\t)\n}\n\nexport function SetAppToPlayground({\n\tappName,\n\tisOutdated,\n}: {\n\tappName: string\n\tisOutdated?: boolean\n}) {\n\tif (ENV.EPICSHOP_DEPLOYED) return null\n\treturn (\n\t\t<SetPlayground\n\t\t\tappName={appName}\n\t\t\ttooltipText={\n\t\t\t\tisOutdated\n\t\t\t\t\t? 'The app the playground was set to has been updated. Click to update to the latest version.'\n\t\t\t\t\t: 'Playground is not set to the right app. Click to set Playground.'\n\t\t\t}\n\t\t>\n\t\t\t<span className=\"text-foreground-destructive flex items-center justify-center gap-1 hover:underline\">\n\t\t\t\t<Icon name=\"Unlinked\" className=\"animate-ping\" />{' '}\n\t\t\t\t<span className=\"uppercase\">\n\t\t\t\t\t{isOutdated ? 'Playground Outdated' : 'Set to Playground'}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</SetPlayground>\n\t)\n}\n","import * as React from 'react'\nimport { type PropsWithChildren } from 'react'\nimport {\n\tLink,\n\tuseLoaderData,\n\tuseSearchParams,\n\ttype LinkProps,\n} from 'react-router'\nimport iconsSvg from '#app/assets/icons.svg'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { type loader } from '../_layout.tsx'\n\ntype StepContextType = {\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}\nconst StepContext = React.createContext<StepContextType | null>(null)\n\nfunction useStepContext() {\n\tconst context = React.useContext(StepContext)\n\tif (!context) {\n\t\tthrow new Error('useStepContext must be used within a StepContextProvider')\n\t}\n\treturn context\n}\n\nfunction StepContextProvider({\n\tchildren,\n\tinBrowserBrowserRef,\n}: {\n\tchildren: React.ReactNode\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\treturn <StepContext value={{ inBrowserBrowserRef }}>{children}</StepContext>\n}\n\nconst stepMdxComponents = {\n\tDiffLink,\n\tPrevDiffLink,\n\tNextDiffLink,\n\tInlineFile,\n\tLinkToApp,\n}\n\nexport function StepMdx({\n\tinBrowserBrowserRef,\n}: {\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tif (!data.exerciseStepApp.instructionsCode) return null\n\treturn (\n\t\t<StepContextProvider inBrowserBrowserRef={inBrowserBrowserRef}>\n\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={data.epicVideoInfosPromise}>\n\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t<Mdx\n\t\t\t\t\t\tcode={data.exerciseStepApp.instructionsCode}\n\t\t\t\t\t\tcomponents={stepMdxComponents}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</EpicVideoInfoProvider>\n\t\t</StepContextProvider>\n\t)\n}\n\nfunction withParam(\n\tsearchParams: URLSearchParams,\n\tkey: string,\n\tvalue: string | null,\n) {\n\tconst newSearchParams = new URLSearchParams(searchParams)\n\tif (value === null) {\n\t\tnewSearchParams.delete(key)\n\t} else {\n\t\tnewSearchParams.set(key, value)\n\t}\n\treturn newSearchParams\n}\n\nfunction NextDiffLink({\n\tapp = 0,\n\tfullPage = false,\n\tchildren,\n}: {\n\tapp: number\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\treturn (\n\t\t<DiffLink app1={app} app2={app + 1} fullPage={fullPage}>\n\t\t\t{children}\n\t\t</DiffLink>\n\t)\n}\n\nfunction PrevDiffLink({\n\tapp = -1,\n\tfullPage = false,\n\tchildren,\n}: {\n\tapp: number\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\treturn (\n\t\t<DiffLink app1={app} app2={app + 1} fullPage={fullPage}>\n\t\t\t{children}\n\t\t</DiffLink>\n\t)\n}\n\nfunction DiffLink({\n\tapp1 = 0,\n\tapp2 = 1,\n\tchildren,\n\tfullPage = false,\n\tto,\n}: {\n\tapp1?: string | number | null\n\tapp2?: string | number | null\n\tto?: string\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tif (!to && !app1 && !app2) {\n\t\treturn (\n\t\t\t<callout-danger className=\"notification\">\n\t\t\t\t<div className=\"title\">DiffLink Error: invalid input</div>\n\t\t\t</callout-danger>\n\t\t)\n\t}\n\n\tfunction getAppName(input: typeof app1) {\n\t\tif (typeof input === 'number') {\n\t\t\tconst stepIndex = data.exerciseIndex + input\n\t\t\treturn data.allApps[stepIndex]?.name\n\t\t}\n\t\tif (!input) return null\n\t\tfor (const { name, stepName } of data.allApps) {\n\t\t\tif (input === name || input === stepName) {\n\t\t\t\treturn name\n\t\t\t}\n\t\t}\n\t\treturn null\n\t}\n\n\tif (to) {\n\t\tconst params = new URLSearchParams(to)\n\t\tapp1 = params.get('app1')\n\t\tapp2 = params.get('app2')\n\t}\n\tconst app1Name = getAppName(app1)\n\tconst app2Name = getAppName(app2)\n\tif (!app1Name || !app2Name) {\n\t\treturn (\n\t\t\t<callout-danger className=\"notification\">\n\t\t\t\t<div className=\"title\">DiffLink Error: invalid input</div>\n\t\t\t\t{!app1Name && <div>app1: \"{app1}\" is not a valid app name</div>}\n\t\t\t\t{!app2Name && <div>app2: \"{app2}\" is not a valid app name</div>}\n\t\t\t</callout-danger>\n\t\t)\n\t}\n\n\tif (!to) {\n\t\tto = `app1=${app1Name}&app2=${app2Name}`\n\t}\n\tconst pathToDiff = fullPage\n\t\t? `/diff?${to}`\n\t\t: `?${decodeURIComponent(\n\t\t\t\twithParam(new URLSearchParams(), 'preview', `diff&${to}`).toString(),\n\t\t\t)}`\n\n\tif (!children) {\n\t\tchildren = (\n\t\t\t<span>\n\t\t\t\tGo to Diff {fullPage ? '' : 'Preview'} from: <code>{app1Name}</code> to:{' '}\n\t\t\t\t<code>{app2Name}</code>\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn <Link to={pathToDiff}>{children}</Link>\n}\n\nfunction InlineFile({\n\tfile,\n\ttype = 'playground',\n\tchildren = <code>{file}</code>,\n\t...props\n}: Omit<PropsWithChildren<typeof LaunchEditor>, 'appName'> & {\n\tfile: string\n\ttype?: 'playground' | 'solution' | 'problem'\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst app = data[type] || data[data.type]\n\n\tconst info = (\n\t\t<div className=\"launch-editor-button-wrapper flex underline underline-offset-4\">\n\t\t\t{children}{' '}\n\t\t\t<svg height={24} width={24}>\n\t\t\t\t<use href={`${iconsSvg}#Keyboard`} />\n\t\t\t</svg>\n\t\t</div>\n\t)\n\n\treturn ENV.EPICSHOP_DEPLOYED && app ? (\n\t\t<div className=\"inline-block grow\">\n\t\t\t<LaunchEditor appFile={file} appName={app.name} {...props}>\n\t\t\t\t{info}\n\t\t\t</LaunchEditor>\n\t\t</div>\n\t) : app ? (\n\t\t<div className=\"inline-block grow\">\n\t\t\t<LaunchEditor appFile={file} appName={app.name} {...props}>\n\t\t\t\t{info}\n\t\t\t</LaunchEditor>\n\t\t</div>\n\t) : type === 'playground' ? (\n\t\t// playground does not exist yet\n\t\t<SimpleTooltip content=\"You must 'Set to Playground' before opening a file\">\n\t\t\t<div className=\"inline-block grow cursor-not-allowed\">{info}</div>\n\t\t</SimpleTooltip>\n\t) : (\n\t\t<>children</>\n\t)\n}\n\nfunction getPreviewType(\n\tpreview: string | null,\n): 'playground' | 'problem' | 'solution' {\n\tif (preview === 'problem') return 'problem'\n\tif (preview === 'solution') return 'solution'\n\treturn 'playground'\n}\n\nfunction LinkToApp({\n\tto: appTo,\n\tchildren = <code>{appTo.toString()}</code>,\n\t...props\n}: LinkProps) {\n\tconst [searchParams] = useSearchParams()\n\tconst to = `?${withParam(\n\t\tsearchParams,\n\t\t'pathname',\n\t\tappTo.toString(),\n\t).toString()}`\n\tconst data = useLoaderData<typeof loader>()\n\tconst type = getPreviewType(searchParams.get('preview'))\n\tconst requestInfo = useRequestInfo()\n\tconst app = data[type]\n\tconst previewAppUrl =\n\t\tapp?.dev.type === 'script'\n\t\t\t? getBaseUrl({\n\t\t\t\t\tdomain: requestInfo.domain,\n\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t})\n\t\t\t: data.playground?.dev.type === 'browser'\n\t\t\t\t? data.playground.dev.pathname\n\t\t\t\t: null\n\tconst { inBrowserBrowserRef } = useStepContext()\n\tconst href = previewAppUrl\n\t\t? previewAppUrl.slice(0, -1) + appTo.toString()\n\t\t: null\n\treturn (\n\t\t<div className=\"inline-flex items-center justify-between gap-1\">\n\t\t\t<Link\n\t\t\t\tto={to}\n\t\t\t\t{...props}\n\t\t\t\tclassName={cn(props.className, {\n\t\t\t\t\t'cursor-not-allowed': ENV.EPICSHOP_DEPLOYED,\n\t\t\t\t})}\n\t\t\t\ttitle={\n\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t? 'Cannot link to app in deployed version'\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\tif (ENV.EPICSHOP_DEPLOYED) event.preventDefault()\n\n\t\t\t\t\tprops.onClick?.(event)\n\t\t\t\t\tinBrowserBrowserRef.current?.handleExtrnalNavigation(appTo.toString())\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Link>\n\t\t\t{href ? (\n\t\t\t\t<SimpleTooltip content=\"Open in new tab\">\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={href}\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\tclassName={cn('flex aspect-square items-center justify-center', {\n\t\t\t\t\t\t\t'cursor-not-allowed': ENV.EPICSHOP_DEPLOYED,\n\t\t\t\t\t\t})}\n\t\t\t\t\t\ttitle={\n\t\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t\t? 'Cannot link to app in deployed version'\n\t\t\t\t\t\t\t\t: 'Open in new tab'\n\t\t\t\t\t\t}\n\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\tif (ENV.EPICSHOP_DEPLOYED) event.preventDefault()\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t</a>\n\t\t\t\t</SimpleTooltip>\n\t\t\t) : null}\n\t\t</div>\n\t)\n}\n","import * as Popover from '@radix-ui/react-popover'\nimport * as React from 'react'\nimport { Await, useLoaderData } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { SetAppToPlayground } from '#app/routes/set-playground.tsx'\nimport { type Route as LayoutRoute } from '../+types/_layout.tsx'\n\nfunction TouchedFiles({\n\tdiffFilesPromise,\n\tcompact = false,\n}: {\n\tdiffFilesPromise: LayoutRoute.ComponentProps['loaderData']['diffFiles']\n\tcompact?: boolean\n}) {\n\tconst data = useLoaderData<LayoutRoute.ComponentProps['loaderData']>()\n\n\tconst [open, setOpen] = React.useState(false)\n\tconst contentRef = React.useRef<HTMLDivElement>(null)\n\n\tfunction handleLaunchUpdate() {\n\t\tsetOpen(false)\n\t}\n\n\tconst appName = data.playground?.appName\n\n\treturn (\n\t\t<>\n\t\t\t<Popover.Root open={open} onOpenChange={setOpen}>\n\t\t\t\t<Popover.Trigger asChild>\n\t\t\t\t\t<button\n\t\t\t\t\t\tclassName=\"flex h-full items-center gap-1 border-r px-6 py-3 font-mono text-sm uppercase\"\n\t\t\t\t\t\taria-label=\"Relevant Files\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Files\" />\n\t\t\t\t\t\t{compact ? null : <span className=\"hidden xl:inline\">Files</span>}\n\t\t\t\t\t</button>\n\t\t\t\t</Popover.Trigger>\n\t\t\t\t<Popover.Portal>\n\t\t\t\t\t<Popover.Content\n\t\t\t\t\t\tref={contentRef}\n\t\t\t\t\t\tclassName=\"slideRightContent lg:slideUpContent invert-theme bg-background text-foreground z-10 rounded px-9 py-8 select-none\"\n\t\t\t\t\t\talign=\"start\"\n\t\t\t\t\t\tsideOffset={5}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"launch-editor-wrapper\">\n\t\t\t\t\t\t\t<strong className=\"inline-block px-2 pb-4 font-semibold uppercase\">\n\t\t\t\t\t\t\t\tRelevant Files\n\t\t\t\t\t\t\t</strong>\n\t\t\t\t\t\t\t{data.problem &&\n\t\t\t\t\t\t\tdata.playground?.appName !== data.problem.name ? (\n\t\t\t\t\t\t\t\t<div className=\"mb-2 rounded p-1 font-mono font-medium\">\n\t\t\t\t\t\t\t\t\t<SetAppToPlayground appName={data.problem.name} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<div id=\"files\">\n\t\t\t\t\t\t\t\t<React.Suspense\n\t\t\t\t\t\t\t\t\tfallback={\n\t\t\t\t\t\t\t\t\t\t<SimpleTooltip content=\"Loading diff\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex justify-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"h-8 w-8 animate-spin\" />\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Await\n\t\t\t\t\t\t\t\t\t\tresolve={diffFilesPromise}\n\t\t\t\t\t\t\t\t\t\terrorElement={\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\tSomething went wrong.\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{(diffFiles) => {\n\t\t\t\t\t\t\t\t\t\t\tif (!diffFiles) {\n\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tUnable to determine diff\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tif (typeof diffFiles === 'string') {\n\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tif (!diffFiles.length) {\n\t\t\t\t\t\t\t\t\t\t\t\treturn <p>No files changed</p>\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tconst props =\n\t\t\t\t\t\t\t\t\t\t\t\tappName || ENV.EPICSHOP_GITHUB_ROOT\n\t\t\t\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"You must 'Set to Playground' before opening a file\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName: 'not-allowed',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<ul {...props}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles.length > 1 && !ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"border-opacity-50 mb-2 border-b border-b-gray-50 pb-2 font-sans\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappFile={diffFiles.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(file) => `${file.path},${file.line},1`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappName=\"playground\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonUpdate={handleLaunchUpdate}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<p>Open All Files</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles.map((file) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li key={file.path} data-state={file.status}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappFile={`${file.path},${file.line},1`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappName={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? (data.problem?.name ?? 'playground')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'playground'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonUpdate={handleLaunchUpdate}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<code>{file.path}</code>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t</Await>\n\t\t\t\t\t\t\t\t</React.Suspense>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</Popover.Content>\n\t\t\t\t</Popover.Portal>\n\t\t\t</Popover.Root>\n\t\t</>\n\t)\n}\n\nexport default TouchedFiles\n","import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetAppDisplayName,\n\tgetAppPageRoute,\n\tgetApps,\n\tgetExerciseApp,\n\tgetNextExerciseApp,\n\tgetPrevExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExercise,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getDiffFiles } from '@epic-web/workshop-utils/diff.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport * as cookie from 'cookie'\nimport { useEffect, useRef, useState } from 'react'\nimport {\n\tLink,\n\tOutlet,\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n} from 'react-router'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { SetAppToPlayground } from '#app/routes/set-playground.tsx'\nimport { getExercisePath } from '#app/utils/misc.tsx'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { getStep404Data } from '../__shared/error-boundary.server.ts'\nimport { Exercise404ErrorBoundary } from '../__shared/error-boundary.tsx'\nimport { type Route } from './+types/_layout.tsx'\nimport { StepMdx } from './__shared/step-mdx.tsx'\nimport TouchedFiles from './__shared/touched-files.tsx'\n\n// shared split state helpers\nconst splitCookieName = 'es_split_pct'\n\nfunction computeSplitPercent(input: unknown, defaultValue = 50): number {\n\tconst value = typeof input === 'number' ? input : Number(input)\n\tif (Number.isFinite(value)) {\n\t\treturn Math.min(80, Math.max(20, Math.round(value * 100) / 100))\n\t}\n\treturn defaultValue\n}\n\nfunction pageTitle(\n\tdata: Awaited<Route.ComponentProps['loaderData']> | undefined,\n\tworkshopTitle?: string,\n) {\n\tconst exerciseNumber =\n\t\tdata?.exerciseStepApp.exerciseNumber.toString().padStart(2, '0') ?? '00'\n\tconst stepNumber =\n\t\tdata?.exerciseStepApp.stepNumber.toString().padStart(2, '0') ?? '00'\n\tconst emoji = (\n\t\t{\n\t\t\tproblem: '💪',\n\t\t\tsolution: '🏁',\n\t\t} as const\n\t)[data?.type ?? 'problem']\n\tconst title = data?.[data.type]?.title ?? 'N/A'\n\treturn {\n\t\temoji,\n\t\tstepNumber,\n\t\ttitle,\n\t\texerciseNumber,\n\t\texerciseTitle: data?.exerciseTitle ?? 'Unknown exercise',\n\t\tworkshopTitle,\n\t\ttype: data?.type ?? 'problem',\n\t}\n}\n\nexport const meta: Route.MetaFunction = ({ loaderData, matches, params }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!loaderData || !rootData) return [{ title: '🦉 | Error' }]\n\tconst { emoji, stepNumber, title, exerciseNumber, exerciseTitle } =\n\t\tpageTitle(loaderData)\n\n\treturn getSeoMetaTags({\n\t\ttitle: `${emoji} | ${stepNumber}. ${title} | ${exerciseNumber}. ${exerciseTitle} | ${rootData.workshopTitle}`,\n\t\tdescription: `${params.type} step for exercise ${exerciseNumber}. ${exerciseTitle}`,\n\t\togTitle: title,\n\t\togDescription: `${exerciseTitle} step ${Number(stepNumber)} ${params.type}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('exerciseStepTypeLayoutLoader')\n\tconst url = new URL(request.url)\n\tconst { type } = params\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\n\tconst cacheOptions = { request, timings }\n\n\tconst [allAppsFull, problemApp, solutionApp] = await Promise.all([\n\t\tgetApps(cacheOptions),\n\t\tgetExerciseApp({ ...params, type: 'problem' }, cacheOptions),\n\t\tgetExerciseApp({ ...params, type: 'solution' }, cacheOptions),\n\t])\n\n\tconst reqUrl = new URL(request.url)\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tif (\n\t\t(type === 'problem' && !problemApp) ||\n\t\t(type === 'solution' && !solutionApp)\n\t) {\n\t\tconst errorData = await getStep404Data({\n\t\t\texerciseNumber: params.exerciseNumber,\n\t\t})\n\t\tthrow Response.json(errorData, { status: 404 })\n\t}\n\n\tconst exerciseStepApp = await requireExerciseApp(params, cacheOptions)\n\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\tconst exerciseId = getStepId(exerciseStepApp)\n\tconst exerciseIndex = allApps.findIndex((step) => step.stepId === exerciseId)\n\n\t// These depend on exerciseStepApp\n\tconst [exercise, nextApp, prevApp] = await Promise.all([\n\t\trequireExercise(exerciseStepApp.exerciseNumber, cacheOptions),\n\t\tgetNextExerciseApp(exerciseStepApp, cacheOptions),\n\t\tgetPrevExerciseApp(exerciseStepApp, cacheOptions),\n\t])\n\n\tconst exerciseApps = allAppsFull\n\t\t.filter(isExerciseStepApp)\n\t\t.filter((app) => app.exerciseNumber === exerciseStepApp.exerciseNumber)\n\tconst isLastStep =\n\t\texerciseApps[exerciseApps.length - 1]?.name === exerciseStepApp.name\n\tconst isFirstStep = exerciseApps[0]?.name === exerciseStepApp.name\n\n\tconst articleId = `workshop-${slugify(workshopTitle)}-${\n\t\texercise.exerciseNumber\n\t}-${exerciseStepApp.stepNumber}-${exerciseStepApp.type}`\n\n\tconst subroute = url.pathname.split(\n\t\t`/exercise/${params.exerciseNumber}/${params.stepNumber}/${params.type}/`,\n\t)[1]\n\n\t// read persisted split percentage from cookie (10-90, default 50)\n\tconst cookieHeader = request.headers.get('cookie')\n\tconst rawSplit = cookieHeader\n\t\t? cookie.parse(cookieHeader)[splitCookieName]\n\t\t: null\n\tconst splitPercent = computeSplitPercent(rawSplit, 50)\n\n\treturn data(\n\t\t{\n\t\t\tarticleId,\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\texerciseTitle: exercise.title,\n\t\t\tepicVideoInfosPromise: getEpicVideoInfos(exerciseStepApp.epicVideoEmbeds),\n\t\t\texerciseIndex,\n\t\t\tallApps,\n\t\t\tsplitPercent,\n\t\t\tprevStepLink: isFirstStep\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${exerciseStepApp.exerciseNumber\n\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t.padStart(2, '0')}`,\n\t\t\t\t\t}\n\t\t\t\t: prevApp\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: getAppPageRoute(prevApp, {\n\t\t\t\t\t\t\t\tsubroute,\n\t\t\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t\tnextStepLink: isLastStep\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${exerciseStepApp.exerciseNumber\n\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t.padStart(2, '0')}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: nextApp\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: getAppPageRoute(nextApp, {\n\t\t\t\t\t\t\t\tsubroute,\n\t\t\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t\tisUpToDate: playgroundApp.isUpToDate,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiffFiles:\n\t\t\t\tproblemApp && solutionApp\n\t\t\t\t\t? getDiffFiles(problemApp, solutionApp, {\n\t\t\t\t\t\t\t...cacheOptions,\n\t\t\t\t\t\t\tforceFresh: url.searchParams.get('forceFresh') === 'diff',\n\t\t\t\t\t\t}).catch((e) => {\n\t\t\t\t\t\t\tconsole.error(e)\n\t\t\t\t\t\t\treturn 'There was a problem generating the diff (check the terminal output)'\n\t\t\t\t\t\t})\n\t\t\t\t\t: 'No diff available',\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nexport default function ExercisePartRoute({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tconst inBrowserBrowserRef = useRef<InBrowserBrowserRef>(null)\n\tconst containerRef = useRef<HTMLDivElement>(null)\n\tconst leftPaneRef = useRef<HTMLDivElement>(null)\n\tconst [splitPercent, setSplitPercent] = useState<number>(data.splitPercent)\n\tconst [leftWidthPx, setLeftWidthPx] = useState<number>(0)\n\n\tuseEffect(() => {\n\t\tconst left = leftPaneRef.current\n\t\tif (!left) return\n\t\tconst ro = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tsetLeftWidthPx(entry.contentRect.width)\n\t\t\t}\n\t\t})\n\t\tro.observe(left)\n\t\tsetLeftWidthPx(left.getBoundingClientRect().width)\n\t\treturn () => ro.disconnect()\n\t}, [])\n\n\tfunction setCookie(percent: number) {\n\t\tconst clamped = computeSplitPercent(percent)\n\t\tdocument.cookie = `${splitCookieName}=${clamped}; path=/; SameSite=Lax;`\n\t}\n\n\tfunction startDrag(initialClientX: number) {\n\t\tconst container = containerRef.current\n\t\tif (!container) return\n\t\tconst rect = container.getBoundingClientRect()\n\t\tlet dragging = true\n\n\t\t// Disable pointer events on iframes so the drag keeps receiving events\n\t\tconst iframes = Array.from(\n\t\t\tdocument.querySelectorAll('iframe'),\n\t\t) as HTMLIFrameElement[]\n\t\tconst originalPointerEvents = iframes.map((el) => el.style.pointerEvents)\n\t\tiframes.forEach((el) => (el.style.pointerEvents = 'none'))\n\n\t\tfunction handleMove(clientX: number) {\n\t\t\t// Safety check: ensure user is still dragging\n\t\t\tif (!dragging) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst relativeX = clientX - rect.left\n\t\t\tconst percent = (relativeX / rect.width) * 100\n\t\t\tconst clamped = computeSplitPercent(percent)\n\t\t\tsetSplitPercent(clamped)\n\t\t\tsetCookie(clamped)\n\t\t}\n\n\t\tfunction onMouseMove(e: MouseEvent) {\n\t\t\tif (!dragging || e.buttons === 0) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandleMove(e.clientX)\n\t\t}\n\t\tfunction onTouchMove(e: TouchEvent) {\n\t\t\tconst firstTouch = e.touches?.[0]\n\t\t\tif (!dragging || !firstTouch) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandleMove(firstTouch.clientX)\n\t\t}\n\t\tfunction cleanup() {\n\t\t\tif (!dragging) return\n\t\t\tdragging = false\n\t\t\tiframes.forEach(\n\t\t\t\t(el, i) => (el.style.pointerEvents = originalPointerEvents[i] ?? ''),\n\t\t\t)\n\t\t\twindow.removeEventListener('mousemove', onMouseMove)\n\t\t\twindow.removeEventListener('mouseup', cleanup)\n\t\t\twindow.removeEventListener('touchmove', onTouchMove)\n\t\t\twindow.removeEventListener('touchend', cleanup)\n\t\t\tdocument.body.style.cursor = ''\n\t\t\tdocument.body.style.userSelect = ''\n\t\t}\n\n\t\twindow.addEventListener('mousemove', onMouseMove)\n\t\twindow.addEventListener('mouseup', cleanup)\n\t\twindow.addEventListener('touchmove', onTouchMove)\n\t\twindow.addEventListener('touchend', cleanup)\n\t\tdocument.body.style.cursor = 'col-resize'\n\t\tdocument.body.style.userSelect = 'none'\n\t\thandleMove(initialClientX)\n\t}\n\n\tconst titleBits = pageTitle(data)\n\n\tuseRevalidationWS({\n\t\twatchPaths: [`${data.exerciseStepApp.relativePath}/README.mdx`],\n\t})\n\n\treturn (\n\t\t<div className=\"flex max-w-full grow flex-col\">\n\t\t\t<main\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName=\"flex grow flex-col sm:h-full sm:min-h-[800px] md:min-h-[unset] lg:flex-row\"\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"relative flex min-w-0 flex-none basis-full flex-col sm:col-span-1 sm:row-span-1 sm:h-full lg:basis-(--split-pct)\"\n\t\t\t\t\tstyle={{ ['--split-pct' as any]: `${splitPercent}%` }}\n\t\t\t\t\tref={leftPaneRef}\n\t\t\t\t>\n\t\t\t\t\t<h1 className=\"h-14 border-b pr-5 pl-10 text-sm leading-tight font-medium\">\n\t\t\t\t\t\t<div className=\"flex h-14 items-center justify-between gap-x-2 overflow-x-auto py-2 whitespace-nowrap\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2 uppercase\">\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={getExercisePath(data.exerciseStepApp.exerciseNumber)}\n\t\t\t\t\t\t\t\t\tclassName=\"hover:underline\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{titleBits.exerciseNumber}. {titleBits.exerciseTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t{'/'}\n\t\t\t\t\t\t\t\t<Link to=\".\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{titleBits.stepNumber}. {titleBits.title}\n\t\t\t\t\t\t\t\t\t{' ('}\n\t\t\t\t\t\t\t\t\t{titleBits.emoji} {titleBits.type}\n\t\t\t\t\t\t\t\t\t{')'}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{data.problem &&\n\t\t\t\t\t\t\t(data.playground?.appName !== data.problem.name ||\n\t\t\t\t\t\t\t\t!data.playground?.isUpToDate) ? (\n\t\t\t\t\t\t\t\t<div className=\"hidden md:block\">\n\t\t\t\t\t\t\t\t\t<SetAppToPlayground\n\t\t\t\t\t\t\t\t\t\tappName={data.problem.name}\n\t\t\t\t\t\t\t\t\t\tisOutdated={data.playground?.isUpToDate === false}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t\tkey={data.articleId}\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex h-full w-full max-w-none flex-1 scroll-pt-6 flex-col justify-between space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.exerciseStepApp.instructionsCode ? (\n\t\t\t\t\t\t\t<StepMdx inBrowserBrowserRef={inBrowserBrowserRef} />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t\t\t\t\t<p>No instructions yet...</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<div className=\"mt-auto flex justify-between\">\n\t\t\t\t\t\t\t{data.prevStepLink ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={data.prevStepLink.to}\n\t\t\t\t\t\t\t\t\taria-label=\"Previous Step\"\n\t\t\t\t\t\t\t\t\tdata-keyboard-action=\"g+p\"\n\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span aria-hidden>←</span>\n\t\t\t\t\t\t\t\t\t<span className=\"hidden xl:inline\"> Previous</span>\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<span />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{data.nextStepLink ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={data.nextStepLink.to}\n\t\t\t\t\t\t\t\t\taria-label=\"Next Step\"\n\t\t\t\t\t\t\t\t\tdata-keyboard-action=\"g+n\"\n\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"hidden xl:inline\">Next </span>\n\t\t\t\t\t\t\t\t\t<span aria-hidden>→</span>\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<span />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration\n\t\t\t\t\t\telementQuery={`#${data.articleId}`}\n\t\t\t\t\t\tkey={`scroll-${data.articleId}`}\n\t\t\t\t\t/>\n\t\t\t\t\t{data.type === 'solution' ? (\n\t\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\texerciseNumber={data.exerciseStepApp.exerciseNumber}\n\t\t\t\t\t\t\tstepNumber={data.exerciseStepApp.stepNumber}\n\t\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<div className=\"h-full\">\n\t\t\t\t\t\t\t\t<TouchedFiles\n\t\t\t\t\t\t\t\t\tdiffFilesPromise={data.diffFiles}\n\t\t\t\t\t\t\t\t\tcompact={leftWidthPx < 640}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\tappName={data.exerciseStepApp.name}\n\t\t\t\t\t\t\trelativePath={`${data.exerciseStepApp.relativePath}/README.mdx`}\n\t\t\t\t\t\t\tcompact={leftWidthPx < 720}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<NavChevrons\n\t\t\t\t\t\t\tprev={\n\t\t\t\t\t\t\t\tdata.prevStepLink\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tto: data.prevStepLink.to,\n\t\t\t\t\t\t\t\t\t\t\t'aria-label': 'Previous Step',\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnext={\n\t\t\t\t\t\t\t\tdata.nextStepLink\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tto: data.nextStepLink.to,\n\t\t\t\t\t\t\t\t\t\t\t'aria-label': 'Next Step',\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div\n\t\t\t\t\trole=\"separator\"\n\t\t\t\t\taria-orientation=\"vertical\"\n\t\t\t\t\ttitle=\"Drag to resize\"\n\t\t\t\t\tclassName=\"bg-border hover:bg-accent hidden w-1 cursor-col-resize lg:block\"\n\t\t\t\t\tonMouseDown={(e) => startDrag(e.clientX)}\n\t\t\t\t\tonDoubleClick={() => {\n\t\t\t\t\t\tsetSplitPercent(50)\n\t\t\t\t\t\tsetCookie(50)\n\t\t\t\t\t}}\n\t\t\t\t\tonTouchStart={(e) => {\n\t\t\t\t\t\tconst firstTouch = e.touches?.[0]\n\t\t\t\t\t\tif (firstTouch) startDrag(firstTouch.clientX)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<div className=\"flex min-w-0 flex-1\">\n\t\t\t\t\t<Outlet context={{ inBrowserBrowserRef }} />\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tclassName=\"container flex items-center justify-center\"\n\t\t\tstatusHandlers={{\n\t\t\t\t404: Exercise404ErrorBoundary,\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import { invariant, invariantResponse } from '@epic-web/invariant'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcloseProcess,\n\trunAppDev,\n\tstopPort,\n\twaitOnApp,\n} from '@epic-web/workshop-utils/process-manager.server'\nimport { data, type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { ensureUndeployed, useAltDown } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server'\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tinvariantResponse(typeof intent === 'string', 'intent is required')\n\n\tif (intent === 'start' || intent === 'stop' || intent === 'restart') {\n\t\tconst name = formData.get('name')\n\t\tinvariantResponse(typeof name === 'string', 'name is required')\n\t\tconst app = await getAppByName(name)\n\t\tif (!app) {\n\t\t\tthrow new Response('Not found', { status: 404 })\n\t\t}\n\t\tif (app.dev.type !== 'script') {\n\t\t\tthrow new Response(`App \"${name}\" does not have a server`, {\n\t\t\t\tstatus: 400,\n\t\t\t})\n\t\t}\n\n\t\tasync function startApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tconst result = await runAppDev(app)\n\t\t\tif (result.running) {\n\t\t\t\tconst appRunningResult = await waitOnApp(app)\n\t\t\t\tif (appRunningResult?.status === 'success') {\n\t\t\t\t\t// wait another 200ms just in case the build output for assets isn't finished\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 200))\n\t\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\t\tstatus: 'app-started',\n\t\t\t\t\t} as const)\n\t\t\t\t} else if (app.dev.type === 'script') {\n\t\t\t\t\tconst errorMessage = appRunningResult\n\t\t\t\t\t\t? appRunningResult.error\n\t\t\t\t\t\t: 'Unknown error'\n\t\t\t\t\treturn data(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t\t\t} as const,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tstatusText: 'App did not start',\n\t\t\t\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\t\t\t\tdescription: errorMessage,\n\t\t\t\t\t\t\t\ttitle: 'App did not start',\n\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else if (result.portNumber) {\n\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\terror: result.status,\n\t\t\t\t\tport: result.portNumber,\n\t\t\t\t} as const)\n\t\t\t} else {\n\t\t\t\tthrow new Response(\n\t\t\t\t\t'Tried starting a server for an app that does not have one',\n\t\t\t\t\t{ status: 400 },\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tasync function stopApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tawait closeProcess(app.name)\n\t\t\treturn dataWithPE(request, formData, { status: 'app-stopped' } as const)\n\t\t}\n\n\t\tswitch (intent) {\n\t\t\tcase 'start': {\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t\tcase 'stop': {\n\t\t\t\treturn stopApp()\n\t\t\t}\n\t\t\tcase 'restart': {\n\t\t\t\tawait stopApp()\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intent === 'stop-port') {\n\t\tconst port = formData.get('port')\n\t\tinvariantResponse(typeof port === 'string', 'port is required')\n\t\tawait stopPort(port)\n\t\treturn dataWithPE(request, formData, { status: 'port-stopped' } as const)\n\t}\n\tthrow new Error(`Unknown intent: ${intent}`)\n}\n\nexport function AppStopper({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst inFlightIntent = fetcher.formData?.get('intent')\n\tconst inFlightState =\n\t\tinFlightIntent === 'stop'\n\t\t\t? 'Stopping App'\n\t\t\t: inFlightIntent === 'restart'\n\t\t\t\t? 'Restarting App'\n\t\t\t\t: null\n\tconst altDown = useAltDown()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tname=\"intent\"\n\t\t\t\tvalue={altDown ? 'restart' : 'stop'}\n\t\t\t\tclassName=\"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase\"\n\t\t\t>\n\t\t\t\t{inFlightState ? inFlightState : altDown ? 'Restart App' : 'Stop App'}\n\t\t\t</button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function PortStopper({ port }: { port: number | string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"port\" value={port} />\n\t\t\t<Button varient=\"mono\" type=\"submit\" name=\"intent\" value=\"stop-port\">\n\t\t\t\t{fetcher.state === 'idle' ? 'Stop Port' : 'Stopping Port'}\n\t\t\t</Button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function AppStarter({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tif (fetcher.data?.status === 'app-not-started') {\n\t\tif (fetcher.data.error === 'port-unavailable') {\n\t\t\treturn (\n\t\t\t\t<div>\n\t\t\t\t\tThe port is unavailable. Would you like to stop whatever is running on\n\t\t\t\t\tthat port and try again?\n\t\t\t\t\t<PortStopper port={fetcher.data.port} />\n\t\t\t\t</div>\n\t\t\t)\n\t\t} else {\n\t\t\treturn <div>An unknown error has happened.</div>\n\t\t}\n\t}\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t<Button type=\"submit\" name=\"intent\" value=\"start\" varient=\"mono\">\n\t\t\t\t\tStart App\n\t\t\t\t</Button>\n\t\t\t) : (\n\t\t\t\t<div>\n\t\t\t\t\t<Loading>Starting App</Loading>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</fetcher.Form>\n\t)\n}\n","import { clsx } from 'clsx'\nimport * as React from 'react'\nimport { useImperativeHandle, useRef, useState } from 'react'\nimport { Icon } from '#app/components/icons.tsx'\nimport { AppStarter, AppStopper, PortStopper } from '#app/routes/start.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { LinkButton } from './button.tsx'\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from './ui/tooltip.tsx'\n\nexport type InBrowserBrowserRef = {\n\thandleExtrnalNavigation: (pathname?: string) => void\n}\n\ntype Props = {\n\tid: string\n\tname: string\n\tport: number\n\tportIsAvailable: boolean | null\n\tisRunning: boolean\n\tbaseUrl: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nexport function InBrowserBrowser({\n\tname,\n\tport,\n\tportIsAvailable,\n\tisRunning,\n\tbaseUrl,\n\tid,\n\tinitialRoute,\n\tref,\n}: Props) {\n\tconst requestInfo = useRequestInfo()\n\tconst [showUnmanaged, setShowUnmanaged] = useState(false)\n\tif (isRunning || showUnmanaged) {\n\t\treturn (\n\t\t\t<InBrowserBrowserForRealz\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tid={id}\n\t\t\t\tname={name}\n\t\t\t\tref={ref}\n\t\t\t\tinitialRoute={initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (portIsAvailable === false) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center justify-center\">\n\t\t\t\t<p className=\"max-w-xs pb-5 text-center\" role=\"status\">\n\t\t\t\t\t{`The port for this app is unavailable. It could be that you're running it `}\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={getBaseUrl({ domain: requestInfo.domain, port })}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t>\n\t\t\t\t\t\telsewhere\n\t\t\t\t\t</a>\n\t\t\t\t\t{'. '}\n\t\t\t\t\t<LinkButton onClick={() => setShowUnmanaged(true)}>\n\t\t\t\t\t\tShow here anyway\n\t\t\t\t\t</LinkButton>\n\t\t\t\t</p>\n\t\t\t\t<PortStopper port={port} />\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-center\">\n\t\t\t\t<AppStarter name={name} />\n\t\t\t</div>\n\t\t)\n\t}\n}\ntype RealBrowserProps = {\n\tbaseUrl: string\n\tid: string\n\tname: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nfunction InBrowserBrowserForRealz({\n\tbaseUrl,\n\tid,\n\tname,\n\tinitialRoute,\n\tref,\n}: RealBrowserProps) {\n\tconst theme = useTheme()\n\tconst [iframeKeyNumber, setIframeKeyNumber] = useState(0)\n\tconst iframeKey = id + iframeKeyNumber\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\n\tconst appUrl = new URL(initialRoute, baseUrl)\n\tconst [iframeSrcUrl, setIframeSrcUrl] = useState(appUrl)\n\n\tconst currentId = useRef(id)\n\tif (currentId.current !== id) {\n\t\tcurrentId.current = id\n\t\tsetIframeSrcUrl(appUrl)\n\t}\n\n\tfunction handleExtrnalNavigation(pathname?: string) {\n\t\tif (pathname) {\n\t\t\tconst newUrl = new URL(pathname, baseUrl)\n\t\t\tsetIframeSrcUrl(newUrl)\n\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t}\n\t}\n\n\tuseImperativeHandle(ref, () => ({ handleExtrnalNavigation }))\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t\t<div className=\"flex items-center justify-between border-b pl-1.5\">\n\t\t\t\t\t<div className=\"mr-2 flex items-center justify-center gap-2 px-1\">\n\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>Refresh</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none\">\n\t\t\t\t\t\t<a href={iframeSrcUrl.toString()} target=\"_blank\" rel=\"noreferrer\">\n\t\t\t\t\t\t\t{iframeSrcUrl.toString()}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t\t<AppStopper name={name} />\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={iframeSrcUrl.toString()}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex aspect-square items-center justify-center px-3.5',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>Open in new tab</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex h-full w-full grow dark:bg-white\">\n\t\t\t\t\t<iframe\n\t\t\t\t\t\ttitle={name}\n\t\t\t\t\t\tkey={iframeKey}\n\t\t\t\t\t\tref={iframeRef}\n\t\t\t\t\t\tsrc={iframeSrcUrl.toString()}\n\t\t\t\t\t\tclassName=\"h-full w-full grow bg-white\"\n\t\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t)\n}\n","import { type BaseExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport { useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Icon } from '#app/components/icons'\nimport {\n\tInBrowserBrowser,\n\ttype InBrowserBrowserRef,\n} from '#app/components/in-browser-browser.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\n\nexport function Preview({\n\tid,\n\tappInfo,\n\tinBrowserBrowserRef,\n}: {\n\tid?: string\n\tappInfo: {\n\t\tisRunning: boolean\n\t\tappName?: string\n\t\tname: string\n\t\ttitle: string\n\t\tportIsAvailable: boolean | null\n\t\ttype: string\n\t\tfullPath: string\n\t\tdev: BaseExerciseStepApp['dev']\n\t\ttest: BaseExerciseStepApp['test']\n\t\tstackBlitzUrl: BaseExerciseStepApp['stackBlitzUrl']\n\t} | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst requestInfo = useRequestInfo()\n\tconst [searchParams] = useSearchParams()\n\tconst theme = useTheme()\n\tif (!appInfo) return <p>No app here. Sorry.</p>\n\tconst { isRunning, dev, name, portIsAvailable, title } = appInfo\n\n\tif (ENV.EPICSHOP_DEPLOYED && appInfo.stackBlitzUrl) {\n\t\tconst url = new URL(appInfo.stackBlitzUrl)\n\t\turl.searchParams.set('embed', '1')\n\t\turl.searchParams.set('theme', theme)\n\n\t\treturn (\n\t\t\t<StackBlitzEmbed\n\t\t\t\ttitle={title}\n\t\t\t\turl={url.toString()}\n\t\t\t\tloadingContent={\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tLoading{' '}\n\t\t\t\t\t\t\t<a className=\"underline\" href={appInfo.stackBlitzUrl}>\n\t\t\t\t\t\t\t\t\"{title}\"\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t}\n\t\t\t/>\n\t\t)\n\t}\n\n\tif (dev.type === 'script') {\n\t\tconst baseUrl = getBaseUrl({\n\t\t\tdomain: requestInfo.domain,\n\t\t\tport: dev.portNumber,\n\t\t})\n\t\treturn (\n\t\t\t<InBrowserBrowser\n\t\t\t\tref={inBrowserBrowserRef}\n\t\t\t\tisRunning={isRunning}\n\t\t\t\tid={id ?? name}\n\t\t\t\tname={name}\n\t\t\t\tportIsAvailable={portIsAvailable}\n\t\t\t\tport={dev.portNumber}\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tinitialRoute={searchParams.get('pathname') ?? dev.initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (dev.type === 'browser') {\n\t\treturn (\n\t\t\t<div className=\"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto\">\n\t\t\t\t<a\n\t\t\t\t\thref={dev.pathname}\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'absolute right-5 bottom-5 flex items-center justify-center rounded-full bg-gray-100 p-2.5 transition hover:bg-gray-200 dark:bg-gray-800 hover:dark:bg-gray-600',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"ExternalLink\" aria-hidden=\"true\" />\n\t\t\t\t\t<span className=\"sr-only\">Open in New Window</span>\n\t\t\t\t</a>\n\t\t\t\t<iframe\n\t\t\t\t\ttitle={title}\n\t\t\t\t\tsrc={dev.pathname}\n\t\t\t\t\tclassName=\"yo yo h-full w-full grow bg-white\"\n\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>\n\t\t\t\t\tPreview for dev type of <code>{dev.type}</code> not supported.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t)\n\t}\n}\n\nexport function StackBlitzEmbed({\n\turl,\n\ttitle,\n\tloadingContent,\n}: {\n\turl: string\n\ttitle?: string\n\tloadingContent: React.ReactNode\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = useState(false)\n\n\treturn (\n\t\t<div className=\"h-full w-full grow\">\n\t\t\t{iframeLoaded ? null : (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t{loadingContent}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\tsrc={url}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'h-full w-full grow transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\ttitle={title}\n\t\t\t\tsandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n","import { type App } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tgetTestProcessEntry,\n\tisAppRunning,\n\tisPortAvailable,\n\tisTestRunning,\n} from '@epic-web/workshop-utils/process-manager.server'\n\nexport async function getAppRunningState(a: App) {\n\tif (a.dev.type !== 'script') {\n\t\treturn { isRunning: false, portIsAvailable: null }\n\t}\n\tconst isRunning = await isAppRunning(a)\n\tconst portIsAvailable = isRunning\n\t\t? null\n\t\t: await isPortAvailable(a.dev.portNumber)\n\treturn { isRunning, portIsAvailable }\n}\n\nexport function getTestState(a: App) {\n\tconst testProcess = getTestProcessEntry(a)\n\tif (!testProcess) {\n\t\treturn { isTestRunning: false, testExitCode: null }\n\t}\n\treturn {\n\t\tisTestRunning: isTestRunning(a),\n\t\ttestExitCode: testProcess.exitCode ?? null,\n\t}\n}\n","import { requireExerciseApp } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcombineServerTimings,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { useRef } from 'react'\nimport {\n\tdata,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tuseLoaderData,\n} from 'react-router'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.ts'\nimport { Preview } from './__shared/preview.tsx'\nimport { getAppRunningState } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exercise-step-test')\n\tconst exerciseStepApp = await requireExerciseApp(params, { request, timings })\n\tconst { isRunning, portIsAvailable } =\n\t\tawait getAppRunningState(exerciseStepApp)\n\n\treturn data(\n\t\t{\n\t\t\tappInfo: {\n\t\t\t\tisRunning,\n\t\t\t\tname: exerciseStepApp.name,\n\t\t\t\ttitle: exerciseStepApp.title,\n\t\t\t\tportIsAvailable,\n\t\t\t\ttype: exerciseStepApp.type,\n\t\t\t\tfullPath: exerciseStepApp.fullPath,\n\t\t\t\tdev: exerciseStepApp.dev,\n\t\t\t\ttest: exerciseStepApp.test,\n\t\t\t\tstackBlitzUrl: exerciseStepApp.stackBlitzUrl,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nexport default function TestsList() {\n\tconst { appInfo } = useLoaderData<typeof loader>()\n\tconst ref = useRef<InBrowserBrowserRef>(null)\n\n\treturn <Preview appInfo={appInfo} inBrowserBrowserRef={ref} />\n}\n","import * as Accordion from '@radix-ui/react-accordion'\nimport { clsx } from 'clsx'\nimport * as React from 'react'\nimport { Icon } from './icons.tsx'\n\ntype AccordionProps = {\n\ttitle: string\n\tchildren: React.ReactElement\n\tvariant?: 'changed' | 'added' | 'deleted' | 'renamed'\n\ticon?: React.ReactElement\n\tforceMount?: boolean\n}\n\nconst AccordionComponent: React.FC<AccordionProps> = ({\n\ttitle,\n\tchildren,\n\tvariant,\n\ticon,\n\tforceMount = false,\n}) => {\n\tconst getVariantIcon = () => {\n\t\tswitch (variant) {\n\t\t\tcase 'changed':\n\t\t\t\treturn (\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"Modified\"\n\t\t\t\t\t\taria-label=\"Modified\"\n\t\t\t\t\t\tclassName=\"text-[#fb923c]\"\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\tcase 'renamed':\n\t\t\t\treturn (\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"Renamed\"\n\t\t\t\t\t\taria-label=\"Renamed\"\n\t\t\t\t\t\tclassName=\"text-[#fb923c]\"\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\tcase 'added':\n\t\t\t\treturn (\n\t\t\t\t\t<Icon name=\"Added\" aria-label=\"Added\" className=\"text-[#10b981]\" />\n\t\t\t\t)\n\t\t\tcase 'deleted':\n\t\t\t\treturn (\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"Deleted\"\n\t\t\t\t\t\taria-label=\"Deleted\"\n\t\t\t\t\t\tclassName=\"text-[#ef4444]\"\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\treturn (\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"Modified\"\n\t\t\t\t\t\taria-label=\"Modified\"\n\t\t\t\t\t\tclassName=\"text-[#fb923c]\"\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t}\n\t}\n\tconst getVariantLabel = () => {\n\t\tswitch (variant) {\n\t\t\tcase 'changed':\n\t\t\t\treturn 'modified'\n\t\t\tdefault:\n\t\t\t\treturn variant\n\t\t}\n\t}\n\n\t// Somehow on windows we get double backslashes in the title\n\t// so we'll just remove those 🤷‍♂️\n\tconst fixedTitle = title.replace(/\\\\\\\\/g, '\\\\')\n\treturn (\n\t\t<Accordion.Item value={title}>\n\t\t\t<AccordionTrigger variant={getVariantLabel()}>\n\t\t\t\t{icon ? icon : getVariantIcon()} {fixedTitle}\n\t\t\t</AccordionTrigger>\n\t\t\t<AccordionContent\n\t\t\t\tforceMount={forceMount}\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'prose dark:prose-invert prose-pre:m-0 prose-pre:mb-1 prose-pre:rounded-none max-w-none whitespace-pre-wrap',\n\t\t\t\t\t{\n\t\t\t\t\t\t'radix-state-closed:hidden': forceMount,\n\t\t\t\t\t},\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</AccordionContent>\n\t\t</Accordion.Item>\n\t)\n}\n\nexport default AccordionComponent\n\nconst AccordionTrigger: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\tvariant,\n\t...props\n}) => (\n\t<Accordion.Header className=\"flex\" asChild>\n\t\t<Accordion.Trigger\n\t\t\tclassName={clsx(\n\t\t\t\t'group hover:bg-foreground/20 flex w-full items-center justify-between border-b p-4 pr-3 font-mono text-sm leading-none font-medium',\n\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t\tref={forwardedRef}\n\t\t>\n\t\t\t<div className=\"flex items-center gap-1.5\">{children}</div>\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<span className=\"text-muted-foreground font-mono text-xs font-normal uppercase\">\n\t\t\t\t\t{variant}\n\t\t\t\t</span>\n\t\t\t\t<Icon\n\t\t\t\t\tname=\"TriangleDownSmall\"\n\t\t\t\t\tclassName=\"group-radix-state-open:rotate-180 transition\"\n\t\t\t\t\taria-hidden\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</Accordion.Trigger>\n\t</Accordion.Header>\n)\n\nconst AccordionContent: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => (\n\t<Accordion.Content\n\t\tclassName={clsx('', className)}\n\t\t{...props}\n\t\tref={forwardedRef}\n\t>\n\t\t<div>{children}</div>\n\t</Accordion.Content>\n)\n","import * as Accordion from '@radix-ui/react-accordion'\nimport * as Select from '@radix-ui/react-select'\nimport { clsx } from 'clsx'\nimport React, { Suspense } from 'react'\nimport { ErrorBoundary } from 'react-error-boundary'\nimport {\n\tAwait,\n\tForm,\n\tLink,\n\tuseNavigation,\n\tuseSearchParams,\n\tuseSubmit,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport AccordionComponent from '#app/components/accordion.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useApps } from '#app/utils/root-loader.ts'\nimport { DeferredEpicVideo } from './epic-video.tsx'\nimport { Icon } from './icons.tsx'\nimport { useRevalidationWS } from './revalidation-ws.tsx'\nimport { SimpleTooltip } from './ui/tooltip.tsx'\n\ntype diffProp = {\n\tapp1?: string\n\tapp2?: string\n\tdiffCode?: string | null\n}\n\nconst pre = (props: any) => <pre {...props} />\n\nconst mdxComponents = {\n\tAccordion: AccordionComponent,\n\t// override the pre-with-buttons\n\tpre,\n}\n\nfunction RevalidateApps({\n\tapp1: app1Name,\n\tapp2: app2Name,\n}: {\n\tapp1?: string\n\tapp2?: string\n}) {\n\tconst apps = useApps()\n\tconst app1 = apps.find((app) => app.name === app1Name)\n\tconst app2 = apps.find((app) => app.name === app2Name)\n\n\tuseRevalidationWS({\n\t\twatchPaths: [app1?.fullPath, app2?.fullPath].filter(Boolean),\n\t})\n\treturn null\n}\n\nexport function UserHasAccessDiff({\n\tuserHasAccessPromise,\n\tdiff,\n\tallApps,\n}: {\n\tuserHasAccessPromise: Promise<boolean>\n\tdiff: Promise<diffProp> | diffProp\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\treturn (\n\t\t<ErrorBoundary\n\t\t\tfallbackRender={() => (\n\t\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t\t<p className=\"text-2xl font-bold\">Error</p>\n\t\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\t\tThere was an error loading the user access.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t>\n\t\t\t<Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div className=\"flex items-center justify-center p-8\">\n\t\t\t\t\t\t<SimpleTooltip content=\"Loading user access\">\n\t\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"animate-spin\" />\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await resolve={userHasAccessPromise}>\n\t\t\t\t\t{(userHasAccess) =>\n\t\t\t\t\t\tuserHasAccess ? (\n\t\t\t\t\t\t\t<DiffImplementation diff={diff} allApps={allApps} />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t\t\t\t\t<p className=\"text-2xl font-bold\">Access Denied</p>\n\t\t\t\t\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\t\t\t\t\tYou must login or register for the workshop to view the\n\t\t\t\t\t\t\t\t\t\tdiff.\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"h-16\" />\n\t\t\t\t\t\t\t\t<p className=\"pb-4\">\n\t\t\t\t\t\t\t\t\tCheck out this video to see how the diff tab works.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t<DeferredEpicVideo url=\"https://www.epicweb.dev/tips/epic-workshop-diff-tab-demo\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t</Await>\n\t\t\t</Suspense>\n\t\t</ErrorBoundary>\n\t)\n}\n\nexport { UserHasAccessDiff as Diff }\n\nexport function DiffImplementation({\n\tdiff,\n\tallApps,\n}: {\n\tdiff: Promise<diffProp> | diffProp\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\tconst submit = useSubmit()\n\tconst [params] = useSearchParams()\n\tconst paramsWithForcedRefresh = new URLSearchParams(params)\n\tparamsWithForcedRefresh.set('forceFresh', 'diff')\n\tconst navigation = useNavigation()\n\tconst spinnerNavigating = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 0,\n\t\tminDuration: 1000,\n\t})\n\n\tconst hiddenInputs: Array<React.ReactNode> = []\n\tfor (const [key, value] of params.entries()) {\n\t\tif (key === 'app1' || key === 'app2') continue\n\t\thiddenInputs.push(\n\t\t\t<input key={key} type=\"hidden\" name={key} value={value} />,\n\t\t)\n\t}\n\n\treturn (\n\t\t<Suspense\n\t\t\tfallback={\n\t\t\t\t<div className=\"flex items-center justify-center p-8\">\n\t\t\t\t\t<SimpleTooltip content=\"Loading diff\">\n\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"animate-spin\" />\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t</div>\n\t\t\t}\n\t\t>\n\t\t\t<Await\n\t\t\t\tresolve={diff}\n\t\t\t\terrorElement={\n\t\t\t\t\t<p className=\"text-foreground-destructive p-6\">\n\t\t\t\t\t\tThere was an error calculating the diff. Sorry.\n\t\t\t\t\t</p>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t{(diff) => (\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col\">\n\t\t\t\t\t\t<div className=\"flex h-14 min-h-14 w-full overflow-x-hidden border-b\">\n\t\t\t\t\t\t\t<div className=\"border-r\">\n\t\t\t\t\t\t\t\t<SimpleTooltip content=\"Reload diff\">\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={`.?${paramsWithForcedRefresh}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex h-full w-14 items-center justify-center\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\tname=\"Refresh\"\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn({ 'animate-spin': spinnerNavigating })}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<Form\n\t\t\t\t\t\t\t\tonChange={(e) => submit(e.currentTarget)}\n\t\t\t\t\t\t\t\tclassName=\"scrollbar-thin scrollbar-thumb-scrollbar flex h-full flex-1 items-center overflow-x-auto\"\n\t\t\t\t\t\t\t\tkey={`${diff.app1}${diff.app2}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{hiddenInputs}\n\t\t\t\t\t\t\t\t<SelectFileToDiff\n\t\t\t\t\t\t\t\t\tname=\"app1\"\n\t\t\t\t\t\t\t\t\tlabel=\"App 1\"\n\t\t\t\t\t\t\t\t\tclassName=\"border-r\"\n\t\t\t\t\t\t\t\t\tallApps={allApps}\n\t\t\t\t\t\t\t\t\tdefaultValue={diff.app1}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<SelectFileToDiff\n\t\t\t\t\t\t\t\t\tname=\"app2\"\n\t\t\t\t\t\t\t\t\tlabel=\"App 2\"\n\t\t\t\t\t\t\t\t\tallApps={allApps}\n\t\t\t\t\t\t\t\t\tdefaultValue={diff.app2}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"scrollbar-thin scrollbar-thumb-scrollbar grow overflow-y-scroll\">\n\t\t\t\t\t\t\t{diff.diffCode ? (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<Accordion.Root className=\"w-full\" type=\"multiple\">\n\t\t\t\t\t\t\t\t\t\t<Mdx code={diff.diffCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t\t</Accordion.Root>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : diff.app1 && diff.app2 ? (\n\t\t\t\t\t\t\t\t<p className=\"bg-foreground text-background m-5 inline-flex items-center justify-center px-1 py-0.5 font-mono text-sm uppercase\">\n\t\t\t\t\t\t\t\t\tThere was a problem generating the diff\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"bg-foreground text-background m-5 inline-flex items-center justify-center px-1 py-0.5 font-mono text-sm uppercase\">\n\t\t\t\t\t\t\t\t\tSelect two apps to compare\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<RevalidateApps app1={diff.app1} app2={diff.app2} />\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</Await>\n\t\t</Suspense>\n\t)\n}\n\nfunction SelectFileToDiff({\n\tname,\n\tlabel,\n\tclassName,\n\tallApps,\n\tdefaultValue,\n}: {\n\tname: string\n\tlabel: string\n\tclassName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tdefaultValue?: string\n}) {\n\treturn (\n\t\t<Select.Root name={name} defaultValue={defaultValue}>\n\t\t\t<Select.Trigger\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'radix-placeholder:text-gray-500 flex h-full w-full max-w-[50%] items-center justify-between px-3 text-left focus-visible:outline-none',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\taria-label={`Select ${label} for git Diff`}\n\t\t\t>\n\t\t\t\t<span className=\"overflow-hidden text-ellipsis whitespace-nowrap\">\n\t\t\t\t\t{label}:{' '}\n\t\t\t\t\t<Select.Value\n\t\t\t\t\t\tplaceholder={`Select ${label}`}\n\t\t\t\t\t\tclassName=\"inline-block w-40 text-ellipsis\"\n\t\t\t\t\t/>\n\t\t\t\t</span>\n\t\t\t\t<Select.Icon className=\"\">\n\t\t\t\t\t<Icon name=\"TriangleDownSmall\" />\n\t\t\t\t</Select.Icon>\n\t\t\t</Select.Trigger>\n\t\t\t<Select.Portal>\n\t\t\t\t<Select.Content\n\t\t\t\t\tposition=\"popper\"\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]\"\n\t\t\t\t>\n\t\t\t\t\t<Select.ScrollUpButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronUp\" />\n\t\t\t\t\t</Select.ScrollUpButton>\n\t\t\t\t\t<Select.Viewport className=\"p-3\">\n\t\t\t\t\t\t<Select.Group>\n\t\t\t\t\t\t\t<Select.Label className=\"px-5 pb-3 font-mono uppercase\">\n\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t</Select.Label>\n\t\t\t\t\t\t\t{allApps.map((app) => {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<SelectItem key={app.name} value={app.name}>\n\t\t\t\t\t\t\t\t\t\t{app.displayName}\n\t\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</Select.Group>\n\t\t\t\t\t</Select.Viewport>\n\t\t\t\t\t<Select.ScrollDownButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronDown\" />\n\t\t\t\t\t</Select.ScrollDownButton>\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Portal>\n\t\t</Select.Root>\n\t)\n}\n\nconst SelectItem: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => {\n\treturn (\n\t\t<Select.Item\n\t\t\tclassName={clsx(\n\t\t\t\t'radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100 relative flex cursor-pointer items-center rounded px-10 py-2 leading-none opacity-80 select-none',\n\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t\tref={forwardedRef}\n\t\t>\n\t\t\t<Select.ItemText>{children}</Select.ItemText>\n\t\t\t<Select.ItemIndicator className=\"absolute left-0 inline-flex w-[25px] items-center justify-center\">\n\t\t\t\t<Icon name=\"CheckSmall\" />\n\t\t\t</Select.ItemIndicator>\n\t\t</Select.Item>\n\t)\n}\n","export function StatusIndicator({\n\tstatus,\n}: {\n\tstatus: 'running' | 'passed' | 'failed' | 'stopped'\n}) {\n\tconst colors = {\n\t\trunning: {\n\t\t\tpinger: 'bg-green-400',\n\t\t\tcircle: 'bg-green-500',\n\t\t},\n\t\tpassed: {\n\t\t\tcircle: 'bg-green-500',\n\t\t},\n\t\tfailed: {\n\t\t\tcircle: 'bg-red-500',\n\t\t},\n\t\tstopped: {\n\t\t\tcircle: 'bg-gray-500',\n\t\t},\n\t}[status]\n\treturn (\n\t\t<span className=\"relative flex h-3 w-3\">\n\t\t\t{colors.pinger ? (\n\t\t\t\t<span\n\t\t\t\t\tclassName={`absolute inline-flex h-full w-full animate-ping rounded-full ${colors.pinger} opacity-75`}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<span\n\t\t\t\tclassName={`relative inline-flex h-3 w-3 rounded-full ${colors.circle}`}\n\t\t\t/>\n\t\t</span>\n\t)\n}\n","import {\n\tcachified,\n\tdiscordCache,\n\tshouldForceFresh,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { dayjs } from '@epic-web/workshop-utils/utils.server'\nimport { z } from 'zod'\nimport { getHints } from '#app/utils/client-hints.tsx'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\n\nconst EmojiDataSchema = z.union([\n\tz.object({\n\t\temojiName: z.never().optional(),\n\t\temojiUrl: z.string(),\n\t}),\n\tz.object({\n\t\temojiName: z.string(),\n\t\temojiUrl: z.never().optional(),\n\t}),\n\tz.object({\n\t\temojiName: z.never().optional(),\n\t\temojiUrl: z.never().optional(),\n\t}),\n])\n\nexport const ThreadItemSchema = z.object({\n\tid: z.string(),\n\ttags: z.array(\n\t\tz\n\t\t\t.object({\n\t\t\t\tname: z.string(),\n\t\t\t})\n\t\t\t.and(EmojiDataSchema),\n\t),\n\tname: z.string(),\n\tlink: z.string(),\n\tauthorDisplayName: z.string(),\n\tauthorHexAccentColor: z.string().nullable().optional(),\n\tauthorAvatarUrl: z.string().nullable(),\n\tmessagePreview: z.string(),\n\tmessageCount: z.number(),\n\tlastUpdated: z.string(),\n\tpreviewImageUrl: z.string().nullable(),\n\treactions: z.array(\n\t\tz\n\t\t\t.object({\n\t\t\t\tcount: z.number(),\n\t\t\t})\n\t\t\t.and(EmojiDataSchema),\n\t),\n})\n\nconst ThreadDataSchema = z.array(ThreadItemSchema)\n\nconst EpicForumResponseSchema = z\n\t.object({\n\t\tstatus: z.literal('error'),\n\t\terror: z.string(),\n\t})\n\t.or(\n\t\tz.object({\n\t\t\tstatus: z.literal('success'),\n\t\t\tthreadData: ThreadDataSchema,\n\t\t}),\n\t)\n\nexport async function fetchDiscordPosts({ request }: { request: Request }) {\n\tconst config = getWorkshopConfig()\n\tif (!config.product.discordChannelId) return []\n\n\tconst forceFresh = await shouldForceFresh({ request })\n\tconst searchParams = new URLSearchParams({\n\t\tchannelId: config.product.discordChannelId,\n\t})\n\tif (config.product.discordTags?.length) {\n\t\tfor (const tag of config.product.discordTags) {\n\t\t\tsearchParams.append('tagId', tag)\n\t\t}\n\t}\n\tif (forceFresh) searchParams.set('fresh', 'true')\n\t// const url = `http://localhost:3000/resources/forum-feed?${searchParams}`\n\tconst url = `https://kcd-discord-bot-v2.fly.dev/resources/forum-feed?${searchParams}`\n\n\tconst threadData = await cachified({\n\t\tkey: url,\n\t\trequest,\n\t\tforceFresh,\n\t\tcache: discordCache,\n\t\tttl: 1000 * 60 * 2,\n\t\tswr: 1000 * 60 * 60 * 24 * 365 * 100,\n\t\tofflineFallbackValue: [],\n\t\tcheckValue: ThreadDataSchema,\n\t\tasync getFreshValue(): Promise<z.infer<typeof ThreadDataSchema>> {\n\t\t\tconst result = await fetch(url, {\n\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t}).catch((error) => {\n\t\t\t\treturn new Response(getErrorMessage(error), { status: 500 })\n\t\t\t})\n\n\t\t\tif (!result.ok) {\n\t\t\t\tconsole.error(`There was an error communicating with discord`)\n\t\t\t\ttry {\n\t\t\t\t\tconsole.error(await result.text())\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore\n\t\t\t\t}\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\tconst jsonResult = await result.json()\n\t\t\tconst epicForumResponseResult =\n\t\t\t\tEpicForumResponseSchema.safeParse(jsonResult)\n\t\t\tif (epicForumResponseResult.success) {\n\t\t\t\tif (epicForumResponseResult.data.status === 'error') {\n\t\t\t\t\tconsole.error(`There was an error communicating with discord`)\n\t\t\t\t\tconsole.error(epicForumResponseResult.data.error)\n\t\t\t\t\treturn []\n\t\t\t\t} else {\n\t\t\t\t\treturn epicForumResponseResult.data.threadData\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconsole.error(`There was an error parsing the discord response`)\n\t\t\t\tconsole.error(epicForumResponseResult.error.flatten())\n\t\t\t\treturn []\n\t\t\t}\n\t\t},\n\t})\n\n\tconst hints = getHints(request)\n\n\treturn threadData.map((thread) => ({\n\t\t...thread,\n\t\tlastUpdatedDisplay: dayjs(thread.lastUpdated).tz(hints.timeZone).fromNow(),\n\t}))\n}\n","import * as React from 'react'\nimport { Await, Link, useLoaderData } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { DiscordCTA, useDiscordCTALink } from '#app/routes/_app+/discord.tsx'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { type Route } from '../+types/index.tsx'\n\nexport function DiscordChat() {\n\treturn (\n\t\t<div className=\"flex h-full w-full flex-col gap-4 pt-4\">\n\t\t\t<div className=\"text-center\">\n\t\t\t\t<DiscordCTA />\n\t\t\t</div>\n\t\t\t<div className=\"bg-accent scrollbar-thin scrollbar-thumb-scrollbar flex-1 overflow-y-scroll pb-4\">\n\t\t\t\t<DiscordPosts />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPosts() {\n\tconst data = useLoaderData<Route.ComponentProps['loaderData']>()\n\tconst ctaLink = useDiscordCTALink()\n\tconst altDown = useAltDown()\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t<div className=\"text-foreground-destructive flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\tUnable to load discord messages when offline\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\treturn (\n\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t<React.Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t\t<Loading>Loading Discord Posts</Loading>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await\n\t\t\t\t\tresolve={data.discordPostsPromise}\n\t\t\t\t\terrorElement={\n\t\t\t\t\t\t<div className=\"text-red-500\">\n\t\t\t\t\t\t\tThere was a problem loading the discord posts\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{(posts) => (\n\t\t\t\t\t\t<ul className=\"flex w-full flex-col gap-4 p-3 xl:p-12\">\n\t\t\t\t\t\t\t{posts.map((post) => (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={post.id}\n\t\t\t\t\t\t\t\t\tclassName=\"bg-background rounded-xl border transition-all duration-200 focus-within:-translate-y-1 focus-within:shadow-lg hover:-translate-y-1 hover:shadow-lg\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<DiscordPost thread={post} />\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t)}\n\t\t\t\t</Await>\n\t\t\t</React.Suspense>\n\t\t\t<div>\n\t\t\t\t<Link\n\t\t\t\t\tto={\n\t\t\t\t\t\taltDown && !ctaLink.includes('oauth')\n\t\t\t\t\t\t\t? ctaLink.replace(/^https/, 'discord')\n\t\t\t\t\t\t\t: ctaLink\n\t\t\t\t\t}\n\t\t\t\t\ttarget={ctaLink.includes('oauth') ? undefined : '_blank'}\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\tonClick={\n\t\t\t\t\t\taltDown\n\t\t\t\t\t\t\t? (e) => {\n\t\t\t\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t\t\t\t\twindow.open(\n\t\t\t\t\t\t\t\t\t\te.currentTarget.href,\n\t\t\t\t\t\t\t\t\t\t'_blank',\n\t\t\t\t\t\t\t\t\t\t'noreferrer noopener',\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"flex items-center gap-2 p-2 text-xl hover:underline\"\n\t\t\t\t>\n\t\t\t\t\tCreate Post <Icon name=\"ExternalLink\" />\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPost({\n\tthread,\n}: {\n\tthread: Awaited<\n\t\tRoute.ComponentProps['loaderData']['discordPostsPromise']\n\t>[number]\n}) {\n\tconst reactionsWithCounts = thread.reactions.filter((r) => r.count)\n\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"flex flex-col gap-2 p-4\">\n\t\t\t\t<div className=\"flex gap-4\">\n\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t{thread.tags.length ? (\n\t\t\t\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t\t\t\t{thread.tags.map((t) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={t.name}\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-accent flex items-center justify-center gap-1 rounded-full px-2 py-1 text-sm\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t<Emoji name={t.emojiName} url={t.emojiUrl} />\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span>{t.name}</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<strong className=\"text-xl font-bold\">{thread.name}</strong>\n\t\t\t\t\t\t<div className=\"flex items-start gap-1\">\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t{thread.authorAvatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tsrc={thread.authorAvatarUrl}\n\t\t\t\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-6 w-6 rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclassName=\"font-bold\"\n\t\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\t\tthread.authorHexAccentColor\n\t\t\t\t\t\t\t\t\t\t\t\t? { color: thread.authorHexAccentColor }\n\t\t\t\t\t\t\t\t\t\t\t\t: {}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{thread.authorDisplayName}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t:{' '}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<span className=\"text-muted-foreground flex-1 overflow-ellipsis\">\n\t\t\t\t\t\t\t\t{thread.messagePreview}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{thread.previewImageUrl ? (\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tsrc={thread.previewImageUrl}\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tclassName=\"h-28 w-28 rounded-lg object-cover\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"flex justify-between\">\n\t\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{reactionsWithCounts.length ? (\n\t\t\t\t\t\t\t\t<ul className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t{reactionsWithCounts.map((r, i) => (\n\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-1 rounded-md border border-blue-600 bg-blue-500/20 px-[5px] py-[0.5px] text-sm\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Emoji name={r.emojiName} url={r.emojiUrl} />\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>{r.count}</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t<span className=\"inline-flex items-center gap-1\">\n\t\t\t\t\t\t\t\t<Icon name=\"Chat\" /> {thread.messageCount}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{` · ${thread.lastUpdatedDisplay}`}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span className=\"flex items-center gap-4\">\n\t\t\t\t\t\t<a href={thread.link.replace(/^https/, 'discord')}>\n\t\t\t\t\t\t\t<Icon name=\"Discord\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<a href={thread.link} target=\"_blank\" rel=\"noreferrer noopener\">\n\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction Emoji({ name, url }: { name?: string; url?: string }) {\n\treturn url ? (\n\t\t<img src={url} alt={name} className=\"h-full w-full\" />\n\t) : name ? (\n\t\tname\n\t) : null\n}\n","import { Icon } from '#app/components/icons'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { PlaygroundChooser, SetPlayground } from '#app/routes/set-playground'\n\nexport function PlaygroundWindow({\n\tplaygroundAppName,\n\tproblemAppName,\n\tisUpToDate,\n\tallApps,\n\tchildren,\n}: {\n\tplaygroundAppName?: string\n\tproblemAppName?: string\n\tisUpToDate: boolean\n\tallApps: Array<{ name: string; displayName: string }>\n\tchildren: React.ReactNode\n}) {\n\tconst isCorrectApp = playgroundAppName === problemAppName\n\tconst playgroundLinkedUI =\n\t\tisCorrectApp && isUpToDate ? (\n\t\t\t<Icon size=\"xl\" name=\"Linked\" />\n\t\t) : (\n\t\t\t<Icon\n\t\t\t\tsize=\"xl\"\n\t\t\t\tname=\"Unlinked\"\n\t\t\t\tclassName=\"text-foreground-destructive animate-pulse\"\n\t\t\t/>\n\t\t)\n\tlet setPlaygroundTooltipText = 'Click to reset Playground.'\n\tif (!isUpToDate) {\n\t\tsetPlaygroundTooltipText =\n\t\t\t'Playground is out of date. Click to reset Playground.'\n\t}\n\tif (!isCorrectApp) {\n\t\tsetPlaygroundTooltipText =\n\t\t\t'Playground is not set to the right app. Click to set Playground.'\n\t}\n\treturn (\n\t\t<div className=\"flex h-full w-full flex-col justify-between\">\n\t\t\t<div className=\"flex h-14 shrink-0 items-center justify-start gap-2 border-b px-3\">\n\t\t\t\t<div className=\"display-alt-up\">\n\t\t\t\t\t{problemAppName ? (\n\t\t\t\t\t\t<SetPlayground\n\t\t\t\t\t\t\tappName={problemAppName}\n\t\t\t\t\t\t\ttooltipText={setPlaygroundTooltipText}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{playgroundLinkedUI}\n\t\t\t\t\t\t</SetPlayground>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<SimpleTooltip content=\"No problem app available for this step\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"display-alt-down\">\n\t\t\t\t\t{playgroundAppName ? (\n\t\t\t\t\t\t<SetPlayground\n\t\t\t\t\t\t\tappName={playgroundAppName}\n\t\t\t\t\t\t\treset\n\t\t\t\t\t\t\ttooltipText=\"Reset Playground\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"flex h-7 w-7 items-center justify-center\">\n\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SetPlayground>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"h-7 w-7\" />\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<PlaygroundChooser\n\t\t\t\t\tallApps={allApps}\n\t\t\t\t\tplaygroundAppName={playgroundAppName}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"flex min-h-0 flex-1 grow items-stretch justify-center overflow-hidden\">\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n","import { toast as showToast } from 'sonner'\nimport { Icon } from '#app/components/icons.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser'\nimport { SimpleTooltip } from '#app/components/ui/tooltip'\nimport { SetAppToPlayground } from '#app/routes/set-playground'\nimport { PlaygroundWindow } from './playground-window'\nimport { Preview } from './preview'\n\nexport function Playground({\n\tappInfo: playgroundAppInfo,\n\tinBrowserBrowserRef,\n\tproblemAppName,\n\tallApps,\n\tisUpToDate,\n}: {\n\tappInfo: Parameters<typeof Preview>['0']['appInfo'] | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\tproblemAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tisUpToDate: boolean\n}) {\n\treturn (\n\t\t<PlaygroundWindow\n\t\t\tplaygroundAppName={playgroundAppInfo?.appName}\n\t\t\tproblemAppName={problemAppName}\n\t\t\tallApps={allApps}\n\t\t\tisUpToDate={isUpToDate}\n\t\t>\n\t\t\t{playgroundAppInfo?.dev.type === 'none' ? (\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-center gap-4\">\n\t\t\t\t\t<div className=\"text-secondary-foreground text-2xl\">\n\t\t\t\t\t\tNon-UI exercise\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"text-secondary-foreground max-w-md text-center text-balance\">\n\t\t\t\t\t\tThis exercise has no application or other UI associated with it.{' '}\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\tNavigate to{' '}\n\t\t\t\t\t\t<SimpleTooltip content={playgroundAppInfo.fullPath}>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"inline-flex cursor-pointer items-center gap-1.5 underline\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tvoid navigator.clipboard.writeText(playgroundAppInfo.fullPath)\n\t\t\t\t\t\t\t\t\tshowToast.success('Copied playground path to clipboard')\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tthe playground directory\n\t\t\t\t\t\t\t\t<Icon name=\"Copy\" size=\"sm\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</SimpleTooltip>{' '}\n\t\t\t\t\t\tin your editor and follow the exercise instructions to complete it.\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) : playgroundAppInfo ? (\n\t\t\t\t<Preview\n\t\t\t\t\tid={playgroundAppInfo.appName}\n\t\t\t\t\tappInfo={playgroundAppInfo}\n\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex flex-col justify-center gap-2\">\n\t\t\t\t\t<p>Please set the playground first</p>\n\t\t\t\t\t{problemAppName ? (\n\t\t\t\t\t\t<SetAppToPlayground appName={problemAppName} />\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</PlaygroundWindow>\n\t)\n}\n","import AnsiToHTML from 'ansi-to-html'\nimport { useMemo } from 'react'\nimport { useTheme } from '#app/routes/theme/index.tsx'\n\nexport function useAnsiToHtml() {\n\tconst theme = useTheme()\n\tconst ansi = useMemo(\n\t\t() =>\n\t\t\tnew AnsiToHTML(\n\t\t\t\ttheme === 'dark'\n\t\t\t\t\t? { fg: '#d6deeb', bg: '#121318', escapeXML: true }\n\t\t\t\t\t: { fg: '#000000', bg: '#f3f3f3', escapeXML: true },\n\t\t\t),\n\t\t[theme],\n\t)\n\treturn ansi\n}\n\n// remove this when this is fixed: https://github.com/rburns/ansi-to-html/issues/112\nexport function stripCursorMovements(data: string) {\n\treturn data.replace(/\\u001b\\[\\d+A/g, '').replace(/\\u001b\\[\\d+K/g, '')\n}\n","import * as Accordion from '@radix-ui/react-accordion'\nimport { useEffect, useRef, useState } from 'react'\nimport { z } from 'zod'\nimport AccordionComponent from '#app/components/accordion.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { stripCursorMovements, useAnsiToHtml } from '#app/utils/ansi-text.ts'\nimport { AnimatedBars, Icon } from './icons.tsx'\n\nconst testRunnerStatusDataSchema = z.intersection(\n\tz.object({\n\t\ttype: z.literal('epicshop:test-status-update'),\n\t\ttimestamp: z.number(),\n\t}),\n\tz.union([\n\t\tz.object({ status: z.literal('pending') }),\n\t\tz.object({ status: z.literal('pass') }),\n\t\tz.object({ status: z.literal('fail'), error: z.string() }),\n\t]),\n)\n\nconst testRunnerTestStepDataSchema = z.object({\n\ttype: z.literal('epicshop:test-step-update'),\n\tstatus: z.literal('pass'),\n\ttitle: z.string(),\n\ttimestamp: z.number(),\n})\n\nconst testRunnerDataSchema = z.union([\n\ttestRunnerTestStepDataSchema,\n\ttestRunnerStatusDataSchema,\n])\n\ntype TestRunnerStatusData = z.infer<typeof testRunnerStatusDataSchema>\ntype TestRunnerTestStepData = z.infer<typeof testRunnerTestStepDataSchema>\n\nexport function InBrowserTestRunner({\n\tpathname,\n\ttestFile,\n}: {\n\tpathname: string\n\ttestFile: string\n}) {\n\tconst theme = useTheme()\n\tconst ansi = useAnsiToHtml()\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\tconst [message, setMessage] = useState<TestRunnerStatusData | null>(null)\n\tconst [testSteps, setTestSteps] = useState<Array<TestRunnerTestStepData>>([])\n\n\tuseEffect(() => {\n\t\tfunction handleMessage(messageEvent: MessageEvent) {\n\t\t\tif (messageEvent.source !== iframeRef.current?.contentWindow) return\n\t\t\tif ('request' in messageEvent.data) return\n\n\t\t\tconst result = testRunnerDataSchema.safeParse(messageEvent.data, {\n\t\t\t\tpath: ['messageEvent', 'data'],\n\t\t\t})\n\t\t\tif (!result.success) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Invalid message from test iframe`,\n\t\t\t\t\tmessageEvent.data,\n\t\t\t\t\tresult.error,\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst { data } = result\n\t\t\tif (data.type === 'epicshop:test-status-update') {\n\t\t\t\tif (data.status === 'pending') {\n\t\t\t\t\tsetTestSteps([])\n\t\t\t\t}\n\t\t\t\tsetMessage(data)\n\t\t\t}\n\t\t\tif (data.type === 'epicshop:test-step-update') {\n\t\t\t\tsetTestSteps((steps) => [...steps, data])\n\t\t\t}\n\t\t}\n\t\twindow.addEventListener('message', handleMessage)\n\t\treturn () => {\n\t\t\twindow.removeEventListener('message', handleMessage)\n\t\t}\n\t}, [])\n\n\tconst statusEmoji = {\n\t\tpending: <AnimatedBars size={14} aria-label=\"Pending\" />,\n\t\tpass: (\n\t\t\t<Icon\n\t\t\t\tname=\"CheckSmall\"\n\t\t\t\taria-label=\"Passed\"\n\t\t\t\tclassName=\"text-emerald-700\"\n\t\t\t/>\n\t\t),\n\t\tfail: (\n\t\t\t<Icon\n\t\t\t\tname=\"Remove\"\n\t\t\t\taria-label=\"Failed\"\n\t\t\t\tclassName=\"text-foreground-destructive\"\n\t\t\t/>\n\t\t),\n\t\tunknown: (\n\t\t\t<Icon name=\"Question\" aria-label=\"Unknown\" className=\"animate-pulse\" />\n\t\t),\n\t}[message?.status ?? 'unknown']\n\n\tconst sortedTestSteps = testSteps.sort((a, b) => a.timestamp - b.timestamp)\n\tconst testStepStatusEmojis = {\n\t\tpass: <Icon name=\"CheckSmall\" aria-label=\"Passed\" />,\n\t\tfail: <Icon name=\"Remove\" aria-label=\"Failed\" />,\n\t\tunknown: (\n\t\t\t<Icon name=\"Question\" aria-label=\"Unknown\" className=\"animate-pulse\" />\n\t\t),\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<Accordion.Root className=\"w-full\" type=\"multiple\">\n\t\t\t\t<AccordionComponent\n\t\t\t\t\ticon={statusEmoji}\n\t\t\t\t\ttitle={testFile}\n\t\t\t\t\tforceMount={true}\n\t\t\t\t>\n\t\t\t\t\t<div className=\"not-prose\">\n\t\t\t\t\t\t<div className=\"flex flex-col gap-2 p-5 pt-3\">\n\t\t\t\t\t\t\t<ul className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t{sortedTestSteps.map((testStep, index) => (\n\t\t\t\t\t\t\t\t\t// sometimes the steps come in so fast that the timestamp is the same\n\t\t\t\t\t\t\t\t\t<li key={testStep.timestamp + testStep.title}>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-baseline gap-2 text-emerald-700\">\n\t\t\t\t\t\t\t\t\t\t\t<span>{index + 1}.</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>{testStepStatusEmojis[testStep.status]}</span>\n\t\t\t\t\t\t\t\t\t\t\t<pre className=\"scrollbar-thin scrollbar-thumb-scrollbar max-h-48 overflow-y-auto p-4\">\n\t\t\t\t\t\t\t\t\t\t\t\t{testStep.title}\n\t\t\t\t\t\t\t\t\t\t\t</pre>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t{message?.status === 'fail' ? (\n\t\t\t\t\t\t\t\t<div className=\"text-foreground-destructive flex items-baseline gap-2\">\n\t\t\t\t\t\t\t\t\t<span>{sortedTestSteps.length + 1}.</span>\n\t\t\t\t\t\t\t\t\t<span>{testStepStatusEmojis.fail}</span>\n\t\t\t\t\t\t\t\t\t<pre\n\t\t\t\t\t\t\t\t\t\tclassName=\"scrollbar-thin scrollbar-thumb-scrollbar max-h-48 overflow-y-auto p-4\"\n\t\t\t\t\t\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t\t\t\t\t\t__html: ansi.toHtml(stripCursorMovements(message.error)),\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<iframe\n\t\t\t\t\t\t\t\tref={iframeRef}\n\t\t\t\t\t\t\t\ttitle={testFile}\n\t\t\t\t\t\t\t\tsrc={pathname + testFile}\n\t\t\t\t\t\t\t\tclassName=\"mt-5 min-h-[420px] w-full border bg-white\"\n\t\t\t\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex border-y\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\t\t\t\tiframeRef.current?.contentWindow?.location.reload()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tclassName=\"border-r p-3\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" aria-label=\"Rerun Tests\" />\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={pathname + testFile}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName=\"border-r p-3\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" aria-label=\"Open in New Window\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</AccordionComponent>\n\t\t\t</Accordion.Root>\n\t\t</>\n\t)\n}\n","import { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport { userHasAccessToWorkshop } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tclearTestProcessEntry,\n\tgetTestProcessEntry,\n\tisTestRunning,\n\trunAppTests,\n} from '@epic-web/workshop-utils/process-manager.server'\nimport { useEffect, useReducer, useRef } from 'react'\nimport {\n\tdata,\n\ttype ActionFunctionArgs,\n\ttype LoaderFunctionArgs,\n\tuseFetcher,\n\tuseRevalidator,\n} from 'react-router'\nimport { useEventSource } from 'remix-utils/sse/react'\nimport { eventStream } from 'remix-utils/sse/server'\nimport { z } from 'zod'\nimport { AnimatedBars, Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { stripCursorMovements, useAnsiToHtml } from '#app/utils/ansi-text.ts'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nconst testActionSchema = z.union([\n\tz.object({\n\t\tintent: z.literal('run'),\n\t\tname: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('stop'),\n\t\tname: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('clear'),\n\t\tname: z.string(),\n\t}),\n])\n\nconst testEventSchema = z.union([\n\tz.object({\n\t\ttype: z.literal('init'),\n\t\texitCode: z.number().nullable().optional(),\n\t\tisRunning: z.boolean(),\n\t\toutput: z.array(\n\t\t\tz.object({\n\t\t\t\ttype: z.union([z.literal('stdout'), z.literal('stderr')]),\n\t\t\t\tcontent: z.string(),\n\t\t\t\ttimestamp: z.number(),\n\t\t\t}),\n\t\t),\n\t}),\n\tz.object({\n\t\ttype: z.union([z.literal('stdout'), z.literal('stderr')]),\n\t\tdata: z.string(),\n\t\ttimestamp: z.number(),\n\t}),\n\tz.object({\n\t\ttype: z.literal('exit'),\n\t\tisRunning: z.literal(false),\n\t\tcode: z.number().nullable(),\n\t}),\n])\nconst testEventQueueSchema = z.array(testEventSchema)\n\ntype TestEvent = z.infer<typeof testEventSchema>\ntype TestEventQueue = z.infer<typeof testEventQueueSchema>\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst url = new URL(request.url)\n\tconst name = url.searchParams.get('name')\n\tif (!name) {\n\t\treturn data({ error: 'Missing name' }, { status: 400 })\n\t}\n\tconst app = await getAppByName(name)\n\tif (!app) {\n\t\treturn data({ error: 'App not found' }, { status: 404 })\n\t}\n\tconst processEntry = getTestProcessEntry(app)\n\tif (!processEntry) {\n\t\treturn data({ error: 'App is not running tests' }, { status: 404 })\n\t}\n\treturn eventStream(request.signal, function setup(send) {\n\t\t// have to batch because the client may miss events if we send too many\n\t\t// too rapidly\n\t\tlet queue: TestEventQueue = []\n\t\tfunction sendEvent(event: TestEvent) {\n\t\t\tqueue.push(event)\n\t\t}\n\t\tconst interval = setInterval(() => {\n\t\t\tif (queue.length) {\n\t\t\t\tsend({ data: JSON.stringify(queue) })\n\t\t\t\tqueue = []\n\t\t\t}\n\t\t}, 10)\n\n\t\tconst isRunning = isTestRunning(app)\n\n\t\tsendEvent({\n\t\t\ttype: 'init',\n\t\t\texitCode: processEntry.exitCode,\n\t\t\tisRunning,\n\t\t\toutput: processEntry.output.map((line) => ({\n\t\t\t\ttype: line.type,\n\t\t\t\tcontent: line.content,\n\t\t\t\ttimestamp: line.timestamp,\n\t\t\t})),\n\t\t})\n\n\t\tconst testProcess = processEntry.process\n\t\tif (!testProcess) {\n\t\t\treturn () => {}\n\t\t}\n\n\t\tfunction handleStdOutData(data: Buffer) {\n\t\t\tsendEvent({\n\t\t\t\ttype: 'stdout',\n\t\t\t\tdata: data.toString('utf-8'),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t})\n\t\t}\n\t\tfunction handleStdErrData(data: Buffer) {\n\t\t\tsendEvent({\n\t\t\t\ttype: 'stderr',\n\t\t\t\tdata: data.toString('utf-8'),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t})\n\t\t}\n\t\tfunction handleExit(code: number) {\n\t\t\ttestProcess?.stdout?.off('data', handleStdOutData)\n\t\t\ttestProcess?.stderr?.off('data', handleStdErrData)\n\t\t\ttestProcess?.off('exit', handleExit)\n\t\t\tsendEvent({ type: 'exit', isRunning: false, code })\n\t\t}\n\t\ttestProcess.stdout?.on('data', handleStdOutData)\n\t\ttestProcess.stderr?.on('data', handleStdErrData)\n\t\ttestProcess.on('exit', handleExit)\n\t\treturn function cleanup() {\n\t\t\ttestProcess.stdout?.off('data', handleStdOutData)\n\t\t\ttestProcess.stderr?.off('data', handleStdErrData)\n\t\t\ttestProcess.off('exit', handleExit)\n\t\t\tclearInterval(interval)\n\t\t}\n\t})\n}\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst userHasAccess = await userHasAccessToWorkshop({\n\t\trequest,\n\t})\n\tif (!userHasAccess) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{\n\t\t\t\tsuccess: false,\n\t\t\t\terror:\n\t\t\t\t\t'You do not have access to this workshop. Login or register for the workshop to be able to run the tests.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tstatus: 403,\n\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\ttitle: 'Access denied',\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'You do not have access to this workshop. Login or register for the workshop to be able to run the tests.',\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t}\n\tconst result = testActionSchema.safeParse({\n\t\tintent: formData.get('intent'),\n\t\tname: formData.get('name'),\n\t})\n\tif (!result.success) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ success: false, error: result.error.flatten() },\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\tconst app = await getAppByName(result.data.name)\n\tif (!app) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ success: false, error: 'App not found' },\n\t\t\t{ status: 404 },\n\t\t)\n\t}\n\tswitch (result.data.intent) {\n\t\tcase 'run': {\n\t\t\tvoid runAppTests(app)\n\t\t\treturn dataWithPE(request, formData, { success: true })\n\t\t}\n\t\tcase 'stop': {\n\t\t\tconst processEntry = getTestProcessEntry(app)\n\t\t\tif (processEntry) {\n\t\t\t\tprocessEntry.process?.kill()\n\t\t\t}\n\t\t\treturn dataWithPE(request, formData, { success: true })\n\t\t}\n\t\tcase 'clear': {\n\t\t\tclearTestProcessEntry(app)\n\t\t\treturn dataWithPE(request, formData, { success: true })\n\t\t}\n\t}\n}\n\nfunction simpleReducer<State>(prev: State, getNext: (prev: State) => State) {\n\treturn getNext(prev)\n}\n\nexport function TestOutput({ name }: { name: string }) {\n\ttype State = {\n\t\t/** version is used to trigger an unsubscribe and resubscribe to the event source */\n\t\tversion: number\n\t\tisRunning: boolean\n\t\texitCode: number | null | undefined\n\t\tlines: Array<{\n\t\t\ttype: 'stdout' | 'stderr'\n\t\t\tcontent: string\n\t\t\ttimestamp: number\n\t\t}>\n\t}\n\tconst [state, dispatch] = useReducer(simpleReducer<State>, {\n\t\tversion: 0,\n\t\tisRunning: false,\n\t\texitCode: undefined,\n\t\tlines: [],\n\t})\n\tconst revalidator = useRevalidator()\n\tconst latestRevalidatorRef = useRef(revalidator)\n\tuseEffect(() => {\n\t\tlatestRevalidatorRef.current = revalidator\n\t}, [revalidator])\n\tconst ansi = useAnsiToHtml()\n\tconst { version, isRunning, exitCode, lines } = state\n\tconst lastMessage = useEventSource(\n\t\t`/test?${new URLSearchParams({ name })}&v=${version}`,\n\t)\n\tuseEffect(() => {\n\t\tif (!lastMessage) return\n\n\t\tconst parsed = JSON.parse(lastMessage)\n\t\tconst result = testEventQueueSchema.safeParse(parsed)\n\t\tif (!result.success) {\n\t\t\tconsole.error(result.error.flatten())\n\t\t\treturn\n\t\t}\n\t\tfor (const event of result.data) {\n\t\t\tswitch (event.type) {\n\t\t\t\tcase 'exit': {\n\t\t\t\t\tconst { isRunning, code: exitCode } = event\n\t\t\t\t\tdispatch((prev) => ({ ...prev, isRunning, exitCode }))\n\t\t\t\t\tvoid latestRevalidatorRef.current.revalidate()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'init': {\n\t\t\t\t\tconst { output, exitCode, isRunning } = event\n\t\t\t\t\tdispatch((prev) => ({ ...prev, lines: output, exitCode, isRunning }))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'stderr':\n\t\t\t\tcase 'stdout': {\n\t\t\t\t\tconst { type, data: content, timestamp } = event\n\t\t\t\t\tdispatch((prev) => ({\n\t\t\t\t\t\t...prev,\n\t\t\t\t\t\tlines: [...prev.lines, { type, content, timestamp }].sort(\n\t\t\t\t\t\t\t(a, b) => a.timestamp - b.timestamp,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tisRunning: true,\n\t\t\t\t\t}))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}, [lastMessage])\n\n\treturn (\n\t\t<div className=\"relative flex h-full w-full flex-col overflow-hidden\">\n\t\t\t<div className=\"flex h-12 w-full shrink-0 items-center justify-between border-b\">\n\t\t\t\t<div className=\"flex h-full items-center\">\n\t\t\t\t\t{!isRunning && (\n\t\t\t\t\t\t<TestRunner\n\t\t\t\t\t\t\tname={name}\n\t\t\t\t\t\t\tonRun={() => {\n\t\t\t\t\t\t\t\tdispatch((prev) => ({\n\t\t\t\t\t\t\t\t\t...prev,\n\t\t\t\t\t\t\t\t\texitCode: undefined,\n\t\t\t\t\t\t\t\t\tlines: [],\n\t\t\t\t\t\t\t\t\tversion: prev.version + 1,\n\t\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t\t{isRunning ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<div className=\"flex h-full grow items-center justify-center border-r px-3.5\">\n\t\t\t\t\t\t\t\t<AnimatedBars role=\"status\" aria-label=\"Running Tests\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<StopTest name={name} />\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\n\t\t\t\t{!isRunning && exitCode !== undefined && (\n\t\t\t\t\t<p className=\"pr-3.5 leading-none\">\n\t\t\t\t\t\t{exitCode === 0\n\t\t\t\t\t\t\t? `Tests passed`\n\t\t\t\t\t\t\t: `Test failed (exit code ${String(exitCode)})`}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t\t{!isRunning && exitCode !== undefined && (\n\t\t\t\t\t<ClearTest\n\t\t\t\t\t\tname={name}\n\t\t\t\t\t\tonClear={() => {\n\t\t\t\t\t\t\tdispatch((prev) => ({\n\t\t\t\t\t\t\t\t...prev,\n\t\t\t\t\t\t\t\texitCode: undefined,\n\t\t\t\t\t\t\t\tlines: [],\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"flex min-h-0 flex-1 flex-col gap-5 p-5\">\n\t\t\t\t<p className=\"font-mono text-sm font-medium uppercase\">Test Output</p>\n\t\t\t\t<pre className=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar min-h-0 flex-1 overflow-y-auto\">\n\t\t\t\t\t{lines.map((line) => (\n\t\t\t\t\t\t<code\n\t\t\t\t\t\t\tkey={line.timestamp}\n\t\t\t\t\t\t\tdata-type={line.type}\n\t\t\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t\t\t__html: ansi.toHtml(stripCursorMovements(line.content)),\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</pre>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nexport function TestRunner({\n\tname,\n\tonRun,\n}: {\n\tname: string\n\tonRun?: () => void\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst latestOnRun = useRef(onRun)\n\tuseEffect(() => {\n\t\tlatestOnRun.current = onRun\n\t}, [onRun])\n\tuseEffect(() => {\n\t\tif (fetcher.data?.success) {\n\t\t\tlatestOnRun.current?.()\n\t\t}\n\t}, [fetcher.data])\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/test\" className=\"h-full\">\n\t\t\t{peRedirectInput}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<SimpleTooltip\n\t\t\t\tcontent={fetcher.state === 'idle' ? 'Run Tests' : 'Running Tests...'}\n\t\t\t>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tname=\"intent\"\n\t\t\t\t\tvalue=\"run\"\n\t\t\t\t\tclassName=\"flex h-full grow items-center justify-center border-r px-3.5\"\n\t\t\t\t>\n\t\t\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t\t\t<Icon name=\"TriangleSmall\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<AnimatedBars role=\"status\" />\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t</SimpleTooltip>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function ClearTest({\n\tname,\n\tonClear,\n}: {\n\tname: string\n\tonClear?: () => void\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst latestOnClear = useRef(onClear)\n\tuseEffect(() => {\n\t\tlatestOnClear.current = onClear\n\t}, [onClear])\n\tuseEffect(() => {\n\t\tif (fetcher.data?.success) {\n\t\t\tlatestOnClear.current?.()\n\t\t}\n\t}, [fetcher.data])\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/test\" className=\"h-full\">\n\t\t\t{peRedirectInput}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<SimpleTooltip\n\t\t\t\tcontent={fetcher.state === 'idle' ? 'Clear Tests' : 'Clearing Tests...'}\n\t\t\t>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tname=\"intent\"\n\t\t\t\t\tvalue=\"clear\"\n\t\t\t\t\tclassName=\"flex h-full grow items-center justify-center border-l px-3.5\"\n\t\t\t\t>\n\t\t\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t\t\t<Icon name=\"Clear\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<Icon name=\"Clear\" className=\"animate-pulse\" role=\"status\" />\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t</SimpleTooltip>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function StopTest({\n\tname,\n\tonStop,\n}: {\n\tname: string\n\tonStop?: () => void\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst latestOnStop = useRef(onStop)\n\tuseEffect(() => {\n\t\tlatestOnStop.current = onStop\n\t}, [onStop])\n\tuseEffect(() => {\n\t\tif (fetcher.data?.success) {\n\t\t\tlatestOnStop.current?.()\n\t\t}\n\t}, [fetcher.data])\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/test\" className=\"h-full\">\n\t\t\t{peRedirectInput}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<SimpleTooltip\n\t\t\t\tcontent={fetcher.state === 'idle' ? 'Stop Tests' : 'Stopping Tests...'}\n\t\t\t>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tname=\"intent\"\n\t\t\t\t\tvalue=\"stop\"\n\t\t\t\t\tclassName=\"flex h-full grow items-center justify-center border-r px-3.5\"\n\t\t\t\t>\n\t\t\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t\t\t<Icon name=\"Stop\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<Icon name=\"Stop\" className=\"animate-pulse\" role=\"status\" />\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t</SimpleTooltip>\n\t\t</fetcher.Form>\n\t)\n}\n","import { type PlaygroundApp } from '@epic-web/workshop-utils/apps.server'\nimport { Suspense, useState } from 'react'\nimport { ErrorBoundary } from 'react-error-boundary'\nimport { Await } from 'react-router'\nimport { DeferredEpicVideo } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons'\nimport { InBrowserTestRunner } from '#app/components/in-browser-test-runner'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { TestOutput } from '#app/routes/test'\nimport { PlaygroundWindow } from './playground-window'\n\nexport function Tests({\n\tappInfo: playgroundAppInfo,\n\tproblemAppName,\n\tallApps,\n\tisUpToDate,\n\tuserHasAccessPromise,\n}: {\n\tappInfo: Pick<PlaygroundApp, 'appName' | 'name' | 'test'> | null\n\tproblemAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tisUpToDate: boolean\n\tuserHasAccessPromise: Promise<boolean>\n}) {\n\treturn (\n\t\t<PlaygroundWindow\n\t\t\tplaygroundAppName={playgroundAppInfo?.appName}\n\t\t\tproblemAppName={problemAppName}\n\t\t\tallApps={allApps}\n\t\t\tisUpToDate={isUpToDate}\n\t\t>\n\t\t\t<ErrorBoundary\n\t\t\t\tfallbackRender={() => (\n\t\t\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t\t\t<p className=\"text-2xl font-bold\">Error</p>\n\t\t\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\t\t\tThere was an error loading the user access.\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Suspense\n\t\t\t\t\tfallback={\n\t\t\t\t\t\t<div className=\"flex items-center justify-center p-8\">\n\t\t\t\t\t\t\t<SimpleTooltip content=\"Loading user access\">\n\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"animate-spin\" />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Await resolve={userHasAccessPromise}>\n\t\t\t\t\t\t{(userHasAccess) => (\n\t\t\t\t\t\t\t<TestUI\n\t\t\t\t\t\t\t\tplaygroundAppInfo={playgroundAppInfo}\n\t\t\t\t\t\t\t\tuserHasAccess={userHasAccess}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Await>\n\t\t\t\t</Suspense>\n\t\t\t</ErrorBoundary>\n\t\t</PlaygroundWindow>\n\t)\n}\n\nexport function TestUI({\n\tuserHasAccess,\n\tplaygroundAppInfo,\n}: {\n\tplaygroundAppInfo: Pick<PlaygroundApp, 'name' | 'test'> | null\n\tuserHasAccess: boolean\n}) {\n\tconst [inBrowserTestKey, setInBrowserTestKey] = useState(0)\n\n\tif (!userHasAccess) {\n\t\treturn (\n\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t<p className=\"text-2xl font-bold\">Access Denied</p>\n\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\tYou must login or register for the workshop to view and run the\n\t\t\t\t\t\ttests.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"h-16\" />\n\t\t\t\t<p className=\"pb-4\">\n\t\t\t\t\tCheck out this video to see how the test tab works.\n\t\t\t\t</p>\n\t\t\t\t<DeferredEpicVideo url=\"https://www.epicweb.dev/tips/epic-workshop-test-tab-demo\" />\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (!playgroundAppInfo) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>No tests here 😢 Sorry.</p>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (playgroundAppInfo.test.type === 'script') {\n\t\treturn <TestOutput name={playgroundAppInfo.name} />\n\t}\n\n\tif (playgroundAppInfo.test.type === 'browser') {\n\t\tconst { pathname } = playgroundAppInfo.test\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName=\"flex h-full min-h-0 w-full grow flex-col overflow-y-auto\"\n\t\t\t\tkey={inBrowserTestKey}\n\t\t\t>\n\t\t\t\t{playgroundAppInfo.test.testFiles.map((testFile) => (\n\t\t\t\t\t<div key={testFile}>\n\t\t\t\t\t\t<InBrowserTestRunner pathname={pathname} testFile={testFile} />\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t\t<div className=\"px-3 py-[21px]\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tonClick={() => setInBrowserTestKey((c) => c + 1)}\n\t\t\t\t\t\tclassName=\"flex items-center gap-2 font-mono text-sm leading-none uppercase\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Refresh\" aria-hidden /> Rerun All Tests\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t<p>No tests here 😢 Sorry.</p>\n\t\t</div>\n\t)\n}\n","import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tgetExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { userHasAccessToExerciseStep } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport * as Tabs from '@radix-ui/react-tabs'\nimport { clsx } from 'clsx'\nimport * as React from 'react'\nimport {\n\tLink,\n\tuseNavigate,\n\tuseSearchParams,\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tuseOutletContext,\n} from 'react-router'\nimport { Diff } from '#app/components/diff.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { StatusIndicator } from '#app/components/status-indicator.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { type Route } from './+types/index.ts'\nimport { fetchDiscordPosts } from './__shared/discord.server.ts'\nimport { DiscordChat } from './__shared/discord.tsx'\nimport { Playground } from './__shared/playground.tsx'\nimport { Preview } from './__shared/preview.tsx'\nimport { Tests } from './__shared/tests.tsx'\nimport { getAppRunningState, getTestState } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exerciseStepTypeIndexLoader')\n\tconst searchParams = new URL(request.url).searchParams\n\tconst cacheOptions = { request, timings }\n\n\tconst [exerciseStepApp, allAppsFull, problemApp, solutionApp] =\n\t\tawait Promise.all([\n\t\t\trequireExerciseApp(params, cacheOptions),\n\t\t\tgetApps(cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'problem' }, cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'solution' }, cacheOptions),\n\t\t])\n\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\tconst reqUrl = new URL(request.url)\n\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: playgroundApp || problemApp\n\tconst app2 = app2Name ? await getAppByName(app2Name) : solutionApp\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\treturn data(\n\t\t{\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\tallApps,\n\t\t\t// defer this promise so that we don't block the response from being sent\n\t\t\tdiscordPostsPromise: fetchDiscordPosts({ request }),\n\t\t\tuserHasAccessPromise: userHasAccessToExerciseStep({\n\t\t\t\texerciseNumber: Number(params.exerciseNumber),\n\t\t\t\tstepNumber: Number(params.stepNumber),\n\t\t\t\trequest,\n\t\t\t\ttimings,\n\t\t\t}),\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t\ttest: playgroundApp.test,\n\t\t\t\t\t\ttitle: playgroundApp.title,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tisUpToDate: playgroundApp.isUpToDate,\n\t\t\t\t\t\tstackBlitzUrl: playgroundApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(playgroundApp)),\n\t\t\t\t\t\t...getTestState(playgroundApp),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t\ttest: problemApp.test,\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tstackBlitzUrl: problemApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(problemApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t\ttest: solutionApp.test,\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tstackBlitzUrl: solutionApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(solutionApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiff: getDiffProp(),\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst tabs = [\n\t'playground',\n\t'problem',\n\t'solution',\n\t'tests',\n\t'diff',\n\t'chat',\n] as const\nconst isValidPreview = (s: string | null): s is (typeof tabs)[number] =>\n\tBoolean(s && tabs.includes(s as (typeof tabs)[number]))\n\nfunction withParam(\n\tsearchParams: URLSearchParams,\n\tkey: string,\n\tvalue: string | null,\n) {\n\tconst newSearchParams = new URLSearchParams(searchParams)\n\tif (value === null) {\n\t\tnewSearchParams.delete(key)\n\t} else {\n\t\tnewSearchParams.set(key, value)\n\t}\n\treturn newSearchParams\n}\n\nexport default function ExercisePartRoute({\n\tloaderData,\n}: Route.ComponentProps) {\n\tconst { inBrowserBrowserRef } = useOutletContext<{\n\t\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\t}>()\n\tconst workshopConfig = useWorkshopConfig()\n\tconst [searchParams] = useSearchParams()\n\n\tconst preview = searchParams.get('preview')\n\n\tconst altDown = useAltDown()\n\tconst navigate = useNavigate()\n\n\tfunction shouldHideTab(tab: (typeof tabs)[number]) {\n\t\tif (tab === 'tests') {\n\t\t\treturn (\n\t\t\t\tENV.EPICSHOP_DEPLOYED ||\n\t\t\t\t!loaderData.playground ||\n\t\t\t\tloaderData.playground.test.type === 'none'\n\t\t\t)\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution') {\n\t\t\tif (loaderData[tab]?.dev.type === 'none') return true\n\t\t\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\t\t\treturn (\n\t\t\t\t\tloaderData[tab]?.dev.type !== 'browser' &&\n\t\t\t\t\t!loaderData[tab]?.stackBlitzUrl\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tif (tab === 'playground' && ENV.EPICSHOP_DEPLOYED) return true\n\n\t\tif (tab === 'chat') {\n\t\t\treturn !workshopConfig.product.discordChannelId\n\t\t}\n\t\treturn false\n\t}\n\n\tfunction getTabStatus(\n\t\ttab: (typeof tabs)[number],\n\t): 'running' | 'passed' | 'failed' | null {\n\t\tif (tab === 'tests') {\n\t\t\tif (!loaderData.playground) return null\n\t\t\tconst { isTestRunning, testExitCode } = loaderData.playground\n\t\t\tif (isTestRunning) return 'running'\n\t\t\tif (testExitCode === 0) return 'passed'\n\t\t\tif (testExitCode !== null && testExitCode !== 0) return 'failed'\n\t\t\treturn null\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution' || tab === 'playground') {\n\t\t\tconst appData =\n\t\t\t\ttab === 'playground' ? loaderData.playground : loaderData[tab]\n\t\t\tif (appData?.isRunning) return 'running'\n\t\t}\n\t\treturn null\n\t}\n\n\tconst activeTab = isValidPreview(preview)\n\t\t? preview\n\t\t: tabs.find((t) => !shouldHideTab(t))\n\n\t// when alt is held down, the diff tab should open to the full-page diff view\n\t// between the problem and solution (this is more for the instructor than the student)\n\tconst altDiffUrl = `/diff?${new URLSearchParams({\n\t\tapp1: loaderData.problem?.name ?? '',\n\t\tapp2: loaderData.solution?.name ?? '',\n\t})}`\n\n\tfunction handleDiffTabClick(event: React.MouseEvent<HTMLAnchorElement>) {\n\t\tif (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) {\n\t\t\tevent.preventDefault()\n\t\t\tvoid navigate(altDiffUrl)\n\t\t}\n\t}\n\n\treturn (\n\t\t<Tabs.Root\n\t\t\tclassName=\"relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden sm:col-span-1 sm:row-span-1\"\n\t\t\tvalue={activeTab}\n\t\t\t// intentionally no onValueChange here because the Link will trigger the\n\t\t\t// change.\n\t\t>\n\t\t\t<Tabs.List className=\"scrollbar-thin scrollbar-thumb-scrollbar h-14 min-h-14 overflow-x-auto border-b whitespace-nowrap\">\n\t\t\t\t{tabs.map((tab) => {\n\t\t\t\t\tconst hidden = shouldHideTab(tab)\n\t\t\t\t\tconst status = getTabStatus(tab)\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Tabs.Trigger key={tab} value={tab} hidden={hidden} asChild>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tid={`${tab}-tab`}\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'clip-path-button radix-state-active:z-10 radix-state-active:bg-foreground radix-state-active:text-background radix-state-active:hover:bg-foreground/80 radix-state-active:hover:text-background/80 radix-state-inactive:hover:bg-foreground/20 radix-state-inactive:hover:text-foreground/80 focus:bg-foreground/80 focus:text-background/80 relative h-full px-6 py-4 font-mono text-sm uppercase outline-none',\n\t\t\t\t\t\t\t\t\thidden ? 'hidden' : 'inline-block',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tpreventScrollReset\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tonClick={handleDiffTabClick}\n\t\t\t\t\t\t\t\tto={\n\t\t\t\t\t\t\t\t\ttab === 'diff' && altDown\n\t\t\t\t\t\t\t\t\t\t? altDiffUrl\n\t\t\t\t\t\t\t\t\t\t: `?${withParam(\n\t\t\t\t\t\t\t\t\t\t\t\tsearchParams,\n\t\t\t\t\t\t\t\t\t\t\t\t'preview',\n\t\t\t\t\t\t\t\t\t\t\t\ttab === 'playground' ? null : tab,\n\t\t\t\t\t\t\t\t\t\t\t)}`\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t{status && <StatusIndicator status={status} />}\n\t\t\t\t\t\t\t\t\t<span>{tab}</span>\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</Tabs.Trigger>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t</Tabs.List>\n\t\t\t<div className=\"relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden\">\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"playground\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Playground\n\t\t\t\t\t\tappInfo={loaderData.playground}\n\t\t\t\t\t\tproblemAppName={loaderData.problem?.name}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tisUpToDate={loaderData.playground?.isUpToDate ?? false}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"problem\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={loaderData.problem}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"solution\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={loaderData.solution}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"tests\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start overflow-hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Tests\n\t\t\t\t\t\tappInfo={loaderData.playground}\n\t\t\t\t\t\tproblemAppName={loaderData.problem?.name}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tisUpToDate={loaderData.playground?.isUpToDate ?? false}\n\t\t\t\t\t\tuserHasAccessPromise={loaderData.userHasAccessPromise}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"diff\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t>\n\t\t\t\t\t<Diff\n\t\t\t\t\t\tdiff={loaderData.diff}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tuserHasAccessPromise={loaderData.userHasAccessPromise}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"chat\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t>\n\t\t\t\t\t<DiscordChat />\n\t\t\t\t</Tabs.Content>\n\t\t\t</div>\n\t\t</Tabs.Root>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import { requireExerciseApp } from '@epic-web/workshop-utils/apps.server'\nimport { userHasAccessToExerciseStep } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport {\n\tdata,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tuseLoaderData,\n} from 'react-router'\nimport { TestUI } from './__shared/tests.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exercise-step-test')\n\tconst exerciseStepApp = await requireExerciseApp(params, { request, timings })\n\n\treturn data(\n\t\t{\n\t\t\tappInfo: {\n\t\t\t\tname: exerciseStepApp?.name,\n\t\t\t\ttest: exerciseStepApp?.test,\n\t\t\t},\n\t\t\tuserHasAccess: await userHasAccessToExerciseStep({\n\t\t\t\texerciseNumber: Number(params.exerciseNumber),\n\t\t\t\tstepNumber: Number(params.stepNumber),\n\t\t\t\trequest,\n\t\t\t\ttimings,\n\t\t\t}),\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nexport default function TestsList() {\n\tconst { appInfo, userHasAccess } = useLoaderData<typeof loader>()\n\n\treturn (\n\t\t<TestUI\n\t\t\tkey={appInfo.name}\n\t\t\tplaygroundAppInfo={appInfo}\n\t\t\tuserHasAccess={userHasAccess}\n\t\t/>\n\t)\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport {\n\tgetExerciseApp,\n\tisProblemApp,\n\tisSolutionApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { getStep404Data } from './__shared/error-boundary.server.ts'\nimport { Exercise404ErrorBoundary } from './__shared/error-boundary.tsx'\n\nexport async function loader({ params }: LoaderFunctionArgs) {\n\tinvariantResponse(params.exerciseNumber, 'exerciseNumber is required')\n\tconst problemApp = await getExerciseApp({ ...params, type: 'problem' }).then(\n\t\t(a) => (isProblemApp(a) ? a : null),\n\t)\n\tif (problemApp) {\n\t\treturn redirect(\n\t\t\t`/exercise/${params.exerciseNumber}/${params.stepNumber}/problem`,\n\t\t)\n\t}\n\tconst solutionApp = await getExerciseApp({\n\t\t...params,\n\t\ttype: 'solution',\n\t}).then((a) => (isSolutionApp(a) ? a : null))\n\tif (solutionApp) {\n\t\treturn redirect(\n\t\t\t`/exercise/${params.exerciseNumber}/${params.stepNumber}/solution`,\n\t\t)\n\t}\n\tthrow Response.json(\n\t\tawait getStep404Data({ exerciseNumber: params.exerciseNumber }),\n\t\t{ status: 404 },\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tclassName=\"container flex items-center justify-center\"\n\t\t\tstatusHandlers={{\n\t\t\t\t404: Exercise404ErrorBoundary,\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import path from 'path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetAppPageRoute,\n\tgetApps,\n\tgetExercise,\n\tgetWorkshopRoot,\n\tisExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport * as React from 'react'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { type Route } from './+types/$exerciseNumber_.finished.tsx'\n\nexport const meta: Route.MetaFunction = ({ loaderData, matches }) => {\n\tconst number = loaderData?.exercise.exerciseNumber.toString().padStart(2, '0')\n\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!loaderData || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🦉 | ${number}. ${loaderData.exercise.title} | ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${number}. ${loaderData.exercise.title}`,\n\t\togTitle: `Finished: ${loaderData.exercise.title}`,\n\t\togDescription: `Elaboration for exercise ${Number(number)}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('exerciseFinishedLoader')\n\tinvariantResponse(params.exerciseNumber, 'exerciseNumber is required')\n\tconst exercise = await getExercise(params.exerciseNumber, {\n\t\ttimings,\n\t\trequest,\n\t})\n\tif (!exercise) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\n\tconst workshopConfig = getWorkshopConfig()\n\tconst exerciseFormTemplate = workshopConfig.forms.exercise\n\tconst exerciseFormEmbedUrl = exerciseFormTemplate\n\t\t.replace('{workshopTitle}', encodeURIComponent(workshopConfig.title))\n\t\t.replace('{exerciseTitle}', encodeURIComponent(exercise.title))\n\tconst nextExercise = await getExercise(exercise.exerciseNumber + 1, {\n\t\ttimings,\n\t\trequest,\n\t})\n\n\tconst finishedFilepath = path.join(\n\t\tgetWorkshopRoot(),\n\t\t'exercises',\n\t\texercise.dirName,\n\t\t'FINISHED.mdx',\n\t)\n\n\tconst apps = await getApps({ request, timings })\n\tconst exerciseApps = apps\n\t\t.filter(isExerciseStepApp)\n\t\t.filter((app) => app.exerciseNumber === exercise.exerciseNumber)\n\tconst prevApp = exerciseApps[exerciseApps.length - 1]\n\n\tconst articleId = `workshop-${slugify(workshopConfig.title)}-${\n\t\texercise.exerciseNumber\n\t}-finished`\n\n\treturn data(\n\t\t{\n\t\t\tarticleId,\n\t\t\tworkshopTitle: workshopConfig.title,\n\t\t\texercise,\n\t\t\texerciseFormEmbedUrl,\n\t\t\tepicVideoInfosPromise: getEpicVideoInfos(\n\t\t\t\texercise.finishedEpicVideoEmbeds,\n\t\t\t\t{ request },\n\t\t\t),\n\t\t\texerciseFinished: {\n\t\t\t\tfile: finishedFilepath,\n\t\t\t\trelativePath: `exercises/${exercise.dirName}/FINISHED.mdx`,\n\t\t\t},\n\t\t\tprevStepLink: prevApp\n\t\t\t\t? {\n\t\t\t\t\t\tto: getAppPageRoute(prevApp),\n\t\t\t\t\t\t'aria-label': `${prevApp.title} (${prevApp.type})`,\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t\tnextStepLink: nextExercise\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${nextExercise.exerciseNumber.toString().padStart(2, '0')}`,\n\t\t\t\t\t\t'aria-label': `${nextExercise.title}`,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tto: '/finished',\n\t\t\t\t\t\t'aria-label': 'Finished! 🎉',\n\t\t\t\t\t},\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst mdxComponents = { h1: () => null }\nexport default function ExerciseFinished({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tconst exerciseNumber = data.exercise.exerciseNumber\n\t\t.toString()\n\t\t.padStart(2, '0')\n\n\tuseRevalidationWS({\n\t\twatchPaths: [`./exercises/${exerciseNumber}/FINISHED.mdx`],\n\t})\n\n\treturn (\n\t\t<div className=\"flex max-w-full grow flex-col\">\n\t\t\t<main className=\"flex grow flex-col sm:grid sm:h-full sm:min-h-[800px] sm:grid-cols-1 sm:grid-rows-2 md:min-h-[unset] lg:grid-cols-2 lg:grid-rows-1\">\n\t\t\t\t<div className=\"relative flex flex-col sm:col-span-1 sm:row-span-1 sm:h-full lg:border-r\">\n\t\t\t\t\t<h1 className=\"h-14 border-b pr-5 pl-10 text-sm leading-tight font-medium\">\n\t\t\t\t\t\t<div className=\"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2\">\n\t\t\t\t\t\t\t\t<Link to={`/${exerciseNumber}`} className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{`${exerciseNumber}. ${data.exercise.title}`}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t<span>/</span>\n\t\t\t\t\t\t\t\t<span>Elaboration</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\n\t\t\t\t\t<article\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8\"\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.exercise.finishedCode ? (\n\t\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\t\tcode={data.exercise.finishedCode}\n\t\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t// TODO: render a random dad joke...\n\t\t\t\t\t\t\t'No finished instructions yet...'\n\t\t\t\t\t\t)}\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\texerciseNumber={data.exercise.exerciseNumber}\n\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\tfile={data.exerciseFinished.file}\n\t\t\t\t\t\t\trelativePath={data.exerciseFinished.relativePath}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<NavChevrons prev={data.prevStepLink} next={data.nextStepLink} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<Survey\n\t\t\t\t\texerciseFormEmbedUrl={data.exerciseFormEmbedUrl}\n\t\t\t\t\texerciseTitle={data.exercise.title}\n\t\t\t\t/>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nfunction Survey({\n\texerciseFormEmbedUrl,\n\texerciseTitle,\n}: {\n\texerciseFormEmbedUrl: string\n\texerciseTitle: string\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"relative shrink-0\">\n\t\t\t\t<div className=\"text-body-md text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{'Unable to load the '}\n\t\t\t\t\t\t\t<a href={exerciseFormEmbedUrl} className=\"underline\">\n\t\t\t\t\t\t\t\t{`${exerciseTitle} feedback form`}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{' when offline'}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\treturn (\n\t\t<div className=\"relative min-h-full sm:min-h-[unset] sm:shrink-0\">\n\t\t\t{!iframeLoaded ? (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>Loading {exerciseTitle} Elaboration form</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\ttitle=\"Elaboration\"\n\t\t\t\tsrc={exerciseFormEmbedUrl}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n","import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopFinished,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport slugify from '@sindresorhus/slugify'\nimport * as React from 'react'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { EditFileOnGitHub } from '../launch-editor.tsx'\nimport { ProgressToggle } from '../progress.tsx'\nimport { useTheme } from '../theme/index.tsx'\nimport { type Route } from './+types/finished.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => [{ route: '/finished' }],\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!rootData) return []\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🎉 ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${rootData?.workshopTitle}`,\n\t\togTitle: `Finished ${rootData?.workshopTitle}`,\n\t\togDescription: `You finished! Time to submit feedback.`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('finishedLoader')\n\tconst exercises = await getExercises({ request, timings })\n\tconst compiledFinished = await time(() => getWorkshopFinished({ request }), {\n\t\ttimings,\n\t\ttype: 'compileMdx',\n\t\tdesc: 'compileMdx in finished',\n\t})\n\n\tconst lastExercises = exercises[exercises.length - 1]\n\tconst workshopConfig = getWorkshopConfig()\n\tconst workshopTitle = workshopConfig.title\n\tconst workshopFormTemplate = workshopConfig.forms.workshop\n\tconst workshopFormEmbedUrl = workshopFormTemplate.replace(\n\t\t'{workshopTitle}',\n\t\tencodeURIComponent(workshopTitle),\n\t)\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(workshopTitle)}-finished`,\n\t\t\tworkshopTitle,\n\t\t\tworkshopFormEmbedUrl,\n\t\t\tfinishedCode:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? compiledFinished.compiled.code\n\t\t\t\t\t: null,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(compiledFinished.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t\tworkshopFinished: {\n\t\t\t\tstatus: compiledFinished.compiled.status,\n\t\t\t\tfile: compiledFinished.file,\n\t\t\t\trelativePath: compiledFinished.relativePath,\n\t\t\t},\n\t\t\tprevStepLink: lastExercises\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/${lastExercises.exerciseNumber}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function ExerciseFinished({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tuseRevalidationWS({ watchPaths: ['./exercises/FINISHED.mdx'] })\n\treturn (\n\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t<main className=\"grid h-full grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1\">\n\t\t\t\t<div className=\"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r\">\n\t\t\t\t\t<h1 className=\"h-14 border-b pr-5 pl-10 text-sm leading-none font-medium uppercase\">\n\t\t\t\t\t\t<div className=\"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2\">\n\t\t\t\t\t\t\t\t<Link to=\"/\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{data.workshopTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t<span>/</span>\n\t\t\t\t\t\t\t\t<span>Elaboration</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8\"\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.finishedCode ? (\n\t\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t\t<Mdx code={data.finishedCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t// TODO: render a random dad joke...\n\t\t\t\t\t\t\t'No finished instructions yet...'\n\t\t\t\t\t\t)}\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\ttype=\"workshop-finished\"\n\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t{data.workshopFinished.status === 'success' ? (\n\t\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\t\tfile={data.workshopFinished.file}\n\t\t\t\t\t\t\t\trelativePath={data.workshopFinished.relativePath}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<NavChevrons prev={data.prevStepLink} next={{ to: '/' }} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<Survey\n\t\t\t\t\tworkshopTitle={data.workshopTitle}\n\t\t\t\t\tworkshopFormEmbedUrl={data.workshopFormEmbedUrl}\n\t\t\t\t/>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nfunction Survey({\n\tworkshopTitle,\n\tworkshopFormEmbedUrl,\n}: {\n\tworkshopTitle: string\n\tworkshopFormEmbedUrl: string\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"relative shrink-0\">\n\t\t\t\t<div className=\"text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{'Unable to load the '}\n\t\t\t\t\t\t\t<a href={workshopFormEmbedUrl} className=\"underline\">\n\t\t\t\t\t\t\t\t{`${workshopTitle} feedback form`}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{' when offline'}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\treturn (\n\t\t<div className=\"relative shrink-0\">\n\t\t\t{!iframeLoaded ? (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>Loading {workshopTitle} Elaboration form</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\ttitle=\"Elaboration\"\n\t\t\t\tsrc={workshopFormEmbedUrl}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n","import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopInstructions,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { ProgressToggle, useExerciseProgressClassName } from '../progress.tsx'\nimport { type Route } from './+types/index.tsx'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('indexLoader')\n\tconst { title } = getWorkshopConfig()\n\tconst [exercises, workshopReadme] = await Promise.all([\n\t\ttime(() => getExercises({ request, timings }), {\n\t\t\ttimings,\n\t\t\ttype: 'getExercises',\n\t\t\tdesc: 'getExercises in index',\n\t\t}),\n\t\ttime(() => getWorkshopInstructions({ request }), {\n\t\t\ttimings,\n\t\t\ttype: 'compileMdx',\n\t\t\tdesc: 'compileMdx in index',\n\t\t}),\n\t])\n\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(title)}-instructions`,\n\t\t\ttitle:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? workshopReadme.compiled.title\n\t\t\t\t\t: title,\n\t\t\texercises: exercises.map((e) => ({\n\t\t\t\texerciseNumber: e.exerciseNumber,\n\t\t\t\ttitle: e.title,\n\t\t\t})),\n\t\t\tworkshopReadme,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(workshopReadme.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nfunction ExerciseListItem({\n\tindex,\n\texercise,\n}: {\n\tindex: number\n\texercise: Awaited<Route.ComponentProps['loaderData']>['exercises'][number]\n}) {\n\tconst progressClassName = useExerciseProgressClassName(\n\t\texercise.exerciseNumber,\n\t)\n\treturn (\n\t\t<li key={exercise.exerciseNumber}>\n\t\t\t<Link\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition after:absolute after:right-10 after:-translate-x-2 after:opacity-0 after:transition after:content-['→'] hover:bg-gray-50 hover:after:translate-x-0 hover:after:opacity-100 dark:hover:bg-white/5\",\n\t\t\t\t\tprogressClassName,\n\t\t\t\t)}\n\t\t\t\tto={`${exercise.exerciseNumber.toString().padStart(2, '0')}`}\n\t\t\t\tdata-keyboard-action={index === 0 ? 'g+n' : undefined}\n\t\t\t>\n\t\t\t\t<span className=\"text-xs font-normal tabular-nums opacity-50\">\n\t\t\t\t\t{exercise.exerciseNumber}\n\t\t\t\t</span>\n\t\t\t\t<span>{exercise.title}</span>\n\t\t\t</Link>\n\t\t</li>\n\t)\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function Index({ loaderData: data }: Route.ComponentProps) {\n\tconst exerciseLinks = (\n\t\t<ul className=\"divide-border dark:divide-border/50 flex flex-col divide-y\">\n\t\t\t<strong className=\"px-10 pb-3 font-mono text-xs uppercase\">\n\t\t\t\tExercises\n\t\t\t</strong>\n\t\t\t{data.exercises.map((exercise, index) => (\n\t\t\t\t<ExerciseListItem\n\t\t\t\t\tkey={exercise.exerciseNumber}\n\t\t\t\t\tindex={index}\n\t\t\t\t\texercise={exercise}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</ul>\n\t)\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"px-10 text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold\">\n\t\t\t\t\t\t{data.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"w-full max-w-none scroll-pt-6 border-t px-3 pt-3 md:px-10 md:pt-8\">\n\t\t\t\t\t<h2 className=\"pb-5 font-mono text-xs font-semibold uppercase\">\n\t\t\t\t\t\tIntro\n\t\t\t\t\t</h2>\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.workshopReadme.compiled.code}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t) : data.workshopReadme.compiled.status === 'error' ? (\n\t\t\t\t\t\t<div className=\"text-red-500\">\n\t\t\t\t\t\t\tThere was an error:\n\t\t\t\t\t\t\t<pre>{data.workshopReadme.compiled.error}</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No instructions yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"pt-10 pb-5\">\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code &&\n\t\t\t\t\tdata.workshopReadme.compiled.code.length > 500\n\t\t\t\t\t\t? exerciseLinks\n\t\t\t\t\t\t: null}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t<ProgressToggle\n\t\t\t\ttype=\"workshop-instructions\"\n\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t/>\n\t\t\t<div className=\"flex h-16 justify-center border-t\">\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.workshopReadme.file}\n\t\t\t\t\trelativePath={data.workshopReadme.relativePath}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn <GeneralErrorBoundary />\n}\n","import { getExercises } from '@epic-web/workshop-utils/apps.server'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst exercises = await getExercises({ request })\n\tif (!exercises.length) {\n\t\tthrow new Response('No exercises found', { status: 404 })\n\t}\n\n\tconst lastExercise = exercises[exercises.length - 1]\n\tif (!lastExercise || !lastExercise.steps || !lastExercise.steps.length) {\n\t\tthrow new Response('No steps found in last exercise', { status: 404 })\n\t}\n\n\tconst lastStep = lastExercise.steps[lastExercise.steps.length - 1]\n\tif (!lastStep || !lastStep.solution) {\n\t\tthrow new Response('No solution found for last step', { status: 404 })\n\t}\n\n\tconst exerciseNumber = lastExercise.exerciseNumber.toString().padStart(2, '0')\n\tconst stepNumber = lastStep.stepNumber.toString().padStart(2, '0')\n\treturn redirect(`/exercise/${exerciseNumber}/${stepNumber}/solution`)\n}\n\nexport default function LastExerciseRedirect() {\n\treturn null\n}\n","export const EVENTS = {\n\tUSER_CODE_RECEIVED: 'USER_CODE_RECEIVED',\n\tAUTH_RESOLVED: 'AUTH_RESOLVED',\n\tAUTH_REJECTED: 'AUTH_REJECTED',\n} as const\nexport type EventTypes = keyof typeof EVENTS\n","import { EventEmitter } from 'events'\nimport { remember } from '@epic-web/remember'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { setAuthInfo } from '@epic-web/workshop-utils/db.server'\nimport { getUserInfo } from '@epic-web/workshop-utils/epic-api.server'\nimport { logger } from '@epic-web/workshop-utils/logger'\nimport * as client from 'openid-client'\nimport { z } from 'zod'\nimport { EVENTS } from './auth-events.ts'\nimport { getErrorMessage } from './misc.tsx'\n\nconst log = logger('epic:auth')\n\nconst UserInfoSchema = z.object({\n\tid: z.string(),\n\temail: z.string(),\n\tname: z.string().nullable().optional(),\n})\n\nexport const authEmitter = remember('authEmitter', () => new EventEmitter())\n// cleanup any that may exist already\nauthEmitter.removeAllListeners()\n\nexport async function registerDevice() {\n\tlog('Starting device registration process')\n\tconst {\n\t\tproduct: { host },\n\t} = getWorkshopConfig()\n\tconst { ISSUER = `https://${host}/oauth` } = process.env\n\tlog.info(`Using OAuth issuer: ${ISSUER}`)\n\n\ttry {\n\t\tlog('Discovering OAuth configuration')\n\t\tconst config = await client.discovery(new URL(ISSUER), 'EPICSHOP_APP')\n\t\tlog.info('OAuth configuration discovered successfully')\n\n\t\tlog('Initiating device authorization')\n\t\tconst deviceResponse = await client.initiateDeviceAuthorization(config, {})\n\t\tlog.info(\n\t\t\t`Device authorization initiated - user code: ${deviceResponse.user_code}`,\n\t\t)\n\n\t\tauthEmitter.emit(EVENTS.USER_CODE_RECEIVED, {\n\t\t\tcode: deviceResponse.user_code,\n\t\t\turl: deviceResponse.verification_uri_complete,\n\t\t})\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\tlog.error('Device authorization timed out')\n\t\t\tthrow new Error('Device authorization timed out')\n\t\t}, deviceResponse.expires_in * 1000)\n\n\t\ttry {\n\t\t\tlog('Polling for device authorization grant')\n\t\t\tconst tokenSet = await client.pollDeviceAuthorizationGrant(\n\t\t\t\tconfig,\n\t\t\t\tdeviceResponse,\n\t\t\t)\n\t\t\tclearTimeout(timeout)\n\n\t\t\tif (!tokenSet) {\n\t\t\t\tlog.error('No token set received from device authorization')\n\t\t\t\tauthEmitter.emit(EVENTS.AUTH_REJECTED, {\n\t\t\t\t\terror: 'No token set',\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.info('Device authorization grant received successfully')\n\n\t\t\tlog('Fetching user info from protected resource')\n\t\t\tconst protectedResourceResponse = await client.fetchProtectedResource(\n\t\t\t\tconfig,\n\t\t\t\ttokenSet.access_token,\n\t\t\t\tnew URL(`${ISSUER}/userinfo`),\n\t\t\t\t'GET',\n\t\t\t)\n\t\t\tconst userinfoRaw = await protectedResourceResponse.json()\n\t\t\tlog.info('User info fetched from protected resource')\n\n\t\t\tconst userinfoResult = UserInfoSchema.safeParse(userinfoRaw)\n\t\t\tif (!userinfoResult.success) {\n\t\t\t\tlog.error(`Failed to parse user info: ${userinfoResult.error.message}`)\n\t\t\t\tauthEmitter.emit(EVENTS.AUTH_REJECTED, {\n\t\t\t\t\terror: `Failed to parse user info: ${userinfoResult.error.message}`,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst userinfo = userinfoResult.data\n\t\t\tlog.info(\n\t\t\t\t`User info parsed successfully - ID: ${userinfo.id}, Email: ${userinfo.email}`,\n\t\t\t)\n\n\t\t\tlog('Setting auth info in database')\n\t\t\tawait setAuthInfo({\n\t\t\t\tid: userinfo.id,\n\t\t\t\ttokenSet,\n\t\t\t\temail: userinfo.email,\n\t\t\t\tname: userinfo.name,\n\t\t\t})\n\t\t\tlog.info('Auth info saved to database successfully')\n\n\t\t\tlog('Fetching fresh user info from API')\n\t\t\tawait getUserInfo({ forceFresh: true })\n\t\t\tlog.info('Fresh user info fetched successfully')\n\n\t\t\tlog('Authentication process completed successfully')\n\t\t\tauthEmitter.emit(EVENTS.AUTH_RESOLVED)\n\t\t} catch (error) {\n\t\t\tclearTimeout(timeout)\n\t\t\tlog.error('Error during device authorization polling:', error)\n\t\t\tthrow error\n\t\t}\n\t} catch (error) {\n\t\tlog.error('Device registration failed:', error)\n\t\tauthEmitter.emit(EVENTS.AUTH_REJECTED, {\n\t\t\terror: getErrorMessage(error),\n\t\t})\n\t}\n}\n","import { type LoaderFunctionArgs } from 'react-router'\nimport { eventStream } from 'remix-utils/sse/server'\nimport { z } from 'zod'\nimport { EVENTS } from '#app/utils/auth-events.ts'\nimport { authEmitter } from '#app/utils/auth.server.ts'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\n\nconst CodeReceivedEventSchema = z.object({\n\ttype: z.literal(EVENTS.USER_CODE_RECEIVED),\n\tcode: z.string(),\n\turl: z.string(),\n})\nconst AuthResolvedEventSchema = z.object({\n\ttype: z.literal(EVENTS.AUTH_RESOLVED),\n})\nconst AuthRejectedEventSchema = z.object({\n\ttype: z.literal(EVENTS.AUTH_REJECTED),\n\terror: z.string().optional().default('Unknown error'),\n})\nexport const EventSchema = z.union([\n\tCodeReceivedEventSchema,\n\tAuthResolvedEventSchema,\n\tAuthRejectedEventSchema,\n])\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\treturn eventStream(request.signal, function setup(send) {\n\t\tfunction handleCodeReceived(data: any) {\n\t\t\tsend({\n\t\t\t\tdata: JSON.stringify(\n\t\t\t\t\tCodeReceivedEventSchema.parse({\n\t\t\t\t\t\ttype: EVENTS.USER_CODE_RECEIVED,\n\t\t\t\t\t\t...data,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t})\n\t\t}\n\t\tfunction handleAuthResolved() {\n\t\t\tsend({ data: JSON.stringify({ type: EVENTS.AUTH_RESOLVED }) })\n\t\t}\n\t\tfunction handleAuthRejected(data: any) {\n\t\t\tconst result = AuthRejectedEventSchema.safeParse({\n\t\t\t\ttype: EVENTS.AUTH_REJECTED,\n\t\t\t\t...data,\n\t\t\t})\n\t\t\tif (result.success) {\n\t\t\t\tsend({ data: JSON.stringify(result.data) })\n\t\t\t} else {\n\t\t\t\tconsole.error('Error parsing auth rejected event', result.error, data)\n\t\t\t}\n\t\t}\n\t\tauthEmitter.on(EVENTS.USER_CODE_RECEIVED, handleCodeReceived)\n\t\tauthEmitter.on(EVENTS.AUTH_RESOLVED, handleAuthResolved)\n\t\tauthEmitter.on(EVENTS.AUTH_REJECTED, handleAuthRejected)\n\t\treturn () => {\n\t\t\tauthEmitter.off(EVENTS.USER_CODE_RECEIVED, handleCodeReceived)\n\t\t\tauthEmitter.off(EVENTS.AUTH_RESOLVED, handleAuthResolved)\n\t\t\tauthEmitter.off(EVENTS.AUTH_REJECTED, handleAuthRejected)\n\t\t}\n\t})\n}\n","import { getAuthInfo } from '@epic-web/workshop-utils/db.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { useEffect, useState } from 'react'\nimport {\n\tredirect,\n\tLink,\n\tuseFetcher,\n\tuseNavigate,\n\tuseRevalidator,\n} from 'react-router'\nimport { useEventSource } from 'remix-utils/sse/react'\nimport { Button, ButtonLink } from '#app/components/button.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { Logo } from '#app/components/product.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { EVENTS } from '#app/utils/auth-events.ts'\nimport { registerDevice } from '#app/utils/auth.server.ts'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { EventSchema } from '../login-sse.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst isAuthenticated = Boolean(await getAuthInfo())\n\tif (isAuthenticated) throw redirect('/account')\n\treturn {}\n}\n\nexport async function action() {\n\tensureUndeployed()\n\tvoid registerDevice()\n\treturn { status: 'pending' } as const\n}\n\nexport default function Login() {\n\tconst {\n\t\tproduct: { displayName },\n\t} = useWorkshopConfig()\n\tconst loginFetcher = useFetcher<typeof action>()\n\tconst [clickedVerificationLink, setClickedVerificationLink] = useState(false)\n\tconst [authError, setAuthError] = useState<null | string>(null)\n\tconst [userCodeInfo, setUserCodeInfo] = useState<null | {\n\t\tcode: string\n\t\turl: string\n\t}>(null)\n\tconst navigate = useNavigate()\n\tconst revalidator = useRevalidator()\n\tconst lastMessage = useEventSource(`/login-sse`)\n\tuseEffect(() => {\n\t\tif (!lastMessage) return\n\n\t\tconst parsed = JSON.parse(lastMessage)\n\t\tconst result = EventSchema.safeParse(parsed)\n\t\tif (!result.success) {\n\t\t\tconsole.error(result.error.flatten())\n\t\t\treturn\n\t\t}\n\t\tswitch (result.data.type) {\n\t\t\tcase EVENTS.USER_CODE_RECEIVED: {\n\t\t\t\tsetUserCodeInfo(result.data)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase EVENTS.AUTH_RESOLVED: {\n\t\t\t\tvoid revalidator.revalidate().then(() => navigate('/'))\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase EVENTS.AUTH_REJECTED: {\n\t\t\t\tsetAuthError(result.data.error)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}, [lastMessage, navigate, revalidator])\n\n\treturn (\n\t\t<main className=\"flex h-full w-full grow flex-col items-center justify-center p-10\">\n\t\t\t<div className=\"flex flex-col items-center\">\n\t\t\t\t<Logo className=\"h-16 w-16\" />\n\t\t\t\t<h1 className=\"pt-5 text-2xl font-semibold md:text-3xl\">\n\t\t\t\t\tLogin to {displayName}\n\t\t\t\t</h1>\n\t\t\t\t<div className=\"flex w-full flex-col items-center pt-5\">\n\t\t\t\t\t{userCodeInfo ? (\n\t\t\t\t\t\t<div className=\"flex w-full max-w-md flex-col items-center gap-3\">\n\t\t\t\t\t\t\t<div className=\"my-2 flex w-full flex-col items-center gap-2\">\n\t\t\t\t\t\t\t\t<p className=\"text-lg\">Your verification code is: </p>\n\t\t\t\t\t\t\t\t<div className=\"mb-3 w-full bg-gray-100 px-5 py-3 text-center text-lg font-bold dark:bg-black/40\">\n\t\t\t\t\t\t\t\t\t<code>{userCodeInfo.code}</code>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<p className=\"text-base\">\n\t\t\t\t\t\t\t\t\tYou'll use this to verify your device on {displayName}. Click\n\t\t\t\t\t\t\t\t\tverify code below to open the verification page.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<ButtonLink\n\t\t\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\t\t\tto={userCodeInfo.url}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tonClick={() => setClickedVerificationLink(true)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tVerify Auth Code\n\t\t\t\t\t\t\t</ButtonLink>\n\t\t\t\t\t\t\t{clickedVerificationLink ? (\n\t\t\t\t\t\t\t\t<div className=\"justify-center pt-5 text-center opacity-60\">\n\t\t\t\t\t\t\t\t\t<Loading className=\"justify-center\">\n\t\t\t\t\t\t\t\t\t\tWaiting for confirmation\n\t\t\t\t\t\t\t\t\t</Loading>\n\t\t\t\t\t\t\t\t\t<p className=\"pt-2\">\n\t\t\t\t\t\t\t\t\t\tPlease open{' '}\n\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\thref={userCodeInfo.url}\n\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tyour auth page\n\t\t\t\t\t\t\t\t\t\t</a>{' '}\n\t\t\t\t\t\t\t\t\t\tin a new tab to continue.\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"flex flex-col items-center gap-8\">\n\t\t\t\t\t\t\t<div className=\"flex max-w-lg flex-col gap-3 pt-3 text-base text-gray-700 dark:text-gray-300\">\n\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\tIf you have access to this workshop on {displayName}, you'll\n\t\t\t\t\t\t\t\t\tbe able to watch videos, track progress, run tests, view the\n\t\t\t\t\t\t\t\t\tdiffs, and more!\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\tFirst you need to authenticate your device by requesting an\n\t\t\t\t\t\t\t\t\taccess code and verifying on {displayName}.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<loginFetcher.Form method=\"POST\">\n\t\t\t\t\t\t\t\t<Button varient=\"primary\" type=\"submit\">\n\t\t\t\t\t\t\t\t\t{loginFetcher.state === 'idle' &&\n\t\t\t\t\t\t\t\t\tloginFetcher.data?.status !== 'pending'\n\t\t\t\t\t\t\t\t\t\t? `Retrieve Auth Code`\n\t\t\t\t\t\t\t\t\t\t: `Retrieving Auth Code...`}\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</loginFetcher.Form>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{authError ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<div className=\"mt-4 text-red-500\">\n\t\t\t\t\t\t\t\tThere was an error: <pre>{authError}</pre>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"mt-4 text-red-500\">\n\t\t\t\t\t\t\t\tPlease try again or{' '}\n\t\t\t\t\t\t\t\t<Link to=\"/support\" className=\"underline\">\n\t\t\t\t\t\t\t\t\tcontact support\n\t\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\t\tif the problem persists.\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n","import {\n\tgetPreferences,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { Form, useNavigation } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst preferences = await getPreferences()\n\treturn { preferences }\n}\n\nexport async function action({ request }: { request: Request }) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\n\tconst minResolution = formData.get('minResolution')\n\tconst maxResolution = formData.get('maxResolution')\n\tconst fontSize = formData.get('fontSize')\n\tconst optOutPresence = formData.get('optOutPresence') === 'on'\n\tconst persistPlayground = formData.get('persistPlayground') === 'on'\n\tconst dismissExerciseWarning = formData.get('dismissExerciseWarning') === 'on'\n\n\tawait setPreferences({\n\t\tplayer: {\n\t\t\tminResolution: minResolution ? Number(minResolution) : undefined,\n\t\t\tmaxResolution: maxResolution ? Number(maxResolution) : undefined,\n\t\t},\n\t\tfontSize: fontSize ? Number(fontSize) : undefined,\n\t\tpresence: { optOut: optOutPresence },\n\t\tplayground: { persist: persistPlayground },\n\t\texerciseWarning: { dismissed: dismissExerciseWarning },\n\t})\n\n\treturn redirectWithToast('/preferences', {\n\t\ttitle: 'Preferences updated',\n\t\tdescription: 'Your preferences have been updated.',\n\t\ttype: 'success',\n\t})\n}\n\nexport default function AccountSettings() {\n\tconst rootData = useRootLoaderData()\n\tconst playerPreferences = rootData.preferences?.player\n\tconst fontSizePreference = rootData.preferences?.fontSize\n\tconst presencePreferences = rootData.preferences?.presence\n\tconst playgroundPreferences = rootData.preferences?.playground\n\tconst exerciseWarningPreferences = rootData.preferences?.exerciseWarning\n\tconst navigation = useNavigation()\n\n\tconst isSubmitting = navigation.state === 'submitting'\n\n\treturn (\n\t\t<div className=\"h-full w-full overflow-y-auto\">\n\t\t\t<main className=\"container mt-12 flex w-full max-w-3xl grow flex-col gap-4 pb-24\">\n\t\t\t\t<h1 className=\"text-h1 mb-4\">Preferences</h1>\n\t\t\t\t<Form method=\"post\" className=\"flex w-full max-w-sm flex-col gap-4\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"text-body-xl mb-2\">Video Player Preferences</h2>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"minResolution\">Minimum Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"minResolution\"\n\t\t\t\t\t\t\t\tname=\"minResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={playerPreferences?.minResolution}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Auto</option>\n\t\t\t\t\t\t\t\t<option value=\"480\">480p</option>\n\t\t\t\t\t\t\t\t<option value=\"720\">720p</option>\n\t\t\t\t\t\t\t\t<option value=\"1080\">1080p</option>\n\t\t\t\t\t\t\t\t<option value=\"1440\">1440p</option>\n\t\t\t\t\t\t\t\t<option value=\"2160\">2160p (4K)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"maxResolution\">Maximum Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"maxResolution\"\n\t\t\t\t\t\t\t\tname=\"maxResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={playerPreferences?.maxResolution}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Auto</option>\n\t\t\t\t\t\t\t\t<option value=\"720\">720p</option>\n\t\t\t\t\t\t\t\t<option value=\"1080\">1080p</option>\n\t\t\t\t\t\t\t\t<option value=\"1440\">1440p</option>\n\t\t\t\t\t\t\t\t<option value=\"2160\">2160p (4K)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Font Size Preference</h2>\n\t\t\t\t\t\t\t<SimpleTooltip content=\"Defaults to 16px\">\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"fontSize\">Font Size</label>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\tid=\"fontSize\"\n\t\t\t\t\t\t\t\tname=\"fontSize\"\n\t\t\t\t\t\t\t\tdefaultValue={fontSizePreference ?? 16}\n\t\t\t\t\t\t\t\tstep=\"1\"\n\t\t\t\t\t\t\t\tmin=\"12\"\n\t\t\t\t\t\t\t\tmax=\"26\"\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Presence Preference</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip content=\"This controls whether your name and avatar are displayed in the pile of faces in navigation\">\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"optOutPresence\"\n\t\t\t\t\t\t\t\tname=\"optOutPresence\"\n\t\t\t\t\t\t\t\tdefaultChecked={presencePreferences?.optOut}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"optOutPresence\">\n\t\t\t\t\t\t\t\tOpt out of presence features\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Persist Playground</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\t\tcontent={`When enabled, clicking \"Set to Playground\" will save the current playground in the \"saved-playgrounds\" directory.`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"persistPlayground\"\n\t\t\t\t\t\t\t\tname=\"persistPlayground\"\n\t\t\t\t\t\t\t\tdefaultChecked={playgroundPreferences?.persist}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"persistPlayground\">\n\t\t\t\t\t\t\t\tEnable saving playground\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Exercise Directory Warning</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\t\tcontent={`When enabled, you'll see a warning banner when you have changes in the exercises directory. This helps remind you to work in the playground directory instead.`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"dismissExerciseWarning\"\n\t\t\t\t\t\t\t\tname=\"dismissExerciseWarning\"\n\t\t\t\t\t\t\t\tdefaultChecked={exerciseWarningPreferences?.dismissed}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"dismissExerciseWarning\">\n\t\t\t\t\t\t\t\tDismiss exercise directory warnings\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"h-4\" />\n\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\tvalue=\"update-preferences\"\n\t\t\t\t\t\tdisabled={isSubmitting}\n\t\t\t\t\t>\n\t\t\t\t\t\t{isSubmitting ? 'Updating...' : 'Update Preferences'}\n\t\t\t\t\t</Button>\n\t\t\t\t</Form>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n","import { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { Link } from 'react-router'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport default function Support() {\n\tconst repoGroups = ENV.EPICSHOP_GITHUB_REPO.match(\n\t\t/github\\.com\\/(?<org>[^/?]+)\\/(?<repo>[^/?]+)/,\n\t)?.groups\n\n\tlet repoUrl = ENV.EPICSHOP_GITHUB_REPO\n\tlet repoIssuesUrl = repoUrl\n\tif (repoGroups?.org && repoGroups.repo) {\n\t\trepoUrl = `https://github.com/${repoGroups.org}/${repoGroups.repo}`\n\t\trepoIssuesUrl = `${repoUrl}/issues`\n\t}\n\treturn (\n\t\t<div className=\"container flex h-full max-w-3xl flex-col items-center justify-center gap-4 p-12\">\n\t\t\t<h1 className=\"text-5xl font-bold\">Support</h1>\n\t\t\t<p>\n\t\t\t\tWe're here to support you! Depending on the kind of support you need,\n\t\t\t\tyou will want to reach out in different places:\n\t\t\t</p>\n\t\t\t<ul className=\"flex list-disc flex-col gap-4\">\n\t\t\t\t<li>\n\t\t\t\t\t<strong>Technical issues:</strong>{' '}\n\t\t\t\t\t<a href=\"mailto:team@epicweb.dev\" className=\"underline\">\n\t\t\t\t\t\tteam@epicweb.dev\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\t– Helpful if you're having trouble with or have feedback for your\n\t\t\t\t\tEpicWeb.dev account or access to course content.\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<strong>Workshop App:</strong>{' '}\n\t\t\t\t\t<a\n\t\t\t\t\t\thref=\"https://github.com/epicweb-dev/epicshop/issues\"\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\tgithub.com/epicweb-dev/epicshop\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\t– Helpful if you're having trouble with or feedback for the local\n\t\t\t\t\tworkshop app.\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<strong>Workshop content:</strong>{' '}\n\t\t\t\t\t<a href={repoIssuesUrl} className=\"underline\">\n\t\t\t\t\t\t{repoUrl.replace('https://', '')}\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\t– Open an issue or pull request here to report an issue with the\n\t\t\t\t\tcontent of this workshop.\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<strong>Discord:</strong>{' '}\n\t\t\t\t\t<Link to=\"/discord\" className=\"underline\">\n\t\t\t\t\t\t/discord\n\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t– Connect your account with discord to get access to the private forum\n\t\t\t\t\tand ask questions of other students and the workshop instructor.\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\t)\n}\n","import {\n\tgetPreferences,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { Form, useLoaderData, useNavigation } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst preferences = await getPreferences()\n\treturn { preferences }\n}\n\nexport async function action({ request }: { request: Request }) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst dismissed = formData.get('dismissWarning') === 'on'\n\n\tawait setPreferences({\n\t\texerciseWarning: { dismissed },\n\t})\n\n\treturn redirectWithToast('/workspace-structure', {\n\t\ttitle: 'Preferences updated',\n\t\tdescription:\n\t\t\t'Your workspace structure warning preference has been updated.',\n\t\ttype: 'success',\n\t})\n}\n\nexport default function WorkspaceStructure() {\n\tconst { preferences } = useLoaderData<typeof loader>()\n\tconst navigation = useNavigation()\n\tconst isSubmitting = navigation.state === 'submitting'\n\n\treturn (\n\t\t<div className=\"h-full w-full overflow-y-auto\">\n\t\t\t<main className=\"container mt-12 flex w-full max-w-4xl grow flex-col gap-6 pb-24\">\n\t\t\t\t<h1 className=\"text-h1\">Workshop Structure & Guidelines</h1>\n\n\t\t\t\t<div className=\"border-destructive bg-destructive/10 rounded-lg border p-4\">\n\t\t\t\t\t<h2 className=\"text-destructive mb-2 text-lg font-semibold\">\n\t\t\t\t\t\t⚠️ Important: Work in the Right Directory\n\t\t\t\t\t</h2>\n\t\t\t\t\t<p className=\"text-destructive text-sm\">\n\t\t\t\t\t\t<strong>\n\t\t\t\t\t\t\tAlways work in the `playground` directory, not the `exercises`\n\t\t\t\t\t\t\tdirectory.\n\t\t\t\t\t\t</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p className=\"text-destructive mt-2 text-sm\">\n\t\t\t\t\t\tTo <strong>make this warning go away</strong>, either:\n\t\t\t\t\t\t<ol className=\"list-decimal pl-4\">\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t{`Undo your changes in the exercises directory with: `}\n\t\t\t\t\t\t\t\t<code className=\"bg-background rounded px-1 py-0.5 text-xs\">\n\t\t\t\t\t\t\t\t\tgit checkout exercises/\n\t\t\t\t\t\t\t\t</code>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\tRead below and check the box once you understand how this is\n\t\t\t\t\t\t\t\tsupposed to work.\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ol>\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"space-y-6\">\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<h2 className=\"text-h2 mb-3\">Directory Structure</h2>\n\t\t\t\t\t\t<div className=\"space-y-4\">\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">📁 exercises/</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t<strong>Templates only.</strong> These are the original\n\t\t\t\t\t\t\t\t\texercise files that serve as the starting point for each step.\n\t\t\t\t\t\t\t\t\t<strong className=\"text-destructive\">\n\t\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t\tDo not edit these files\n\t\t\t\t\t\t\t\t\t</strong>{' '}\n\t\t\t\t\t\t\t\t\tunless you're contributing to the workshop or are the\n\t\t\t\t\t\t\t\t\tinstructor building the content.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">🏗️ playground/</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t<strong>Your workspace.</strong> This is where you practice\n\t\t\t\t\t\t\t\t\tand develop your skills.\n\t\t\t\t\t\t\t\t\t<strong className=\"text-primary\"> Always work here</strong> to\n\t\t\t\t\t\t\t\t\tcomplete exercises and experiment with the code.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</section>\n\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<h2 className=\"text-h2 mb-3\">Workshop UI Tabs</h2>\n\t\t\t\t\t\t<div className=\"space-y-4\">\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">\n\t\t\t\t\t\t\t\t\t🏗️ Playground Tab\n\t\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tShows the <strong>current state of your playground</strong> -\n\t\t\t\t\t\t\t\t\tthis is your work in progress.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">📋 Problem Tab</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tShows the <strong>current state of the problem</strong> -\n\t\t\t\t\t\t\t\t\tuseful for referencing where you started in this exercise\n\t\t\t\t\t\t\t\t\tstep.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">✅ Solution Tab</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tShows the <strong>current state of the solution</strong> -\n\t\t\t\t\t\t\t\t\tuseful for checking how things should work when you're\n\t\t\t\t\t\t\t\t\tfinished and comparing to your own solution.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</section>\n\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<h2 className=\"text-h2 mb-3\">Exceptions to the Rule</h2>\n\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\tThe only times you should modify files in the{' '}\n\t\t\t\t\t\t\t\t<code className=\"bg-background rounded px-1 py-0.5 text-xs\">\n\t\t\t\t\t\t\t\t\texercises/\n\t\t\t\t\t\t\t\t</code>{' '}\n\t\t\t\t\t\t\t\tdirectory are:\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t<ul className=\"text-muted-foreground mt-2 space-y-1 text-sm\">\n\t\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t\t• <strong>You're the instructor</strong> building or\n\t\t\t\t\t\t\t\t\tmaintaining the workshop content\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t\t• <strong>You're contributing</strong> to the workshop source\n\t\t\t\t\t\t\t\t\tcode (bug fixes, improvements, etc.)\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</section>\n\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<h2 className=\"text-h2 mb-3\">Need a Refresher?</h2>\n\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\tFor a complete overview of the typical workflow, review the\n\t\t\t\t\t\t\tintroductory material for this workshop.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</section>\n\n\t\t\t\t\t<hr />\n\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<div className=\"border-destructive bg-destructive/10 rounded-lg border p-4\">\n\t\t\t\t\t\t\t<h2 className=\"text-destructive mb-2 text-lg font-semibold\">\n\t\t\t\t\t\t\t\tMake this warning go away\n\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t<Form method=\"post\" className=\"space-y-4\">\n\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\t\t\tid=\"dismissWarning\"\n\t\t\t\t\t\t\t\t\t\tname=\"dismissWarning\"\n\t\t\t\t\t\t\t\t\t\tdefaultChecked={preferences?.exerciseWarning?.dismissed}\n\t\t\t\t\t\t\t\t\t\tclassName=\"border-border rounded\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<label htmlFor=\"dismissWarning\" className=\"text-sm\">\n\t\t\t\t\t\t\t\t\t\tI understand this and do not need further warnings about\n\t\t\t\t\t\t\t\t\t\tediting the exercises directory\n\t\t\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<Button type=\"submit\" varient=\"primary\" disabled={isSubmitting}>\n\t\t\t\t\t\t\t\t\t{isSubmitting ? 'Saving...' : 'Save Preference'}\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</section>\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n","import { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { Link, Outlet } from 'react-router'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { type Route } from './+types/_layout.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\treturn [{ title: `👷 | ${rootData?.workshopTitle}` }]\n}\n\nexport default function AdminLayout() {\n\treturn (\n\t\t<main className=\"container mx-auto mt-8\">\n\t\t\t<h1 className=\"text-4xl font-bold\">Admin</h1>\n\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t<nav>\n\t\t\t\t\t<ul className=\"flex gap-3\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/\">\n\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/admin\">\n\t\t\t\t\t\t\t\tAdmin\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/diff\">\n\t\t\t\t\t\t\t\tDiff Viewer\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"db\">\n\t\t\t\t\t\t\t\tDatabase\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"cache\">\n\t\t\t\t\t\t\t\tCache Management\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"version\">\n\t\t\t\t\t\t\t\tVersion\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</nav>\n\t\t\t\t<Outlet />\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n","import { getApps } from '@epic-web/workshop-utils/apps.server'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst apps = await getApps()\n\treturn Response.json({ apps })\n}\n","import {\n\tdeleteCacheEntry,\n\tdeleteWorkshopCache,\n\tgetAllWorkshopCaches,\n\tgetGlobalCaches,\n\tglobalCacheDirectoryExists,\n\tupdateCacheEntry,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getEnv } from '@epic-web/workshop-utils/env.server'\nimport { getErrorMessage } from '@epic-web/workshop-utils/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { href, useFetcher, useSearchParams } from 'react-router'\nimport { ClientOnly } from 'remix-utils/client-only'\nimport { z } from 'zod'\nimport {\n\tButton,\n\tIconButton,\n\ticonButtonClassName,\n} from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport {\n\tcalculateExpirationTime,\n\tcn,\n\tensureUndeployed,\n\tformatDuration,\n\tformatFileSize,\n\tformatTimeRemaining,\n\tuseDayjs,\n\tuseDoubleCheck,\n\tuseInterval,\n} from '#app/utils/misc.tsx'\nimport { type Route } from './+types/cache.ts'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tensureUndeployed()\n\tconst currentWorkshopId = getEnv().EPICSHOP_WORKSHOP_INSTANCE_ID\n\tconst allWorkshopCaches = await getAllWorkshopCaches()\n\tconst globalCaches = await getGlobalCaches()\n\tconst allCaches = [...allWorkshopCaches, ...globalCaches]\n\n\tconst url = new URL(request.url)\n\tconst filterQuery = url.searchParams.get('q') || ''\n\n\t// Ensure 'global' is always in available workshops if global cache directory exists\n\tconst availableWorkshopIds = new Set(allCaches.map((w) => w.workshopId))\n\tconst globalDirExists = await globalCacheDirectoryExists()\n\tif (globalDirExists) {\n\t\tavailableWorkshopIds.add('global')\n\t}\n\n\tconst selectedWorkshops = url.searchParams\n\t\t.get('workshops')\n\t\t?.split(',')\n\t\t.filter(Boolean) || [\n\t\tcurrentWorkshopId,\n\t\t...(globalDirExists ? ['global'] : []),\n\t]\n\n\t// Filter caches based on search query and selected workshops\n\tconst filteredCaches = allCaches\n\t\t.filter(\n\t\t\t(workshopCache) =>\n\t\t\t\tselectedWorkshops.includes(workshopCache.workshopId) ||\n\t\t\t\tselectedWorkshops.length === 0,\n\t\t)\n\t\t.map((workshopCache) => ({\n\t\t\t...workshopCache,\n\t\t\tcaches: workshopCache.caches\n\t\t\t\t.map((cache) => ({\n\t\t\t\t\t...cache,\n\t\t\t\t\tentries: cache.entries.filter(\n\t\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t\tfilterQuery === '' ||\n\t\t\t\t\t\t\tentry.key.toLowerCase().includes(filterQuery.toLowerCase()) ||\n\t\t\t\t\t\t\tcache.name.toLowerCase().includes(filterQuery.toLowerCase()),\n\t\t\t\t\t),\n\t\t\t\t}))\n\t\t\t\t.filter((cache) => cache.entries.length > 0 || filterQuery === ''),\n\t\t}))\n\t\t.filter(\n\t\t\t(workshopCache) => workshopCache.caches.length > 0 || filterQuery === '',\n\t\t)\n\n\treturn {\n\t\tcurrentWorkshopId,\n\t\tallWorkshopCaches: allCaches,\n\t\tfilteredCaches,\n\t\tfilterQuery,\n\t\tselectedWorkshops,\n\t\tavailableWorkshops: Array.from(availableWorkshopIds),\n\t}\n}\n\nconst ActionSchema = z.discriminatedUnion('intent', [\n\tz.object({\n\t\tintent: z.literal('delete-entry'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t\tfilename: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('delete-cache'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('delete-workshop-cache'),\n\t\tworkshopId: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('update-entry'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t\tfilename: z.string(),\n\t\tnewValue: z.string(),\n\t}),\n])\n\nexport async function action({ request }: Route.ActionArgs) {\n\tensureUndeployed()\n\n\tconst formData = await request.formData()\n\tconst rawData = Object.fromEntries(formData.entries())\n\tconst result = ActionSchema.safeParse(rawData)\n\n\tif (!result.success) {\n\t\treturn { status: 'error', error: 'Invalid request' } as const\n\t}\n\n\tconst data = result.data\n\n\ttry {\n\t\tswitch (data.intent) {\n\t\t\tcase 'delete-entry': {\n\t\t\t\tconst path = `${data.workshopId}/${data.cacheName}/${data.filename}`\n\t\t\t\tawait deleteCacheEntry(path)\n\t\t\t\treturn { status: 'success', message: 'Cache entry deleted' } as const\n\t\t\t}\n\t\t\tcase 'delete-cache': {\n\t\t\t\tawait deleteWorkshopCache(data.workshopId, data.cacheName)\n\t\t\t\treturn { status: 'success', message: 'Cache deleted' } as const\n\t\t\t}\n\t\t\tcase 'delete-workshop-cache': {\n\t\t\t\tawait deleteWorkshopCache(data.workshopId)\n\t\t\t\treturn { status: 'success', message: 'Workshop cache deleted' } as const\n\t\t\t}\n\t\t\tcase 'update-entry': {\n\t\t\t\tconst path = `${data.workshopId}/${data.cacheName}/${data.filename}`\n\t\t\t\ttry {\n\t\t\t\t\tconst parsedValue = JSON.parse(data.newValue)\n\t\t\t\t\tawait updateCacheEntry(path, parsedValue)\n\t\t\t\t\treturn { status: 'success', message: 'Cache entry updated' } as const\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\terror: getErrorMessage(error, 'Invalid JSON value'),\n\t\t\t\t\t} as const\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconsole.error('Cache action error:', error)\n\t\treturn { status: 'error', error: 'Operation failed' } as const\n\t}\n}\n\nfunction WorkshopChooser({\n\tselectedWorkshops,\n\tavailableWorkshops,\n\tcurrentWorkshopId,\n}: {\n\tselectedWorkshops: string[]\n\tavailableWorkshops: string[]\n\tcurrentWorkshopId: string\n}) {\n\tconst [searchParams, setSearchParams] = useSearchParams()\n\n\tconst handleWorkshopChange = (workshop: string, checked: boolean) => {\n\t\tconst newSelected = checked\n\t\t\t? [...selectedWorkshops, workshop]\n\t\t\t: selectedWorkshops.filter((w) => w !== workshop)\n\n\t\tconst params = new URLSearchParams(searchParams)\n\t\tif (newSelected.length > 0) {\n\t\t\tparams.set('workshops', newSelected.join(','))\n\t\t} else {\n\t\t\tparams.delete('workshops')\n\t\t}\n\t\tsetSearchParams(params)\n\t}\n\n\treturn (\n\t\t<div className=\"mb-6\">\n\t\t\t<h3 className=\"mb-3 text-lg font-semibold\">Workshop Filter</h3>\n\t\t\t<div className=\"flex flex-wrap gap-3\">\n\t\t\t\t{availableWorkshops.map((workshop) => (\n\t\t\t\t\t<label key={workshop} className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tchecked={selectedWorkshops.includes(workshop)}\n\t\t\t\t\t\t\tonChange={(e) => handleWorkshopChange(workshop, e.target.checked)}\n\t\t\t\t\t\t\tclassName=\"rounded\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclassName={`text-sm ${workshop === currentWorkshopId ? 'text-primary font-bold' : ''}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{workshop} {workshop === currentWorkshopId ? '(current)' : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction SearchFilter({ filterQuery }: { filterQuery: string }) {\n\tconst [searchParams, setSearchParams] = useSearchParams()\n\tconst [inputValue, setInputValue] = useState(filterQuery)\n\tconst inputRef = useRef<HTMLInputElement>(null)\n\n\t// Update input value when filterQuery changes (e.g., from URL)\n\tuseEffect(() => {\n\t\tsetInputValue(filterQuery)\n\t}, [filterQuery])\n\n\tconst handleSearch = (query: string) => {\n\t\tconst params = new URLSearchParams(searchParams)\n\t\tif (query) {\n\t\t\tparams.set('q', query)\n\t\t} else {\n\t\t\tparams.delete('q')\n\t\t}\n\t\tsetSearchParams(params)\n\t}\n\n\tconst handleClear = () => {\n\t\tsetInputValue('')\n\t\thandleSearch('')\n\t\tinputRef.current?.focus()\n\t}\n\n\treturn (\n\t\t<div className=\"mb-6\">\n\t\t\t<h3 className=\"mb-3 text-lg font-semibold\">Search Cache Entries</h3>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t<input\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tplaceholder=\"Search by key or cache name...\"\n\t\t\t\t\tvalue={inputValue}\n\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\tsetInputValue(e.target.value)\n\t\t\t\t\t\thandleSearch(e.target.value)\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"border-border bg-background text-foreground focus:ring-ring flex-1 rounded-md border px-3 py-2 focus:ring-2 focus:outline-none\"\n\t\t\t\t/>\n\t\t\t\t{inputValue ? (\n\t\t\t\t\t<IconButton onClick={handleClear} title=\"Clear search\">\n\t\t\t\t\t\t<Icon name=\"Close\" className=\"h-4 w-4\" />\n\t\t\t\t\t</IconButton>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Inline entry editor component\nfunction InlineEntryEditor({\n\tworkshopId,\n\tcacheName,\n\tfilename,\n\tcurrentValue,\n\tentryKey,\n}: {\n\tworkshopId: string\n\tcacheName: string\n\tfilename: string\n\tcurrentValue: any\n\tentryKey: string\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst [editValue, setEditValue] = useState(\n\t\tJSON.stringify(currentValue, null, 2),\n\t)\n\tconst [hasChanges, setHasChanges] = useState(false)\n\n\tconst handleSave = () => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'update-entry',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t\tfilename,\n\t\t\t\tnewValue: editValue,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t\tsetHasChanges(false)\n\t}\n\n\tconst handleChange = (value: string) => {\n\t\tsetEditValue(value)\n\t\tsetHasChanges(value !== JSON.stringify(currentValue, null, 2))\n\t}\n\n\tconst handleReset = () => {\n\t\tsetEditValue(JSON.stringify(currentValue, null, 2))\n\t\tsetHasChanges(false)\n\t}\n\n\treturn (\n\t\t<details className=\"mt-2\">\n\t\t\t<summary className=\"text-muted-foreground hover:text-foreground cursor-pointer text-sm\">\n\t\t\t\tEdit entry details\n\t\t\t</summary>\n\t\t\t<div className=\"border-border bg-muted mt-2 space-y-3 rounded border p-3\">\n\t\t\t\t<div>\n\t\t\t\t\t<label className=\"mb-1 block text-sm font-medium\">Key:</label>\n\t\t\t\t\t<code className=\"bg-background rounded border px-2 py-1 text-sm\">\n\t\t\t\t\t\t{entryKey}\n\t\t\t\t\t</code>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<label className=\"mb-1 block text-sm font-medium\">Value:</label>\n\t\t\t\t\t<textarea\n\t\t\t\t\t\tvalue={editValue}\n\t\t\t\t\t\tonChange={(e) => handleChange(e.target.value)}\n\t\t\t\t\t\tclassName=\"resize-vertical border-border bg-background text-foreground focus:ring-ring h-32 w-full rounded border p-2 font-mono text-sm focus:ring-2 focus:outline-none\"\n\t\t\t\t\t\tplaceholder=\"Enter JSON value...\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\tonClick={handleSave}\n\t\t\t\t\t\tdisabled={!hasChanges || fetcher.state !== 'idle'}\n\t\t\t\t\t>\n\t\t\t\t\t\t{fetcher.state !== 'idle' ? 'Saving...' : 'Save'}\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button varient=\"mono\" onClick={handleReset} disabled={!hasChanges}>\n\t\t\t\t\t\tReset\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</details>\n\t)\n}\n\nfunction SkippedFilesSection({\n\tskippedFiles,\n\tworkshopId,\n\tcacheName,\n}: {\n\tskippedFiles: Array<{\n\t\tfilename: string\n\t\terror: string\n\t\tsize: number\n\t\tskipped: true\n\t}>\n\tworkshopId: string\n\tcacheName: string\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\n\tif (skippedFiles.length === 0) return null\n\n\treturn (\n\t\t<div className=\"border-warning bg-warning mt-4 rounded border p-3\">\n\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t<Icon\n\t\t\t\t\tname=\"TriangleAlert\"\n\t\t\t\t\tclassName=\"text-warning-foreground h-4 w-4\"\n\t\t\t\t/>\n\t\t\t\t<h5 className=\"text-warning-foreground font-medium\">\n\t\t\t\t\tSkipped Files ({skippedFiles.length})\n\t\t\t\t</h5>\n\t\t\t</div>\n\t\t\t<p className=\"text-warning-foreground/80 mb-3 text-sm\">\n\t\t\t\tThese cache files were skipped because they exceed the 3MB size limit:\n\t\t\t</p>\n\t\t\t<div className=\"space-y-2\">\n\t\t\t\t{skippedFiles.map((skippedFile) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={skippedFile.filename}\n\t\t\t\t\t\tclassName=\"border-warning/20 bg-warning/5 flex items-center justify-between rounded border p-2\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t<div className=\"text-warning-foreground truncate font-mono text-sm font-medium\">\n\t\t\t\t\t\t\t\t{skippedFile.filename}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"text-warning-foreground/70 text-xs\">\n\t\t\t\t\t\t\t\t{skippedFile.error} • Size:{' '}\n\t\t\t\t\t\t\t\t<span title={`${skippedFile.size} bytes`}>\n\t\t\t\t\t\t\t\t\t{formatFileSize(skippedFile.size)}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"ml-2 flex shrink-0\">\n\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\tonConfirm={() => {\n\t\t\t\t\t\t\t\t\tvoid fetcher.submit(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tintent: 'delete-entry',\n\t\t\t\t\t\t\t\t\t\t\tworkshopId,\n\t\t\t\t\t\t\t\t\t\t\tcacheName,\n\t\t\t\t\t\t\t\t\t\t\tfilename: skippedFile.filename,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{ method: 'POST' },\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\ttitle=\"Delete large cache file\"\n\t\t\t\t\t\t\t\tclassName=\"text-destructive-foreground hover:bg-destructive/20 hover:text-destructive-foreground\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nexport default function CacheManagement({ loaderData }: Route.ComponentProps) {\n\tconst fetcher = useFetcher<typeof action>()\n\n\tconst deleteEntry = (\n\t\tworkshopId: string,\n\t\tcacheName: string,\n\t\tfilename: string,\n\t) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-entry',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t\tfilename,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst deleteCache = (workshopId: string, cacheName: string) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-cache',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst deleteWorkshopCache = (workshopId: string) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-workshop-cache',\n\t\t\t\tworkshopId,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst {\n\t\tcurrentWorkshopId,\n\t\tfilteredCaches,\n\t\tfilterQuery,\n\t\tselectedWorkshops,\n\t\tavailableWorkshops,\n\t} = loaderData\n\n\treturn (\n\t\t<div className=\"space-y-6\">\n\t\t\t<div>\n\t\t\t\t<h2 className=\"mb-2 text-2xl font-bold\">Cache Management</h2>\n\t\t\t\t<p className=\"text-muted-foreground\">\n\t\t\t\t\tCurrent Workshop:{' '}\n\t\t\t\t\t<span className=\"text-foreground font-semibold\">\n\t\t\t\t\t\t{currentWorkshopId}\n\t\t\t\t\t</span>\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<WorkshopChooser\n\t\t\t\tselectedWorkshops={selectedWorkshops}\n\t\t\t\tavailableWorkshops={availableWorkshops}\n\t\t\t\tcurrentWorkshopId={currentWorkshopId}\n\t\t\t/>\n\n\t\t\t<SearchFilter filterQuery={filterQuery} />\n\n\t\t\t{fetcher.data?.status === 'success' ? (\n\t\t\t\t<div className=\"border-border bg-success text-success-foreground rounded border p-4\">\n\t\t\t\t\t{fetcher.data.message}\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{fetcher.data?.status === 'error' ? (\n\t\t\t\t<div className=\"border-border bg-destructive text-destructive-foreground rounded border p-4\">\n\t\t\t\t\t{fetcher.data.error}\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{filteredCaches.length === 0 ? (\n\t\t\t\t<div className=\"text-muted-foreground py-8 text-center\">\n\t\t\t\t\tNo caches found matching your criteria.\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t<div className=\"space-y-6\">\n\t\t\t\t{filteredCaches.map((workshopCache) => (\n\t\t\t\t\t<details\n\t\t\t\t\t\tkey={workshopCache.workshopId}\n\t\t\t\t\t\topen={workshopCache.workshopId === currentWorkshopId}\n\t\t\t\t\t>\n\t\t\t\t\t\t<summary className=\"border-border bg-card hover:bg-accent cursor-pointer rounded-lg border p-4\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t\t<h3 className=\"text-card-foreground flex items-center gap-2 text-lg font-semibold\">\n\t\t\t\t\t\t\t\t\t<Icon name=\"Files\" className=\"h-5 w-5\" />\n\t\t\t\t\t\t\t\t\t{workshopCache.workshopId === 'global'\n\t\t\t\t\t\t\t\t\t\t? 'Global Caches'\n\t\t\t\t\t\t\t\t\t\t: workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t{workshopCache.workshopId === currentWorkshopId ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"bg-primary text-primary-foreground rounded px-2 py-1 text-xs\">\n\t\t\t\t\t\t\t\t\t\t\tCurrent\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\tdeleteWorkshopCache(workshopCache.workshopId)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\ttitle=\"Delete all workshop caches\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</summary>\n\n\t\t\t\t\t\t<div className=\"mt-4 space-y-4 pl-4\">\n\t\t\t\t\t\t\t{workshopCache.caches.map((cache) => {\n\t\t\t\t\t\t\t\tconst totalSize = cache.entries.reduce(\n\t\t\t\t\t\t\t\t\t(sum, entry) => sum + (entry.size || 0),\n\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst skippedSize = (cache.skippedFiles || []).reduce(\n\t\t\t\t\t\t\t\t\t(sum, file) => sum + file.size,\n\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst grandTotal = totalSize + skippedSize\n\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<details key={cache.name} className=\"bg-muted rounded-md\">\n\t\t\t\t\t\t\t\t\t\t<summary className=\"hover:bg-accent cursor-pointer p-3\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t\t\t\t\t\t<h4 className=\"text-muted-foreground flex items-center gap-2 font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Files\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t{cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t({cache.entries.length} entr\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{cache.entries.length === 1 ? 'y' : 'ies'})\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{grandTotal > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t•{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span title={`${grandTotal} bytes`}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(grandTotal)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttotal\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{skippedSize > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-warning\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span title={`${skippedSize} bytes`}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(skippedSize)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tskipped)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t</h4>\n\t\t\t\t\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdeleteCache(workshopCache.workshopId, cache.name)\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Delete cache\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</summary>\n\n\t\t\t\t\t\t\t\t\t\t<div className=\"p-3 pt-0\">\n\t\t\t\t\t\t\t\t\t\t\t{cache.entries.length === 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\tNo entries match your search.\n\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t\t\t\t{cache.skippedFiles && cache.skippedFiles.length > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<SkippedFilesSection\n\t\t\t\t\t\t\t\t\t\t\t\t\tskippedFiles={cache.skippedFiles}\n\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopId={workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t\t\t\t\tcacheName={cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t\t\t\t\t\t{cache.entries.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\t({ key, entry, filename, size, filepath }) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-background rounded border p-3\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-start justify-between\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mb-1 flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"truncate font-mono text-sm font-medium\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{size ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"bg-muted text-muted-foreground inline-flex items-center rounded px-1.5 py-0.5 text-xs whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle={`${size} bytes`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(size)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<CacheMetadata metadata={entry.metadata} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"ml-4 flex shrink-0 gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thref={href('/admin/cache/*', {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'*': `${workshopCache.workshopId}/${cache.name}/${filename}`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground hover:bg-muted focus:ring-ring inline-flex h-8 w-8 items-center justify-center rounded border focus:ring-2 focus:outline-none\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"View JSON\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"ExternalLink\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{filepath ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfile={filepath}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={iconButtonClassName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"Files\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Open in editor\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdeleteEntry(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopCache.workshopId,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcache.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfilename,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Delete entry\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<InlineEntryEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopId={workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcacheName={cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfilename={filename}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcurrentValue={entry.value}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tentryKey={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</details>\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</details>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Component for displaying cache metadata with live countdown\nfunction CacheMetadata({\n\tmetadata,\n}: {\n\tmetadata: {\n\t\tcreatedTime: number\n\t\tttl?: number | null\n\t\tswr?: number\n\t}\n}) {\n\tconst dayjs = useDayjs()\n\tconst [, setCurrentTime] = useState(Date.now())\n\tconst expirationTime = calculateExpirationTime(metadata)\n\n\t// Update time every second for live countdown\n\tuseInterval(() => {\n\t\tsetCurrentTime(Date.now())\n\t}, 1000)\n\n\tconst createdDate = dayjs(metadata.createdTime)\n\tconst timeRemaining = expirationTime\n\t\t? formatTimeRemaining(expirationTime)\n\t\t: { text: 'Never', isExpired: false, isExpiringSoon: false }\n\n\treturn (\n\t\t<div className=\"text-muted-foreground flex flex-col gap-1 text-xs\">\n\t\t\t<div>\n\t\t\t\tCreated: {createdDate.format('MMM D, YYYY HH:mm:ss')}{' '}\n\t\t\t\t<ClientOnly>{() => `(${createdDate.fromNow()})`}</ClientOnly>\n\t\t\t</div>\n\t\t\t<div className=\"flex flex-wrap items-center gap-3\">\n\t\t\t\t{metadata.ttl !== undefined && metadata.ttl !== null ? (\n\t\t\t\t\t<span>\n\t\t\t\t\t\tTTL:{' '}\n\t\t\t\t\t\t{metadata.ttl === Infinity ? (\n\t\t\t\t\t\t\t'Forever'\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<span title={`${metadata.ttl}ms`}>\n\t\t\t\t\t\t\t\t{formatDuration(metadata.ttl)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t{metadata.swr !== undefined ? (\n\t\t\t\t\t<span>\n\t\t\t\t\t\tSWR:{' '}\n\t\t\t\t\t\t<span title={`${metadata.swr}ms`}>\n\t\t\t\t\t\t\t{formatDuration(metadata.swr)}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t<div\n\t\t\t\t\tclassName={`inline-flex w-auto rounded-full px-2 py-[2px] font-medium ${\n\t\t\t\t\t\ttimeRemaining.isExpired\n\t\t\t\t\t\t\t? 'bg-destructive text-destructive-foreground'\n\t\t\t\t\t\t\t: timeRemaining.isExpiringSoon\n\t\t\t\t\t\t\t\t? 'bg-warning text-warning-foreground'\n\t\t\t\t\t\t\t\t: 'text-foreground'\n\t\t\t\t\t}`}\n\t\t\t\t>\n\t\t\t\t\t{expirationTime ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\tExpires: {dayjs(expirationTime).format('MMM D, YYYY HH:mm:ss')} (\n\t\t\t\t\t\t\t<span className=\"tabular-nums\">\n\t\t\t\t\t\t\t\t<ClientOnly>{() => timeRemaining.text}</ClientOnly>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'Expires: Never'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Double-check delete button\nfunction DoubleCheckButton({\n\tonConfirm,\n\tchildren,\n\tclassName,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'> & {\n\tonConfirm: () => void\n}) {\n\tconst doubleCheck = useDoubleCheck()\n\n\treturn (\n\t\t<IconButton\n\t\t\t{...doubleCheck.getButtonProps({\n\t\t\t\tonClick: doubleCheck.doubleCheck ? onConfirm : undefined,\n\t\t\t\t...props,\n\t\t\t})}\n\t\t\tclassName={cn(\n\t\t\t\tdoubleCheck.doubleCheck\n\t\t\t\t\t? 'bg-destructive text-destructive-foreground'\n\t\t\t\t\t: null,\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{doubleCheck.doubleCheck ? '✓' : children}\n\t\t</IconButton>\n\t)\n}\n","import { invariant } from '@epic-web/invariant'\nimport { readEntryByPath } from '@epic-web/workshop-utils/cache.server'\nimport { type Route } from './+types/cache.$.ts'\n\nexport async function loader({ params }: Route.LoaderArgs) {\n\tconst path = params['*']\n\tinvariant(path, 'Path is required')\n\tconst entry = await readEntryByPath(path)\n\treturn { path, entry }\n}\n","import { loadJSON } from '@epic-web/workshop-utils/data-storage.server'\nimport { readDb } from '@epic-web/workshop-utils/db.server'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { LaunchEditor } from '../launch-editor.tsx'\nimport { type Route } from './+types/db.ts'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst db = await readDb()\n\tconst { path: filepath } = await loadJSON()\n\n\treturn { db, filepath }\n}\n\nexport default function DbRoute({ loaderData }: Route.ComponentProps) {\n\tconst { db, filepath } = loaderData\n\treturn (\n\t\t<main>\n\t\t\t<h1 className=\"text-2xl font-bold\">Database</h1>\n\t\t\t<div className=\"prose mt-4\">\n\t\t\t\t<callout-danger>\n\t\t\t\t\t<strong>Warning:</strong> Editing the database directly can corrupt\n\t\t\t\t\tyour data. Be very careful!\n\t\t\t\t</callout-danger>\n\t\t\t</div>\n\t\t\t<LaunchEditor\n\t\t\t\tfile={filepath}\n\t\t\t\tclassName=\"flex max-w-full items-center gap-2\"\n\t\t\t>\n\t\t\t\t<SimpleTooltip content=\"Open the database file in your editor\">\n\t\t\t\t\t<Icon name=\"Files\" className=\"h-4 w-4\" title=\"Open in editor\" />\n\t\t\t\t</SimpleTooltip>\n\t\t\t\t<span className=\"truncate\" title={filepath}>\n\t\t\t\t\t{filepath}\n\t\t\t\t</span>\n\t\t\t</LaunchEditor>\n\t\t\t<pre className=\"mt-4 max-h-[400px] w-full overflow-auto rounded border bg-gray-900 p-4 text-sm text-white\">\n\t\t\t\t{JSON.stringify(db, null, 2)}\n\t\t\t</pre>\n\t\t</main>\n\t)\n}\n","import inspector from 'node:inspector'\nimport path from 'node:path'\nimport { getWorkshopRoot } from '@epic-web/workshop-utils/apps.server'\nimport { deleteCache } from '@epic-web/workshop-utils/cache.server'\nimport { deleteDb } from '@epic-web/workshop-utils/db.server'\nimport fsExtra from 'fs-extra'\n\nexport function isInspectorRunning(): boolean {\n\ttry {\n\t\treturn inspector.url() !== undefined\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport async function clearData() {\n\tif (ENV.EPICSHOP_DEPLOYED) return\n\tawait clearCaches()\n\tawait deleteDb()\n}\n\nexport async function clearCaches() {\n\tif (ENV.EPICSHOP_DEPLOYED) return\n\tawait fsExtra.remove(path.join(getWorkshopRoot(), 'node_modules', '.cache'))\n\tawait deleteCache()\n}\n\nexport async function startInspector() {\n\tif (ENV.EPICSHOP_DEPLOYED) return\n\tif (!isInspectorRunning()) {\n\t\tinspector.open()\n\t} else {\n\t\tconsole.info(`Inspector already running.`)\n\t}\n}\n\nexport async function stopInspector() {\n\tif (ENV.EPICSHOP_DEPLOYED) return\n\tif (isInspectorRunning()) {\n\t\tinspector.close()\n\t} else {\n\t\tconsole.info(`Inspector already stopped.`)\n\t}\n}\n","import { getApps } from '@epic-web/workshop-utils/apps.server'\nimport { getProcesses } from '@epic-web/workshop-utils/process-manager.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { clsx } from 'clsx'\nimport { data, Form, Link, useNavigation } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport {\n\tuseEpicProgress,\n\ttype SerializedProgress,\n} from '#app/routes/progress.tsx'\nimport { cn, ensureUndeployed, useDoubleCheck } from '#app/utils/misc.tsx'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { type Route } from './+types/index.tsx'\nimport {\n\tclearCaches,\n\tclearData,\n\tisInspectorRunning,\n\tstartInspector,\n\tstopInspector,\n} from './admin-utils.server.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\treturn [{ title: `👷 | ${rootData?.workshopTitle}` }]\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('adminLoader')\n\tconst apps = (await getApps({ request, timings })).filter(\n\t\t(a, i, ar) => ar.findIndex((b) => a.name === b.name) === i,\n\t)\n\tconst processes: Record<\n\t\tstring,\n\t\t{ port: number; pid?: number; color: string }\n\t> = {}\n\tconst testProcesses: Record<\n\t\tstring,\n\t\t{ pid?: number; exitCode?: number | null }\n\t> = {}\n\tfor (const [\n\t\tname,\n\t\t{ port, process, color },\n\t] of getProcesses().devProcesses.entries()) {\n\t\tprocesses[name] = { port, pid: process.pid, color }\n\t}\n\n\tfor (const [\n\t\tname,\n\t\t{ process, exitCode },\n\t] of getProcesses().testProcesses.entries()) {\n\t\ttestProcesses[name] = { pid: process?.pid, exitCode }\n\t}\n\treturn data(\n\t\t{\n\t\t\tapps,\n\t\t\tprocesses,\n\t\t\ttestProcesses,\n\t\t\tinspectorRunning: isInspectorRunning(),\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport async function action({ request }: Route.ActionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tswitch (intent) {\n\t\tcase 'clear-data': {\n\t\t\tawait clearData()\n\t\t\treturn { success: true }\n\t\t}\n\t\tcase 'clear-caches': {\n\t\t\tawait clearCaches()\n\t\t\treturn { success: true }\n\t\t}\n\t\tcase 'inspect': {\n\t\t\tawait startInspector()\n\t\t\treturn { success: true }\n\t\t}\n\t\tcase 'stop-inspect': {\n\t\t\tawait stopInspector()\n\t\t\treturn { success: true }\n\t\t}\n\t\tdefault: {\n\t\t\tthrow new Error(`Unknown intent: ${intent}`)\n\t\t}\n\t}\n}\n\nfunction sortProgress(a: SerializedProgress, b: SerializedProgress) {\n\treturn a.type === 'unknown' && b.type === 'unknown'\n\t\t? 0\n\t\t: a.type === 'unknown'\n\t\t\t? -1\n\t\t\t: b.type === 'unknown'\n\t\t\t\t? 1\n\t\t\t\t: 0\n}\n\nfunction linkProgress(progress: SerializedProgress) {\n\tswitch (progress.type) {\n\t\tcase 'workshop-instructions':\n\t\t\treturn '/'\n\t\tcase 'workshop-finished':\n\t\t\treturn '/finished'\n\t\tcase 'instructions':\n\t\t\treturn `/${progress.exerciseNumber.toString().padStart(2, '0')}`\n\t\tcase 'step':\n\t\t\treturn `/${progress.exerciseNumber\n\t\t\t\t.toString()\n\t\t\t\t.padStart(2, '0')}/${progress.stepNumber.toString().padStart(2, '0')}`\n\t\tcase 'finished':\n\t\t\treturn `/${progress.exerciseNumber.toString().padStart(2, '0')}/finished`\n\t\tdefault:\n\t\t\treturn ''\n\t}\n}\n\nexport default function AdminLayout({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tconst navigation = useNavigation()\n\tconst epicProgress = useEpicProgress()\n\n\tconst isStartingInspector = navigation.formData?.get('intent') === 'inspect'\n\tconst isStoppingInspector =\n\t\tnavigation.formData?.get('intent') === 'stop-inspect'\n\n\tconst progressStatus = {\n\t\tcompleted: 'bg-green-500',\n\t\tincomplete: 'bg-yellow-500',\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-6 p-6\">\n\t\t\t<div className=\"mb-2\">\n\t\t\t\t<h1 className=\"text-foreground text-2xl font-bold\">Admin Panel</h1>\n\t\t\t\t<p className=\"text-muted-foreground mt-1 text-sm\">\n\t\t\t\t\tManage workshop settings and monitor processes\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<div className=\"grid gap-6 md:grid-cols-2\">\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Progress</CardTitle>\n\t\t\t\t\t\t<CardDescription>EpicWeb.dev lesson progress</CardDescription>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t{epicProgress ? (\n\t\t\t\t\t\t\t<ul className=\"scrollbar-thin scrollbar-thumb-scrollbar flex max-h-72 flex-col gap-2 overflow-y-auto\">\n\t\t\t\t\t\t\t\t{epicProgress.sort(sortProgress).map((progress) => {\n\t\t\t\t\t\t\t\t\tconst status = progress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t\t? 'completed'\n\t\t\t\t\t\t\t\t\t\t: 'incomplete'\n\t\t\t\t\t\t\t\t\tconst label = [\n\t\t\t\t\t\t\t\t\t\tprogress.epicLessonSlug,\n\t\t\t\t\t\t\t\t\t\tprogress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t\t\t? `(${progress.epicCompletedAt})`\n\t\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\tkey={progress.epicLessonSlug}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"hover:bg-muted/50 flex items-center gap-3 rounded-md p-2\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'h-3 w-3 shrink-0 rounded-full',\n\t\t\t\t\t\t\t\t\t\t\t\t\tprogressStatus[status],\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\ttitle={status}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t{progress.type === 'unknown' ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex flex-1 items-center gap-2 truncate text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"truncate\">{label}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<SimpleTooltip content=\"This video is in the workshop on EpicWeb.dev, but not in the local workshop.\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"Close\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"text-destructive h-4 w-4 shrink-0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\tto={linkProgress(progress)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"text-foreground flex-1 truncate text-sm hover:underline\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={progress.epicLessonUrl}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"text-muted-foreground hover:text-foreground shrink-0\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">No progress data</p>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Commands</CardTitle>\n\t\t\t\t\t\t<CardDescription>Workshop management actions</CardDescription>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<DoubleCheckAdminButton name=\"intent\" value=\"clear-caches\">\n\t\t\t\t\t\t\t\t\t<Icon name=\"Clear\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\tClear local caches\n\t\t\t\t\t\t\t\t</DoubleCheckAdminButton>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<DoubleCheckAdminButton\n\t\t\t\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\t\t\t\tvalue=\"clear-data\"\n\t\t\t\t\t\t\t\t\tclassName=\"border-destructive bg-destructive/80 text-destructive-foreground hover:bg-destructive hover:text-destructive-foreground\"\n\t\t\t\t\t\t\t\t\tdoubleCheckClassName=\"border-destructive bg-destructive text-destructive-foreground\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"TriangleAlert\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\tClear all local data (including auth data)\n\t\t\t\t\t\t\t\t</DoubleCheckAdminButton>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t{data.inspectorRunning ? (\n\t\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t\t<AdminButton name=\"intent\" value=\"stop-inspect\">\n\t\t\t\t\t\t\t\t\t\t<Icon name=\"Stop\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t{isStoppingInspector\n\t\t\t\t\t\t\t\t\t\t\t? 'Stopping inspector...'\n\t\t\t\t\t\t\t\t\t\t\t: 'Stop inspector'}\n\t\t\t\t\t\t\t\t\t</AdminButton>\n\t\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t\t<AdminButton name=\"intent\" value=\"inspect\">\n\t\t\t\t\t\t\t\t\t\t{isStartingInspector\n\t\t\t\t\t\t\t\t\t\t\t? 'Starting inspector...'\n\t\t\t\t\t\t\t\t\t\t\t: 'Start inspector'}\n\t\t\t\t\t\t\t\t\t</AdminButton>\n\t\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Apps</CardTitle>\n\t\t\t\t\t\t<CardDescription>Available workshop apps</CardDescription>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ul className=\"scrollbar-thin scrollbar-thumb-scrollbar flex max-h-48 flex-col gap-2 overflow-y-auto\">\n\t\t\t\t\t\t\t{data.apps.length > 0 ? (\n\t\t\t\t\t\t\t\tdata.apps.map((app) => (\n\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\tkey={app.name}\n\t\t\t\t\t\t\t\t\t\tclassName=\"hover:bg-muted/50 flex items-center gap-3 rounded-md p-2\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{data.processes[app.name] ? (\n\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"stopped\" />\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-sm\">{app.name}</span>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tNo apps available\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Processes</CardTitle>\n\t\t\t\t\t\t<CardDescription>Running development processes</CardDescription>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ul className=\"scrollbar-thin scrollbar-thumb-scrollbar flex max-h-48 flex-col gap-2 overflow-y-auto\">\n\t\t\t\t\t\t\t{Object.entries(data.processes).length > 0 ? (\n\t\t\t\t\t\t\t\tObject.entries(data.processes).map(([key, process]) => (\n\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-muted/30 rounded-md border p-3\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-sm font-semibold\">\n\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div className=\"text-muted-foreground mt-2 flex flex-wrap gap-x-4 gap-y-1 text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">Port:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t{process.port}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t{process.pid && (\n\t\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">PID:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{process.pid}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">Color:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"inline-block h-3 w-3 rounded-full\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{ backgroundColor: process.color }}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tNo processes running\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t{Object.entries(data.testProcesses).length > 0 && (\n\t\t\t\t\t<Card className=\"md:col-span-2\">\n\t\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t\t<CardTitle>Test Processes</CardTitle>\n\t\t\t\t\t\t\t<CardDescription>Test execution processes</CardDescription>\n\t\t\t\t\t\t</CardHeader>\n\t\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t\t<ul className=\"scrollbar-thin scrollbar-thumb-scrollbar flex flex-col gap-2 overflow-y-auto\">\n\t\t\t\t\t\t\t\t{Object.entries(data.testProcesses).map(([key, process]) => (\n\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-muted/30 rounded-md border p-3\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t{process.exitCode === null ||\n\t\t\t\t\t\t\t\t\t\t\tprocess.exitCode === undefined ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t\t\t\t\t) : process.exitCode === 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"stopped\" />\n\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"taken\" />\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-sm font-semibold\">\n\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div className=\"text-muted-foreground mt-2 flex flex-wrap gap-x-4 gap-y-1 text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t{process.pid && (\n\t\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">PID:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{process.pid}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">Exit code:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t{process.exitCode === null ||\n\t\t\t\t\t\t\t\t\t\t\t\tprocess.exitCode === undefined\n\t\t\t\t\t\t\t\t\t\t\t\t\t? 'Running'\n\t\t\t\t\t\t\t\t\t\t\t\t\t: process.exitCode}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</CardContent>\n\t\t\t\t\t</Card>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction Card({\n\tchildren,\n\tclassName,\n}: {\n\tchildren: React.ReactNode\n\tclassName?: string\n}) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'border-border bg-card rounded-lg border p-6 shadow-sm',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t)\n}\n\nfunction CardHeader({ children }: { children: React.ReactNode }) {\n\treturn <div className=\"mb-4\">{children}</div>\n}\n\nfunction CardTitle({ children }: { children: React.ReactNode }) {\n\treturn <h2 className=\"text-foreground text-lg font-semibold\">{children}</h2>\n}\n\nfunction CardDescription({ children }: { children: React.ReactNode }) {\n\treturn <p className=\"text-muted-foreground mt-1 text-sm\">{children}</p>\n}\n\nfunction CardContent({ children }: { children: React.ReactNode }) {\n\treturn <div>{children}</div>\n}\n\nfunction AdminButton({\n\tchildren,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'>) {\n\treturn (\n\t\t<button\n\t\t\t{...props}\n\t\t\tclassName={cn(\n\t\t\t\t'border-border bg-background text-foreground hover:bg-muted hover:text-foreground focus:ring-ring inline-flex w-full items-center justify-center gap-2 rounded-md border px-4 py-2 text-sm font-medium transition-colors focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none disabled:opacity-50',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</button>\n\t)\n}\n\nfunction DoubleCheckAdminButton({\n\tchildren,\n\tdoubleCheckClassName,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'> & {\n\tdoubleCheckClassName?: string\n}) {\n\tconst { doubleCheck, getButtonProps } = useDoubleCheck()\n\n\treturn (\n\t\t<AdminButton\n\t\t\t{...getButtonProps(props)}\n\t\t\tclassName={cn(\n\t\t\t\tprops.className,\n\t\t\t\tdoubleCheck\n\t\t\t\t\t? (doubleCheckClassName ??\n\t\t\t\t\t\t\t'border-destructive bg-destructive text-destructive-foreground')\n\t\t\t\t\t: null,\n\t\t\t)}\n\t\t>\n\t\t\t{doubleCheck ? (\n\t\t\t\t<>\n\t\t\t\t\t<Icon name=\"TriangleAlert\" className=\"h-4 w-4\" />\n\t\t\t\t\tAre you sure?\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\tchildren\n\t\t\t)}\n\t\t</AdminButton>\n\t)\n}\n\nfunction Pinger({\n\tstatus,\n}: {\n\tstatus: 'running' | 'starting' | 'stopped' | 'taken'\n}) {\n\tconst colors = {\n\t\trunning: {\n\t\t\tpinger: 'bg-green-400',\n\t\t\tcircle: 'bg-green-500',\n\t\t},\n\t\tstarting: {\n\t\t\tpinger: 'bg-sky-400',\n\t\t\tcircle: 'bg-sky-500',\n\t\t},\n\t\tstopped: {\n\t\t\tcircle: 'bg-muted-foreground',\n\t\t},\n\t\ttaken: {\n\t\t\tpinger: 'bg-red-400',\n\t\t\tcircle: 'bg-red-500',\n\t\t},\n\t}[status]\n\treturn (\n\t\t<span className=\"relative flex h-3 w-3 shrink-0\">\n\t\t\t{colors.pinger ? (\n\t\t\t\t<span\n\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t'absolute inline-flex h-full w-full animate-ping rounded-full opacity-75',\n\t\t\t\t\t\tcolors.pinger,\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<span\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'relative inline-flex h-3 w-3 rounded-full',\n\t\t\t\t\tcolors.circle,\n\t\t\t\t)}\n\t\t\t/>\n\t\t</span>\n\t)\n}\n","import { getEnv } from '@epic-web/workshop-utils/env.server'\nimport {\n\tgetCommitInfo,\n\tgetLatestWorkshopAppVersion,\n} from '@epic-web/workshop-utils/git.server'\nimport {\n\tcombineServerTimings,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport { dayjs } from '@epic-web/workshop-utils/utils.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { type HeadersFunction, useLoaderData, data } from 'react-router'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader() {\n\tconst timings = makeTimings('versionLoader')\n\tconst [commitInfo, latestVersion] = await Promise.all([\n\t\ttime(() => getCommitInfo(), { timings, type: 'getCommitInfo' }),\n\t\ttime(() => getLatestWorkshopAppVersion().catch((e) => getErrorMessage(e)), {\n\t\t\ttimings,\n\t\t\ttype: 'getLatestWorkshopAppVersion',\n\t\t}),\n\t])\n\n\tconst uptime = process.uptime() * 1000\n\tconst startDate = new Date(Date.now() - uptime)\n\n\treturn data(\n\t\t{\n\t\t\tworkshopInstanceId: getEnv().EPICSHOP_WORKSHOP_INSTANCE_ID,\n\t\t\tworkshopContextCwd: getEnv().EPICSHOP_CONTEXT_CWD,\n\t\t\tworkshopCommit: commitInfo\n\t\t\t\t? {\n\t\t\t\t\t\t...commitInfo,\n\t\t\t\t\t\tdateFormatted: dayjs(commitInfo.date).format('YYYY-MM-DD HH:mm:ss'),\n\t\t\t\t\t\tdateFromNow: dayjs(commitInfo.date).fromNow(),\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t\tlatestWorkshopAppVersion: latestVersion,\n\t\t\tworkshopAppVersion: getEnv().EPICSHOP_APP_VERSION,\n\t\t\tstartTime: startDate.toISOString(),\n\t\t\tstartTimeFormatted: dayjs(startDate).format('YYYY-MM-DD HH:mm:ss'),\n\t\t\tstartTimeFromNow: dayjs(startDate).fromNow(),\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ parentHeaders, loaderHeaders }) => {\n\treturn {\n\t\t'Server-Timing': combineServerTimings(parentHeaders, loaderHeaders),\n\t}\n}\n\nexport default function Version() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst workshopConfig = useWorkshopConfig()\n\n\treturn (\n\t\t<div>\n\t\t\t<h2 className=\"text-lg font-bold\">Workshop Version Information</h2>\n\t\t\t<p>Workshop Instance ID: {data.workshopInstanceId}</p>\n\t\t\t<p>Workshop Context CWD: {data.workshopContextCwd}</p>\n\t\t\t<h3 className=\"text-md font-bold\">Workshop Commit</h3>\n\t\t\t{data.workshopCommit ? (\n\t\t\t\t<>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tHash:{' '}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={`${workshopConfig.githubRepo}/commit/${data.workshopCommit.hash}`}\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{data.workshopCommit.hash}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p>Message: {data.workshopCommit.message}</p>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tDate: {data.workshopCommit.dateFormatted} (\n\t\t\t\t\t\t{data.workshopCommit.dateFromNow})\n\t\t\t\t\t</p>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<p>No commit information available</p>\n\t\t\t)}\n\t\t\t<h3 className=\"text-md font-bold\">Workshop App</h3>\n\t\t\t<p>\n\t\t\t\t{'Current Version: '}\n\t\t\t\t{data.workshopAppVersion ? (\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={`https://github.com/epicweb-dev/epicshop/releases/tag/v${data.workshopAppVersion}`}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.workshopAppVersion}\n\t\t\t\t\t</a>\n\t\t\t\t) : (\n\t\t\t\t\t'Unknown'\n\t\t\t\t)}\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t{'Latest Version: '}\n\t\t\t\t<a\n\t\t\t\t\thref={`https://github.com/epicweb-dev/epicshop/releases/tag/v${data.latestWorkshopAppVersion}`}\n\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t>\n\t\t\t\t\t{data.latestWorkshopAppVersion}\n\t\t\t\t</a>\n\t\t\t</p>\n\t\t\t<h3 className=\"text-md font-bold\">App Start Time</h3>\n\t\t\t<p>\n\t\t\t\t{data.startTimeFormatted} ({data.startTimeFromNow})\n\t\t\t</p>\n\t\t</div>\n\t)\n}\n","import { getApps } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { data, type LoaderFunctionArgs } from 'react-router'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('appsLoader')\n\tconst apps = await getApps({ request, timings })\n\treturn data(\n\t\t{ apps },\n\t\t{ headers: { 'Server-Timing': getServerTimeHeader(timings) } },\n\t)\n}\n","import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tisExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { userHasAccessToWorkshop } from '@epic-web/workshop-utils/epic-api.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport {\n\ttype LoaderFunctionArgs,\n\tuseLoaderData,\n\tuseNavigation,\n\tuseSearchParams,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport { Diff } from '#app/components/diff.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst reqUrl = new URL(request.url)\n\tconst searchParams = reqUrl.searchParams\n\tconst timings = makeTimings('diffLoader')\n\tconst cacheOptions = { request, timings }\n\tconst allAppsFull = await getApps()\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\n\tconst usingDefaultApp1 = !app1Name\n\n\t// defaults to first problem app\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: allAppsFull.filter(isExerciseStepApp).at(0)\n\n\t// defaults to last exercise step app\n\tconst app2 = app2Name\n\t\t? await getAppByName(app2Name)\n\t\t: allAppsFull.filter(isExerciseStepApp).at(-1)\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t}))\n\n\tconst diff = getDiffProp()\n\tconst app1Index = allApps.findIndex((a) => a.name === app1?.name)\n\tconst prevApp1Index = usingDefaultApp1\n\t\t? allApps.length - 2\n\t\t: app1Index === 0\n\t\t\t? -2\n\t\t\t: app1Index - 1\n\tconst prevApp2Index = prevApp1Index + 1\n\tconst nextApp1Index = usingDefaultApp1\n\t\t? 0\n\t\t: app1Index + 1 < allApps.length\n\t\t\t? app1Index + 1\n\t\t\t: -2\n\tconst nextApp2Index = nextApp1Index + 1\n\tconst prevApp1 = allAppsFull[prevApp1Index]?.name\n\tconst prevApp2 = allAppsFull[prevApp2Index]?.name\n\tconst nextApp1 = allAppsFull[nextApp1Index]?.name\n\tconst nextApp2 = allAppsFull[nextApp2Index]?.name\n\tconst prevSearchParams = new URLSearchParams(reqUrl.searchParams)\n\tprevSearchParams.set('app1', prevApp1 ?? '')\n\tprevSearchParams.set('app2', prevApp2 ?? '')\n\tconst nextSearchParams = new URLSearchParams(reqUrl.searchParams)\n\tnextSearchParams.set('app1', nextApp1 ?? '')\n\tnextSearchParams.set('app2', nextApp2 ?? '')\n\treturn {\n\t\tuserHasAccessPromise: userHasAccessToWorkshop({ request, timings }),\n\t\tallApps,\n\t\tdiff,\n\t\tprevLink:\n\t\t\tprevApp1 && prevApp2\n\t\t\t\t? { to: `/diff?${prevSearchParams}`, 'aria-label': 'Previous App' }\n\t\t\t\t: { to: '/diff' },\n\t\tnextLink:\n\t\t\tnextApp1 && nextApp2\n\t\t\t\t? { to: `/diff?${nextSearchParams}`, 'aria-label': 'Next App' }\n\t\t\t\t: { to: '/diff' },\n\t}\n}\n\nexport default function DiffViewer() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst [params] = useSearchParams()\n\tconst paramsWithForcedRefresh = new URLSearchParams(params)\n\tparamsWithForcedRefresh.set('forceFresh', 'diff')\n\tconst navigation = useNavigation()\n\tconst isNavigating = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 200,\n\t\tminDuration: 200,\n\t})\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn('h-screen-safe relative', {\n\t\t\t\t'cursor-wait opacity-30': isNavigating,\n\t\t\t})}\n\t\t>\n\t\t\t<div className=\"h-full pb-16\">\n\t\t\t\t<Diff\n\t\t\t\t\tdiff={data.diff}\n\t\t\t\t\tallApps={data.allApps}\n\t\t\t\t\tuserHasAccessPromise={data.userHasAccessPromise}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"bg-background fixed inset-x-0 bottom-0 z-10 flex h-16 items-center justify-end border-t\">\n\t\t\t\t<div className=\"flex h-full items-center justify-end\">\n\t\t\t\t\t<NavChevrons prev={data.prevLink} next={data.nextLink} />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n","import {\n\ttype ExerciseStepApp,\n\tgetExercise,\n\tgetNextExerciseApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { redirect } from 'react-router'\nimport { type Route } from './+types/diff.$shortcut.ts'\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('diffLoader')\n\n\tconst [exerciseNumber, stepNumber] = params.shortcut?.split('.') ?? []\n\tif (!exerciseNumber) {\n\t\treturn redirect(`/diff`)\n\t}\n\tconst exercise = await getExercise(Number(exerciseNumber), {\n\t\trequest,\n\t\ttimings,\n\t})\n\tconst headers = { 'Server-Timing': timings.toString() }\n\n\tif (!exercise) return redirect(`/diff`, { headers })\n\n\tconst step = stepNumber\n\t\t? exercise.steps.find((s) => s.stepNumber === Number(stepNumber))\n\t\t: exercise.steps.find(Boolean)\n\tconst exerciseStepApp = step?.problem ?? step?.solution\n\tif (!exerciseStepApp) {\n\t\treturn redirect(`/diff`, { headers })\n\t}\n\tlet nextApp = await getNextExerciseApp(exerciseStepApp, {\n\t\trequest,\n\t\ttimings,\n\t})\n\tif (!nextApp) {\n\t\tnextApp = exerciseStepApp\n\t}\n\n\treturn redirect(\n\t\t`/diff?app1=${makeId(exerciseStepApp)}&app2=${makeId(nextApp)}`,\n\t\t{ headers: { 'Server-Timing': timings.toString() } },\n\t)\n}\n\nfunction makeId(app: ExerciseStepApp) {\n\treturn `${pad(app.exerciseNumber)}.${pad(app.stepNumber)}.${app.type}`\n}\n\nfunction pad(number: number) {\n\treturn number.toString().padStart(2, '0')\n}\n","import { getExercises } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { data, type LoaderFunctionArgs } from 'react-router'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('appsLoader')\n\tconst exercises = await getExercises({ request, timings })\n\treturn data(\n\t\t{ exercises },\n\t\t{ headers: { 'Server-Timing': getServerTimeHeader(timings) } },\n\t)\n}\n","import { useEffect } from 'react'\nimport { type z } from 'zod'\n\nexport function useMcpUiInit(rootRef: React.RefObject<HTMLDivElement | null>) {\n\tuseEffect(() => {\n\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\t\tif (!rootRef.current) return\n\n\t\tconst height = rootRef.current.clientHeight\n\t\tconst width = rootRef.current.clientWidth\n\n\t\twindow.parent.postMessage(\n\t\t\t{ type: 'ui-size-change', payload: { height, width } },\n\t\t\t'*',\n\t\t)\n\t}, [rootRef])\n}\n\ntype MessageOptions = { schema?: z.ZodSchema }\n\ntype McpMessageReturnType<Options> = Promise<\n\tOptions extends { schema: z.ZodSchema } ? z.infer<Options['schema']> : unknown\n>\n\ntype McpMessageTypes = {\n\ttool: { toolName: string; params: Record<string, unknown> }\n\tprompt: { prompt: string }\n\tlink: { url: string }\n}\n\ntype McpMessageType = keyof McpMessageTypes\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'tool',\n\tpayload: McpMessageTypes['tool'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'prompt',\n\tpayload: McpMessageTypes['prompt'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'link',\n\tpayload: McpMessageTypes['link'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'link',\n\tpayload: McpMessageTypes['link'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage(\n\ttype: McpMessageType,\n\tpayload: McpMessageTypes[McpMessageType],\n\toptions: MessageOptions = {},\n): McpMessageReturnType<typeof options> {\n\tconst { schema } = options\n\tconst messageId = crypto.randomUUID()\n\n\treturn new Promise((resolve, reject) => {\n\t\tif (!window.parent || window.parent === window) {\n\t\t\tconsole.log(`[MCP] No parent frame available. Would have sent message:`, {\n\t\t\t\ttype,\n\t\t\t\tmessageId,\n\t\t\t\tpayload,\n\t\t\t})\n\t\t\treject(new Error('No parent frame available'))\n\t\t\treturn\n\t\t}\n\n\t\twindow.parent.postMessage({ type, messageId, payload }, '*')\n\n\t\tfunction handleMessage(event: MessageEvent) {\n\t\t\tif (event.data.type !== 'ui-message-response') return\n\t\t\tif (event.data.messageId !== messageId) return\n\t\t\twindow.removeEventListener('message', handleMessage)\n\n\t\t\tconst { response, error } = event.data.payload\n\n\t\t\tif (error) return reject(error)\n\t\t\tif (!schema) return resolve(response)\n\n\t\t\tconst parseResult = schema.safeParse(response)\n\t\t\tif (!parseResult.success) return reject(parseResult.error)\n\n\t\t\treturn resolve(parseResult.data)\n\t\t}\n\n\t\twindow.addEventListener('message', handleMessage)\n\t})\n}\n\nexport { sendMcpMessage }\n\nexport function waitForRenderData<RenderData>(\n\tschema: z.ZodSchema<RenderData>,\n): Promise<RenderData> {\n\treturn new Promise((resolve, reject) => {\n\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\n\t\tfunction handleMessage(event: MessageEvent) {\n\t\t\tif (event.data?.type !== 'ui-lifecycle-iframe-render-data') return\n\t\t\twindow.removeEventListener('message', handleMessage)\n\n\t\t\tconst { renderData, error } = event.data.payload\n\n\t\t\tif (error) return reject(error)\n\t\t\tif (!schema) return resolve(renderData)\n\n\t\t\tconst parseResult = schema.safeParse(renderData)\n\t\t\tif (!parseResult.success) return reject(parseResult.error)\n\n\t\t\treturn resolve(parseResult.data)\n\t\t}\n\n\t\twindow.addEventListener('message', handleMessage)\n\t})\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { useEffect, useRef } from 'react'\nimport { data } from 'react-router'\nimport {\n\tDeferredEpicVideo,\n\tEpicVideoInfoProvider,\n} from '#app/components/epic-video.tsx'\nimport { type Route } from './+types/epic-video.tsx'\nimport { sendMcpMessage } from './__utils.ts'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('epicVideoLoader')\n\tconst videoUrl = new URL(request.url).searchParams.get('url')\n\tinvariantResponse(videoUrl, 'url param is required')\n\tconst videoInfos = getEpicVideoInfos([videoUrl], {\n\t\trequest,\n\t\ttimings,\n\t})\n\treturn data(\n\t\t{ videoInfos, videoUrl },\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport default function EpicVideoEmbedRoute({\n\tloaderData,\n}: Route.ComponentProps) {\n\tconst rootRef = useRef<HTMLDivElement>(null)\n\tuseEffect(() => {\n\t\tvoid loaderData.videoInfos?.finally(() => {\n\t\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\t\t\tif (!rootRef.current) return\n\n\t\t\tconst height = rootRef.current.clientHeight\n\t\t\tconst width = rootRef.current.clientWidth\n\n\t\t\twindow.parent.postMessage(\n\t\t\t\t{ type: 'ui-size-change', payload: { height, width } },\n\t\t\t\t'*',\n\t\t\t)\n\t\t})\n\t}, [loaderData.videoInfos])\n\n\tasync function handleLinksClick(event: React.MouseEvent<HTMLElement>) {\n\t\tconst target = event.target\n\t\tif (!(target instanceof HTMLAnchorElement)) return\n\n\t\tconst href = target.href\n\t\tif (!href) return\n\n\t\tevent.preventDefault()\n\t\tevent.stopPropagation()\n\n\t\tconst url = href.startsWith('http')\n\t\t\t? new URL(href)\n\t\t\t: new URL(href, window.location.origin)\n\t\tconst isLocal = url.host === window.location.host\n\n\t\tif (isLocal && url.pathname === '/login') {\n\t\t\tawait sendMcpMessage('tool', {\n\t\t\t\ttoolName: 'login',\n\t\t\t\tparams: { workshopDirectory: ENV.EPICSHOP_CONTEXT_CWD },\n\t\t\t})\n\t\t}\n\n\t\tawait sendMcpMessage('link', { url: url.toString() })\n\t}\n\n\treturn (\n\t\t<div ref={rootRef} onClickCapture={handleLinksClick}>\n\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={loaderData.videoInfos}>\n\t\t\t\t<DeferredEpicVideo url={loaderData.videoUrl} />\n\t\t\t</EpicVideoInfoProvider>\n\t\t</div>\n\t)\n}\n","import { invariant } from '@epic-web/invariant'\nimport { cachified, ogCache } from '@epic-web/workshop-utils/cache.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\ttype Timings,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { Resvg } from '@resvg/resvg-js'\nimport { renderToStaticMarkup } from 'react-dom/server'\nimport { type LoaderFunctionArgs } from 'react-router'\nimport satori, { type SatoriOptions } from 'satori'\nimport { getDomainUrl, getErrorMessage } from '#app/utils/misc.tsx'\n\nconst WIDTH = 1200\nconst HEIGHT = 630\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('og', 'og image loader')\n\tconst url = new URL(request.url)\n\tconst workshopConfig = getWorkshopConfig()\n\tconst title = url.searchParams.get('title') || workshopConfig.title\n\tconst subtitle = url.searchParams.get('subtitle') || workshopConfig.subtitle\n\tconst urlPathname = url.searchParams.get('urlPathname') || ''\n\tconst logo = workshopConfig.product.logo.startsWith('http')\n\t\t? workshopConfig.product.logo\n\t\t: new URL(workshopConfig.product.logo, getDomainUrl(request)).toString()\n\n\tconst element = (\n\t\t<OgLayout\n\t\t\trequest={request}\n\t\t\tinstructor={workshopConfig.instructor}\n\t\t\turlPathname={urlPathname}\n\t\t\tworkshopTitle={\n\t\t\t\tworkshopConfig.title === title ? null : workshopConfig.title\n\t\t\t}\n\t\t\tproductLogo={logo}\n\t\t\tproductDisplayName={workshopConfig.product.displayName}\n\t\t>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\tflexDirection: 'column',\n\t\t\t\t\tjustifyContent: 'center',\n\t\t\t\t\talignItems: 'center',\n\t\t\t\t\theight: '100%',\n\t\t\t\t\twidth: '100%',\n\t\t\t\t\tcolor: 'white',\n\t\t\t\t\tpadding: 100,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<h1\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\tjustifyContent: 'center',\n\t\t\t\t\t\tfontSize: '80px',\n\t\t\t\t\t\t// https://github.com/vercel/satori/issues/498\n\t\t\t\t\t\ttextWrap: title.includes(' ') ? 'balance' : 'initial',\n\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{title}\n\t\t\t\t</h1>\n\t\t\t\t{subtitle ? (\n\t\t\t\t\t<p\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\tjustifyContent: 'center',\n\t\t\t\t\t\t\tfontSize: '40px',\n\t\t\t\t\t\t\t// https://github.com/vercel/satori/issues/498\n\t\t\t\t\t\t\ttextWrap: subtitle.includes(' ') ? 'balance' : 'initial',\n\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{subtitle}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</OgLayout>\n\t)\n\n\tconst renderHtml = url.searchParams.get('html')\n\tif (renderHtml === 'true') {\n\t\treturn new Response(renderToStaticMarkup(element), {\n\t\t\theaders: { 'Content-Type': 'text/html' },\n\t\t})\n\t}\n\n\tconst debug = url.searchParams.get('debug') === 'true'\n\n\ttry {\n\t\tconst ogImg = await cachified({\n\t\t\trequest,\n\t\t\ttimings,\n\t\t\ttimingKey: 'og-image',\n\t\t\t// if debug is true, then force, otherwise use undefined and it'll be derived from the request\n\t\t\tforceFresh: debug ? debug : undefined,\n\t\t\tkey: request.url,\n\t\t\tcache: ogCache,\n\t\t\tttl: 1000 * 60 * 60 * 24 * 7,\n\t\t\tstaleWhileRevalidate: 1000 * 60 * 60 * 24 * 365,\n\t\t\tgetFreshValue: async () => {\n\t\t\t\treturn await getOgImg(element, { request, timings })\n\t\t\t},\n\t\t})\n\t\t// @ts-ignore 🤷‍♂️ CLI doesn't like this but editor is fine 🙃\n\t\treturn new Response(ogImg, {\n\t\t\theaders: {\n\t\t\t\t'Cache-Control':\n\t\t\t\t\tENV.EPICSHOP_DEPLOYED && !(debug || url.searchParams.has('fresh'))\n\t\t\t\t\t\t? 'public, max-age=31536000, immutable'\n\t\t\t\t\t\t: 'no-cache no-store',\n\t\t\t\t'Content-Type': 'image/png',\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t})\n\t} catch (error) {\n\t\treturn new Response(getErrorMessage(error), {\n\t\t\tstatus: 500,\n\t\t\theaders: { 'Server-Timing': timings.toString() },\n\t\t})\n\t}\n}\n\nasync function getOgImg(\n\tjsx: React.ReactNode,\n\t{ request, timings }: { request: Request; timings: Timings },\n) {\n\tconst url = new URL(request.url)\n\tconst svg = await satori(jsx, {\n\t\twidth: WIDTH,\n\t\theight: HEIGHT,\n\t\tdebug: url.searchParams.get('debug') === 'true',\n\t\tfonts: await Promise.all([\n\t\t\tgetFont({ font: 'Josefin Sans', request, timings }),\n\t\t]).then((fonts) => fonts.flat()),\n\t\tloadAdditionalAsset: async (code: string, segment: string) => {\n\t\t\tif (code === 'emoji') {\n\t\t\t\tconst svg = await getEmoji(segment, { request, timings })\n\t\t\t\tif (!svg) return ''\n\t\t\t\tconst base64 = Buffer.from(svg).toString('base64')\n\t\t\t\treturn `data:image/svg+xml;base64,${base64}`\n\t\t\t}\n\n\t\t\tconsole.error(`Unhandled asset code: \"${code}\" for segment \"${segment}\"`)\n\n\t\t\treturn ''\n\t\t},\n\t})\n\n\tconst resvg = new Resvg(svg)\n\tconst pngData = resvg.render()\n\tconst data = pngData.asPng()\n\n\treturn data\n}\n\nasync function getEmoji(\n\temoji: string,\n\t{ request, timings }: { request: Request; timings: Timings },\n) {\n\tconst emojiCode = emojiToCodePoints(emoji)\n\tif (!emojiCode) return null\n\tconst emojiUrl = `https://cdn.jsdelivr.net/gh/jdecked/twemoji@15/assets/svg/${emojiCode}.svg`\n\treturn cachified({\n\t\tcache: ogCache,\n\t\tkey: emojiUrl,\n\t\trequest,\n\t\ttimings,\n\t\ttimingKey: `loading ${emojiCode}`,\n\t\tgetFreshValue: async () => {\n\t\t\tconst response = await fetch(emojiUrl)\n\t\t\treturn response.text()\n\t\t},\n\t})\n}\n\nfunction emojiToCodePoints(emoji: string) {\n\tconst codePoints = []\n\tfor (let i = 0; i < emoji.length; i++) {\n\t\tconst codePoint = emoji.codePointAt(i)\n\t\tif (!codePoint) continue\n\t\tcodePoints.push(codePoint.toString(16))\n\t\tif (codePoint > 0xffff) {\n\t\t\t// Skip the next code unit for surrogate pairs\n\t\t\ti++\n\t\t}\n\t}\n\treturn codePoints.join('-')\n}\n\nasync function getFont({\n\tfont,\n\tweights = [200, 300, 400, 500, 600, 700],\n\ttimings,\n\trequest,\n}: {\n\tfont: string\n\tweights?: Array<number>\n\ttimings?: Timings\n\trequest?: Request\n}) {\n\tconst weightsString = weights.join(';')\n\tconst fetchUrl = `https://fonts.googleapis.com/css2?family=${font}:wght@${weightsString}`\n\tconst css = await cachified({\n\t\tkey: fetchUrl,\n\t\tcache: ogCache,\n\t\ttimings,\n\t\ttimingKey: `font-${font}`,\n\t\trequest,\n\t\tgetFreshValue: async () => {\n\t\t\treturn fetch(fetchUrl, {\n\t\t\t\theaders: {\n\t\t\t\t\t// Make sure it returns TTF.\n\t\t\t\t\t'User-Agent':\n\t\t\t\t\t\t'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',\n\t\t\t\t},\n\t\t\t}).then((response) => response.text())\n\t\t},\n\t})\n\n\tconst resource = css.matchAll(\n\t\t/src: url\\((.+)\\) format\\('(opentype|truetype)'\\)/g,\n\t)\n\n\treturn Promise.all(\n\t\t[...resource]\n\t\t\t.map((match) => match[1])\n\t\t\t.map((url) => {\n\t\t\t\tinvariant(\n\t\t\t\t\turl,\n\t\t\t\t\t() => `Expected a URL to be parsed from the google font:\\n${css}`,\n\t\t\t\t)\n\t\t\t\treturn fetch(url).then((response) => response.arrayBuffer())\n\t\t\t})\n\t\t\t.map(async (buffer, i) => ({\n\t\t\t\tname: font,\n\t\t\t\tstyle: 'normal',\n\t\t\t\tweight: weights[i],\n\t\t\t\tdata: await buffer,\n\t\t\t})),\n\t) as Promise<SatoriOptions['fonts']>\n}\n\nfunction OgLayout({\n\tinstructor,\n\tchildren,\n\trequest,\n\turlPathname = new URL(request.url).pathname.replace(/\\/og$/, ''),\n\tworkshopTitle,\n}: {\n\tinstructor: ReturnType<typeof getWorkshopConfig>['instructor']\n\trequest: Request\n\tchildren: React.ReactNode\n\tworkshopTitle?: string | null\n\turlPathname?: string | null\n\tproductLogo: string\n\tproductDisplayName: string\n}) {\n\tconst domain = getDomainUrl(request)\n\tconst protocolFreeDomain = domain.replace(/^https?:\\/\\//, '')\n\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\tfontFamily: 'Josefin Sans',\n\t\t\t\tdisplay: 'flex',\n\t\t\t\tflexDirection: 'column',\n\t\t\t\twidth: '100%',\n\t\t\t\theight: '100%',\n\t\t\t\tposition: 'relative',\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tright: 0,\n\t\t\t\t\tbottom: 0,\n\t\t\t\t\tleft: 0,\n\t\t\t\t\twidth: '100%',\n\t\t\t\t\theight: '100%',\n\t\t\t\t\tbackgroundColor: '#080B16',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<img\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\theight: '100%',\n\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\topacity: 0.3,\n\t\t\t\t\t}}\n\t\t\t\t\tsrc={`${domain}/og/background.png`}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div style={{ display: 'flex', position: 'absolute', top: 20, left: 30 }}>\n\t\t\t\t<img height={56} src={`${domain}/og/logo.svg`} />\n\t\t\t</div>\n\t\t\t{instructor ? (\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\tgap: 8,\n\t\t\t\t\t\tjustifyContent: 'center',\n\t\t\t\t\t\talignItems: 'center',\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 20,\n\t\t\t\t\t\tright: 30,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{instructor.avatar ? (\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tsrc={\n\t\t\t\t\t\t\t\tinstructor.avatar.startsWith('/')\n\t\t\t\t\t\t\t\t\t? `${domain}${instructor.avatar}`\n\t\t\t\t\t\t\t\t\t: instructor.avatar\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\twidth: 56,\n\t\t\t\t\t\t\t\theight: 56,\n\t\t\t\t\t\t\t\tborderRadius: '50%',\n\t\t\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{instructor.name ? (\n\t\t\t\t\t\t<h2\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\t\t\topacity: 0.8,\n\t\t\t\t\t\t\t\tcolor: 'white',\n\t\t\t\t\t\t\t\tfontSize: 30,\n\t\t\t\t\t\t\t\tfontWeight: 700,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{instructor.name}\n\t\t\t\t\t\t</h2>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t{children}\n\t\t\t{workshopTitle ? (\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tbottom: 20,\n\t\t\t\t\t\tleft: 30,\n\t\t\t\t\t\tcolor: 'white',\n\t\t\t\t\t\topacity: 0.8,\n\t\t\t\t\t\tfontSize: 20,\n\t\t\t\t\t\tfontWeight: 700,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{workshopTitle}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t{urlPathname == null ? null : (\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tbottom: 20,\n\t\t\t\t\t\tright: 30,\n\t\t\t\t\t\tcolor: 'white',\n\t\t\t\t\t\topacity: 0.8,\n\t\t\t\t\t\tfontSize: 20,\n\t\t\t\t\t\tfontWeight: 700,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{protocolFreeDomain + urlPathname.replace(/\\/$/, '')}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n","import { getProcesses } from '@epic-web/workshop-utils/process-manager.server'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst processes: Record<\n\t\tstring,\n\t\t{ port: number; pid?: number; color: string }\n\t> = {}\n\tfor (const [\n\t\tname,\n\t\t{ port, process, color },\n\t] of getProcesses().devProcesses.entries()) {\n\t\tprocesses[name] = { port, pid: process.pid, color }\n\t}\n\tconst testProcesses: Record<\n\t\tstring,\n\t\t{ pid?: number; exitCode?: number | null; output?: Array<any> }\n\t> = {}\n\tfor (const [\n\t\tname,\n\t\t{ process, exitCode, output },\n\t] of getProcesses().testProcesses.entries()) {\n\t\ttestProcesses[name] = { pid: process?.pid, exitCode, output }\n\t}\n\treturn Response.json({ processes, testProcesses })\n}\n","// TODO: make this a proper healthcheck\nexport const loader = () => new Response('🐨 All good here')\n","import { invariantResponse } from '@epic-web/invariant'\nimport { type Route } from './+types/lookout'\n\nconst SENTRY_HOST = new URL(ENV.SENTRY_DSN).hostname\nconst SENTRY_PROJECT_IDS = [ENV.SENTRY_PROJECT_ID]\n\nexport async function action({ request }: Route.ActionArgs) {\n\tconst envelope = await request.text()\n\tconst piece = envelope.split('\\n')[0]\n\tinvariantResponse(piece, 'no piece in envelope')\n\n\tconst header = JSON.parse(piece ?? '{}') as any\n\tconst dsn = new URL(header.dsn)\n\tconst projectId = dsn.pathname?.replace('/', '')\n\n\tinvariantResponse(\n\t\tdsn.hostname === SENTRY_HOST,\n\t\t`Invalid sentry hostname: ${dsn.hostname}`,\n\t)\n\tinvariantResponse(\n\t\tprojectId && SENTRY_PROJECT_IDS.includes(projectId),\n\t\t`Invalid sentry project id: ${projectId}`,\n\t)\n\n\tconst upstreamSentryURL = `https://${SENTRY_HOST}/api/${projectId}/envelope/`\n\ttry {\n\t\treturn await fetch(upstreamSentryURL, { method: 'POST', body: envelope })\n\t} catch (error) {\n\t\tconsole.error(`Error forwarding Sentry event: ${error}`)\n\t\treturn new Response('Sentry event not forwarded due to network error', {\n\t\t\tstatus: 200,\n\t\t})\n\t}\n}\n","import { generateRobotsTxt } from '@nasa-gcn/remix-seo'\nimport { type LoaderFunctionArgs } from 'react-router'\nimport { getDomainUrl } from '#app/utils/misc.tsx'\n\nexport function loader({ request }: LoaderFunctionArgs) {\n\treturn generateRobotsTxt([\n\t\t{ type: 'sitemap', value: `${getDomainUrl(request)}/sitemap.xml` },\n\t])\n}\n","import { generateSitemap } from '@nasa-gcn/remix-seo'\nimport { type ServerBuild, type LoaderFunctionArgs } from 'react-router'\nimport { getDomainUrl } from '#app/utils/misc.tsx'\n\nexport async function loader({ request, context }: LoaderFunctionArgs) {\n\tconst serverBuild = (await context.serverBuild) as ServerBuild\n\treturn generateSitemap(request, serverBuild.routes, {\n\t\tsiteUrl: getDomainUrl(request),\n\t\theaders: {\n\t\t\t'Cache-Control': `public, max-age=${60 * 5}`,\n\t\t},\n\t})\n}\n"],"names":["Sentry","presence","preferences","ENV","ConfettiShower","sizeClassName","childrenSizeClassName","AnchorOrLink","href","dayjs","Heading","headers","useInterval","formatDuration","index","finished","toast","showToast","data","action","request","formData","intent","get","id","error","status","muteNotification","success","Notifications","unmutedNotifications","fetcher","useFetcher","fetcherRef","useRef","toastedIds","Set","useEffect","notification","current","has","add","info","title","description","children","jsx","message","link","target","className","duration","Infinity","label","onClick","submit","method","useRoute","colorSchemeHint","timeZoneHint","reducedMotionHint","cookieName","ROUTE_PATH","ThemeFormSchema","z","object","theme","enum","loader","referrer","redirect","safeRedirect","submission","parseWithZod","schema","reply","value","responseInit","setTheme","dataWithPE","ThemeSwitch","requestInfo","useRequestInfo","peRedirectInput","usePERedirectInput","form","useForm","lastResult","onValidate","mode","session","nextMode","modeLabel","light","Icon","size","name","dark","system","jsxs","Form","getFormProps","type","SimpleTooltip","content","ErrorList","errors","errorId","useTheme","hints","useHints","fetchers","useFetchers","find","f","optimisticTheme","getUserLocations","cuid","cookie","links","rel","tailwindStylesheetUrl","appStylesheetUrl","sizes","meta","loaderData","getSeoMetaTags","instructor","workshopTitle","workshopSubtitle","timings","makeTimings","workshopConfig","getWorkshopConfig","subtitle","getTheme","confettiId","confettiHeaders","getConfetti","toastHeaders","getToast","isOnlinePromise","checkConnection","asyncStuff","promiseHash","userId","getUserId","getPreferences","progress","getProgress","catch","e","console","emptyProgress","user","getUserInfo","userHasAccess","userHasAccessToWorkshop","apps","getApps","repoUpdates","checkForUpdatesCached","getUnmutedNotifications","exerciseChanges","checkForExerciseChanges","loggedInProductHosts","getLoggedInProductHosts","presentUsers","getPresentUsers","mutedNotifications","getMutedNotifications","remoteCommit","includes","updatesAvailable","map","fullPath","relativePath","getEnv","protocol","URL","url","hostname","port","origin","domain","getDomainUrl","getHints","path","pathname","separator","sep","online","users","combineHeaders","toString","getSetClientIdCookieHeader","Document","env","style","lang","ClientHintCheck","Meta","charSet","Links","dangerouslySetInnerHTML","__html","JSON","stringify","ScrollRestoration","Scripts","App","useLoaderData","navigation","useNavigation","showSpinner","useSpinDelay","state","delay","minDuration","altDown","useAltDown","showKeyboardShortcuts","setShowKeyboardShortcuts","React","useState","handleToggle","prev","window","addEventListener","removeEventListener","fontSize","cn","exerciseWarning","dismissed","ExerciseWarningBanner","Outlet","Confetti","EpicToaster","UpdateToast","EpicProgress","KeyboardShortcutsDialog","open","onOpenChange","_UNSAFE_withComponentProps","AppWithProviders","Presence","TooltipProvider","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary","params","splat","segments","split","length","isNaN","Number","newPath","Response","Location","NotFound","location","useLocation","statusHandlers","Link","to","getSnapshot","subscribe","useEpicProgress","useRootLoaderData","progressFetcher","formAction","p","optimisticCompleted","optimisticLessonSlug","epicLessonSlug","epicCompletedAt","Date","now","useRequireEpicProgress","useNextExerciseRoute","currentPathname","scoreProgress","a","exerciseNumber","stepNumber","sortedProgress","sort","b","nextProgress","ex","padStart","st","problemRoute","solutionRoute","percentageClassNames","useExerciseProgressClassName","exerciseProgress","filter","percentComlete","reduce","acc","numerator","Math","useProgressItemClassName","progressItemSearch","progressItem","useProgressItem","ensureUndeployed","requireAuthInfo","complete","lessonSlug","invariantResponse","beforeProgress","result","updateProgress","lessonProgress","getCompletionAnnouncement","allOtherAreFinished","every","otherExerciseLessons","otherAreFinished","announcement","createConfettiHeaders","createToastHeaders","ProgressToggle","animationRef","buttonRef","Boolean","startAnimation","setStartAnimation","navigationLocationStateFrom","from","navigationLocationPathname","locationPathname","focus","key","latest","Promise","resolve","setTimeout","then","animationPromises","getAnimations","allSettled","EPICSHOP_DEPLOYED","motion","button","ref","clsx","div","initial","scale","opacity","animate","transition","ease","exercises","playgroundAppName","all","getExercises","getPlaygroundAppName","playgroundNumbersAndType","extractNumbersAndTypeFromAppNameOrPath","playground","appName","solutions","problems","steps","problem","solution","isMenuOpened","Vary","getServerTimeHeader","loaderHeaders","parentHeaders","combineServerTimings","opacities","shadows","getScoreClassNames","score","opacityNumber","round","shadowNumber","FacePile","loggedInUser","useOptionalUser","usePresence","product","displayNameShort","useWorkshopConfig","limit","numberOverLimit","shouldShowNumberOverLimit","tiffany","alt","src","overLimitLabel","slice","scoreClassNames","locations","imageUrl","imageUrlSmall","avatarUrl","hasAccess","local","some","loc","productHostEmojis","getUniqueProductHostEmojis","loggedInEmojis","getLoggedInProductEmojis","optOut","Tooltip","TooltipTrigger","asChild","tabIndex","TooltipContent","doingLabel","locationLabel","getLocationLabel","line1","getProductHostEmoji","productHost","line2","hosts","host","join","uniqueHosts","Array","useIsWide","makeMediaQueryStore","isWide","isHydrated","useHydrated","setMenuOpenedState","useRevalidationWS","watchPaths","setMenuOpened","document","NoUserBanner","MobileNavigation","onMenuOpenChange","Navigation","exercise","exercisePortion","s","displayName","useUserHasAccess","details","Fragment","EPICSHOP_GITHUB_REPO","Logo","Dialog","DialogTrigger","DialogContent","DialogHeader","DialogDescription","itemVariants","hidden","x","visible","NavigationExerciseListItem","progressClassName","li","variants","NavigationExerciseStepListItem","nextExerciseRoute","useParams","isOnline","useIsOnline","listVariants","when","staggerChildren","NavToggle","ul","NavLink","prefetch","isActive","showPlayground","getExercisePath","getExerciseStepPath","email","OPENED_MENU_WIDTH","app","menuControls","useAnimationControls","menuVariants","close","width","initialOpenRef","menuButtonRef","path01Variants","d","closed","path02Variants","moving","path01Controls","path02Controls","toggleMenu","start","handleKeyUp","event","click","height","viewBox","stroke","strokeWidth","y","handle","getSitemapEntries","logout","deleteCache","redirectWithToast","setPreferences","useConnectDiscordURL","Account","useUser","config","discordMember","useOptionalDiscordMember","connectDiscordURL","imageUrlLarge","slug","Button","varient","fileApp","resolveApps","dev","getBaseUrl","portNumber","filePath","firstExisting","endsWith","outputFiles","compileTs","file","text","getFileResponse","fsExtra","readFile","mimeType","mimeTypes","lookup","etagValue","etag","ifNoneMatch","Buffer","byteLength","ETag","args","api","getApiModule","mod","cleanupError","ApiModuleSchema","function","optional","apiFiles","readdir","test","apiFile","esbuildOptions","platform","sourcemap","define","apiCode","dataUrl","apiModule","safeParse","Error","stack","replace","relevantPaths","watchParams","URLSearchParams","append","js","baseApp","isPlaygroundApp","getAppByName","htmlFile","hasHtml","pathExists","html","indexFiles","startsWith","indexCss","indexJs","indexTs","indexTsx","scripts","appTitle","baseAppTitle","isExerciseStepApp","getExercise","isProblemApp","isSolutionApp","isExampleApp","script","testName","testFile","testFiles","testScriptPath","testScriptSrc","testScriptTag","testableHtml","useDiscordCTALink","DiscordCTA","DiscordRoute","flatMap","route","ExercisesLayout","PlaybackTimeSchema","time","number","expiresAt","string","transform","usePlayerPreferences","rootData","pendingPreferencesFetcher","submittingData","json","optimisticPlayerPrefs","player","PlayerPreferencesSchema","flatten","useLatest","MuxPlayer","muxPlayerRef","props","playerPreferences","playerPreferencesFetcher","metadataLoaded","setMetadataLoaded","currentTimeSessionKey","playbackId","currentTime","setCurrentTime","playerPreferencesRef","stored","sessionStorage","getItem","parse","getTime","removeItem","updatePreferences","useDebounce","subs","textTracks","t","kind","newPrefs","playbackRate","volumeRate","volume","isDeepEqual","encType","subtitlePref","preferredTextTrack","getTrackById","RealMuxPlayer","playbackRates","thumbnailTime","onRateChange","onVolumeChange","streamType","defaultHiddenCaptions","onTimeUpdate","setItem","toISOString","accentColor","targetLiveWindow","NaN","minResolution","getMinResolutionValue","maxResolution","getMaxResolutionValue","onLoadedMetadata","obj1","obj2","isArray","i","keys1","Object","keys","keys2","resolution","MinResolution","noLessThan480p","noLessThan540p","noLessThan720p","noLessThan1080p","noLessThan1440p","noLessThan2160p","MaxResolution","upTo720p","upTo1080p","upTo1440p","upTo2160p","getFileDescriptorSchema","appFile","union","literal","LaunchSchema","intersection","line","coerce","column","syncTo","array","workshopFile","getAll","syncToIsProvided","values","v","rawData","getFiles","fileDescriptor","filepath","colum","fileDescriptorApp","filesToOpen","originFiles","originFile","destFile","ensureDir","dirname","promises","copyFile","results","push","launchEditor","r","messages","useLaunchFetcher","onUpdate","LaunchEditorImpl","fileList","syncToType","showProgressBarField","LaunchGitHub","useApps","safePath","githubFileRoot","EPICSHOP_GITHUB_ROOT","EPICSHOP_CONTEXT_CWD","filename","appFileLine","lineNumber","EditFileOnGitHub","compact","handleClick","altKey","preventDefault","FormData","githubPath","LaunchEditor","mdxComponents","matches","getRootMatchLoaderData","ogTitle","ogDescription","desc","getExercise404Data","readmeFilepath","getWorkshopRoot","dirName","firstStep","articleId","slugify","exerciseReadme","exerciseTitle","firstType","epicVideoInfosPromise","getEpicVideoInfos","instructionsEpicVideoEmbeds","h1","ExerciseNumberRoute","firstStepNumber","String","instructionsCode","EpicVideoInfoProvider","Mdx","code","components","ElementScrollRestoration","elementQuery","Exercise404ErrorBoundary","SetPlaygroundSchema","reset","nullable","redirectTo","converseApp","solutionName","problemName","setPlayground","getErrorMessage","forceFresh","getDiffCode","SetPlayground","tooltipText","buttonProps","submitButton","PlaygroundChooser","allApps","Select","Root","onValueChange","Trigger","Value","placeholder","Portal","Content","position","align","ScrollUpButton","Viewport","Group","Label","SelectItem","ScrollDownButton","Item","ItemText","ItemIndicator","SetAppToPlayground","isOutdated","withParam","splitCookieName","computeSplitPercent","input","defaultValue","isFinite","min","max","pageTitle","exerciseStepApp","emoji","cacheOptions","allAppsFull","problemApp","solutionApp","getExerciseApp","reqUrl","pathnameParam","searchParams","delete","errorData","getStep404Data","requireExerciseApp","playgroundApp","getStepId","getStepNameAndId","exerciseNumberStr","stepNumberStr","stepName","stepId","ar","findIndex","getAppDisplayName","exerciseId","exerciseIndex","step","nextApp","prevApp","requireExercise","getNextExerciseApp","getPrevExerciseApp","exerciseApps","isLastStep","isFirstStep","subroute","cookieHeader","rawSplit","splitPercent","epicVideoEmbeds","prevStepLink","getAppPageRoute","nextStepLink","isUpToDate","diffFiles","getDiffFiles","ExercisePartRoute","inBrowserBrowserRef","containerRef","leftPaneRef","setSplitPercent","leftWidthPx","setLeftWidthPx","left","ro","ResizeObserver","entries","entry","contentRect","observe","getBoundingClientRect","disconnect","setCookie","percent","clamped","startDrag","initialClientX","container","rect","dragging","iframes","querySelectorAll","originalPointerEvents","el","pointerEvents","forEach","handleMove","clientX","cleanup","relativeX","onMouseMove","buttons","onTouchMove","firstTouch","touches","body","cursor","userSelect","titleBits","StepMdx","TouchedFiles","diffFilesPromise","NavChevrons","next","role","onMouseDown","onDoubleClick","onTouchStart","context","startApp","invariant","runAppDev","running","appRunningResult","waitOnApp","errorMessage","statusText","stopApp","closeProcess","stopPort","AppStopper","inFlightIntent","inFlightState","PortStopper","AppStarter","Loading","isRunning","portIsAvailable","getAppRunningState","appInfo","stackBlitzUrl","TestsList","Preview","diff","testActionSchema","testEventSchema","exitCode","boolean","output","timestamp","testEventQueueSchema","processEntry","getTestProcessEntry","eventStream","signal","setup","send","queue","sendEvent","interval","setInterval","isTestRunning","testProcess","process","handleStdOutData","handleStdErrData","handleExit","stdout","off","stderr","on","clearInterval","runAppTests","kill","clearTestProcessEntry","simpleReducer","getNext","TestOutput","dispatch","useReducer","version","lines","revalidator","useRevalidator","latestRevalidatorRef","ansi","useAnsiToHtml","lastMessage","useEventSource","parsed","revalidate","TestRunner","onRun","AnimatedBars","StopTest","ClearTest","onClear","toHtml","stripCursorMovements","latestOnRun","latestOnClear","onStop","latestOnStop","app1Name","app2Name","app1","app2","getDiffProp","diffCode","discordPostsPromise","fetchDiscordPosts","userHasAccessPromise","userHasAccessToExerciseStep","getTestState","tabs","isValidPreview","newSearchParams","set","useOutletContext","useSearchParams","preview","navigate","useNavigate","shouldHideTab","tab","discordChannelId","getTabStatus","testExitCode","appData","activeTab","altDiffUrl","handleDiffTabClick","ctrlKey","shiftKey","metaKey","Tabs","List","preventScrollReset","StatusIndicator","forceMount","Playground","problemAppName","Tests","Diff","DiscordChat","TestUI","playgroundAppInfo","exerciseFormTemplate","forms","exerciseFormEmbedUrl","encodeURIComponent","nextExercise","finishedFilepath","finishedEpicVideoEmbeds","exerciseFinished","ExerciseFinished","finishedCode","Survey","iframeLoaded","setIframeLoaded","onLoad","onError","colorScheme","compiledFinished","getWorkshopFinished","lastExercises","workshopFormTemplate","workshop","workshopFormEmbedUrl","compiled","workshopFinished","workshopReadme","getWorkshopInstructions","ExerciseListItem","Index","exerciseLinks","lastExercise","lastStep","LastExerciseRedirect","CodeReceivedEventSchema","EVENTS","USER_CODE_RECEIVED","AuthResolvedEventSchema","AUTH_RESOLVED","AuthRejectedEventSchema","AUTH_REJECTED","default","EventSchema","handleCodeReceived","handleAuthResolved","handleAuthRejected","authEmitter","isAuthenticated","getAuthInfo","registerDevice","Login","loginFetcher","clickedVerificationLink","setClickedVerificationLink","authError","setAuthError","userCodeInfo","setUserCodeInfo","ButtonLink","optOutPresence","persistPlayground","dismissExerciseWarning","persist","AccountSettings","fontSizePreference","presencePreferences","playgroundPreferences","exerciseWarningPreferences","isSubmitting","htmlFor","defaultChecked","disabled","Support","repoGroups","match","groups","repoUrl","repoIssuesUrl","org","repo","WorkspaceStructure","AdminLayout","currentWorkshopId","EPICSHOP_WORKSHOP_INSTANCE_ID","allWorkshopCaches","getAllWorkshopCaches","globalCaches","getGlobalCaches","allCaches","filterQuery","availableWorkshopIds","w","workshopId","globalDirExists","globalCacheDirectoryExists","selectedWorkshops","filteredCaches","workshopCache","caches","cache","toLowerCase","availableWorkshops","ActionSchema","discriminatedUnion","cacheName","newValue","fromEntries","deleteCacheEntry","deleteWorkshopCache","parsedValue","updateCacheEntry","WorkshopChooser","setSearchParams","handleWorkshopChange","checked","newSelected","onChange","SearchFilter","inputValue","setInputValue","inputRef","handleSearch","query","handleClear","IconButton","InlineEntryEditor","currentValue","entryKey","editValue","setEditValue","hasChanges","setHasChanges","handleSave","handleChange","handleReset","SkippedFilesSection","skippedFiles","skippedFile","formatFileSize","DoubleCheckButton","onConfirm","CacheManagement","deleteEntry","totalSize","sum","skippedSize","grandTotal","CacheMetadata","metadata","iconButtonClassName","useDayjs","expirationTime","calculateExpirationTime","createdDate","createdTime","timeRemaining","formatTimeRemaining","isExpired","isExpiringSoon","format","ClientOnly","fromNow","ttl","swr","doubleCheck","useDoubleCheck","getButtonProps","readEntryByPath","db","readDb","loadJSON","DbRoute","processes","testProcesses","color","getProcesses","devProcesses","pid","inspectorRunning","isInspectorRunning","clearData","clearCaches","startInspector","stopInspector","sortProgress","linkProgress","epicProgress","isStartingInspector","isStoppingInspector","progressStatus","completed","incomplete","Card","CardHeader","CardTitle","CardDescription","CardContent","epicLessonUrl","DoubleCheckAdminButton","doubleCheckClassName","AdminButton","Pinger","backgroundColor","colors","pinger","circle","starting","stopped","taken","commitInfo","latestVersion","getCommitInfo","getLatestWorkshopAppVersion","uptime","startDate","workshopInstanceId","workshopContextCwd","workshopCommit","dateFormatted","date","dateFromNow","latestWorkshopAppVersion","workshopAppVersion","EPICSHOP_APP_VERSION","startTime","startTimeFormatted","startTimeFromNow","Version","githubRepo","hash","usingDefaultApp1","at","app1Index","prevApp1Index","prevApp2Index","nextApp1Index","nextApp2Index","prevApp1","prevApp2","nextApp1","nextApp2","prevSearchParams","nextSearchParams","prevLink","nextLink","DiffViewer","paramsWithForcedRefresh","isNavigating","shortcut","makeId","pad","videoUrl","videoInfos","EpicVideoEmbedRoute","rootRef","finally","parent","postMessage","clientHeight","clientWidth","payload","handleLinksClick","HTMLAnchorElement","stopPropagation","isLocal","sendMcpMessage","toolName","workshopDirectory","onClickCapture","DeferredEpicVideo","WIDTH","HEIGHT","urlPathname","logo","element","OgLayout","productLogo","productDisplayName","display","flexDirection","justifyContent","alignItems","padding","textWrap","textAlign","renderHtml","renderToStaticMarkup","debug","ogImg","cachified","timingKey","ogCache","staleWhileRevalidate","getFreshValue","getOgImg","svg","satori","fonts","getFont","font","flat","loadAdditionalAsset","segment","getEmoji","base64","resvg","Resvg","pngData","render","asPng","emojiCode","emojiToCodePoints","emojiUrl","response","fetch","codePoints","codePoint","codePointAt","weights","weightsString","fetchUrl","css","resource","matchAll","arrayBuffer","buffer","weight","protocolFreeDomain","fontFamily","top","right","bottom","objectFit","gap","avatar","borderRadius","margin","fontWeight","SENTRY_HOST","SENTRY_DSN","SENTRY_PROJECT_IDS","SENTRY_PROJECT_ID","envelope","piece","header","dsn","projectId","upstreamSentryURL","generateRobotsTxt","serverBuild","generateSitemap","routes","siteUrl"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../app/entry.server.tsx","../../../workshop-presence/src/presence.ts","../../../workshop-presence/src/presence.server.ts","../../app/components/confetti.tsx","../../app/assets/icons.svg","../../app/components/icons.tsx","../../app/utils/misc.tsx","../../app/components/error-boundary.tsx","../../app/components/exercise-warning-banner.tsx","../../app/components/ui/dialog.tsx","../../app/components/keyboard-shortcuts-dialog.tsx","../../app/components/progress-bar.tsx","../../app/components/toaster.tsx","../../app/components/ui/tooltip.tsx","../../app/components/update-repo.tsx","../../app/routes/admin+/notifications.tsx","../../app/utils/root-loader.ts","../../app/utils/client-hints.tsx","../../app/utils/forms.tsx","../../app/utils/pe.tsx","../../app/routes/theme/theme-session.server.ts","../../app/routes/theme/index.tsx","../../app/styles/app.css?url","../../app/styles/tailwind.css?url","../../app/utils/confetti.server.ts","../../app/utils/online.ts","../../app/utils/presence.tsx","../../app/utils/seo.ts","../../app/utils/toast.server.ts","../../app/root.tsx","../../app/routes/$.tsx","../../app/components/media-query.ts","../../app/components/workshop-config.tsx","../../app/components/product.tsx","../../app/components/revalidation-ws.tsx","../../app/components/user.tsx","../../app/routes/progress.tsx","../../app/routes/_app+/_layout.tsx","../../app/components/button.tsx","../../app/routes/_app+/account.tsx","../../app/utils/compile-app.server.ts","../../app/routes/_app+/app.$appName+/__utils.ts","../../app/routes/_app+/app.$appName+/$.ts","../../app/routes/_app+/app.$appName+/api.$.ts","../../app/routes/_app+/app.$appName+/epic_ws[.js].ts","../../app/routes/_app+/app.$appName+/index.ts","../../app/routes/_app+/app.$appName+/test.$testName.ts","../../app/routes/_app+/discord.tsx","../../app/routes/_app+/exercise+/_layout.tsx","../../app/routes/video-player/index.tsx","../../app/components/loading.tsx","../../app/components/epic-video.tsx","../../app/routes/launch-editor.tsx","../../app/components/mermaid.tsx","../../app/utils/mdx.tsx","../../app/routes/_app+/exercise+/__shared/error-boundary.server.ts","../../app/routes/_app+/exercise+/__shared/error-boundary.tsx","../../app/routes/_app+/exercise+/$exerciseNumber.tsx","../../app/components/nav-chevrons.tsx","../../app/routes/set-playground.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/step-mdx.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/touched-files.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/_layout.tsx","../../app/routes/start.tsx","../../app/components/in-browser-browser.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/preview.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/utils.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/app.tsx","../../app/components/accordion.tsx","../../app/components/diff.tsx","../../app/components/status-indicator.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/discord.server.ts","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/discord.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/playground-window.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/playground.tsx","../../app/utils/ansi-text.ts","../../app/components/in-browser-test-runner.tsx","../../app/routes/test.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/tests.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/index.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/test.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.index.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.finished.tsx","../../app/routes/_app+/finished.tsx","../../app/routes/_app+/index.tsx","../../app/routes/_app+/l.tsx","../../app/utils/auth-events.ts","../../app/utils/auth.server.ts","../../app/routes/login-sse.tsx","../../app/routes/_app+/login.tsx","../../app/routes/_app+/preferences.tsx","../../app/routes/_app+/support.tsx","../../app/routes/_app+/workspace-structure.tsx","../../app/routes/admin+/_layout.tsx","../../app/routes/admin+/apps.tsx","../../app/routes/admin+/cache.tsx","../../app/routes/admin+/cache.$.ts","../../app/routes/admin+/db.tsx","../../app/routes/admin+/admin-utils.server.tsx","../../app/routes/admin+/index.tsx","../../app/routes/admin+/version.tsx","../../app/routes/apps.tsx","../../app/routes/diff.tsx","../../app/routes/diff.$shortcut.tsx","../../app/routes/exercises.tsx","../../app/routes/mcp-ui+/__utils.ts","../../app/routes/mcp-ui+/epic-video.tsx","../../app/routes/og.tsx","../../app/routes/processes.tsx","../../app/routes/resources+/healthcheck.ts","../../app/routes/resources+/lookout.ts","../../app/routes/robots[.]txt.ts","../../app/routes/sitemap[.]xml.ts"],"sourcesContent":["import { PassThrough } from 'stream'\nimport { createReadableStreamFromReadable } from '@react-router/node'\n// Dynamic import of Sentry with error handling\nconst sentryPromise = import('@sentry/react-router').catch((error) => {\n\tconsole.warn(\n\t\t'Failed to import @sentry/react-router:',\n\t\terror instanceof Error ? error.message : String(error),\n\t\t'- Sentry monitoring will be disabled but the application will continue to work normally',\n\t)\n\treturn null\n})\n\nimport { isbot } from 'isbot'\nimport { renderToPipeableStream } from 'react-dom/server'\nimport {\n\ttype EntryContext,\n\tServerRouter,\n\ttype LoaderFunctionArgs,\n\ttype ActionFunctionArgs,\n} from 'react-router'\n\nexport const streamTimeout = 60000\nconst ABORT_DELAY = streamTimeout + 1000\n\nexport async function handleError(\n\terror: unknown,\n\t{ request }: LoaderFunctionArgs | ActionFunctionArgs,\n): Promise<void> {\n\tif (request.signal.aborted) return\n\t// Don't send errors to Sentry for bot requests\n\tif (isbot(request.headers.get('user-agent'))) return\n\tif (ENV.EPICSHOP_IS_PUBLISHED) {\n\t\tconst Sentry = await sentryPromise\n\t\tSentry?.captureException(error)\n\t}\n}\n\nexport default function handleRequest(\n\trequest: Request,\n\tresponseStatusCode: number,\n\tresponseHeaders: Headers,\n\treactRouterContext: EntryContext,\n) {\n\tconst callbackName = isbot(request.headers.get('user-agent'))\n\t\t? 'onAllReady'\n\t\t: 'onShellReady'\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet didError = false\n\n\t\tconst { pipe, abort } = renderToPipeableStream(\n\t\t\t<ServerRouter context={reactRouterContext} url={request.url} />,\n\t\t\t{\n\t\t\t\t[callbackName]() {\n\t\t\t\t\tconst body = new PassThrough()\n\n\t\t\t\t\tresponseHeaders.set('Content-Type', 'text/html')\n\n\t\t\t\t\tif (ENV.EPICSHOP_IS_PUBLISHED && process.env.SENTRY_DSN) {\n\t\t\t\t\t\tresponseHeaders.append('Document-Policy', 'js-profiling')\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve(\n\t\t\t\t\t\tnew Response(createReadableStreamFromReadable(body), {\n\t\t\t\t\t\t\tstatus: didError ? 500 : responseStatusCode,\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\tpipe(body)\n\t\t\t\t},\n\t\t\t\tonShellError(err: unknown) {\n\t\t\t\t\treject(err)\n\t\t\t\t},\n\t\t\t\tonError(error: unknown) {\n\t\t\t\t\tdidError = true\n\t\t\t\t\tconsole.error(error)\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\tsetTimeout(abort, ABORT_DELAY)\n\t})\n}\n","import { z } from 'zod'\n\nexport const partykitRoom = 'epic-web-presence'\n// export const partykitBaseUrl = `http://127.0.0.1:1999/parties/main/${partykitRoom}`\nexport const partykitBaseUrl = `https://epic-web-presence.kentcdodds.partykit.dev/parties/main/${partykitRoom}`\n\nexport const RepoStatusSchema = z.object({\n\tupdatesAvailable: z.boolean().nullable().optional(),\n\tcommitsAhead: z.number().nullable().optional(),\n\tcommitsBehind: z.number().nullable().optional(),\n\tlocalCommit: z.string().nullable().optional(),\n\tremoteCommit: z.string().nullable().optional(),\n})\n\nexport type RepoStatus = z.infer<typeof RepoStatusSchema>\n\nexport const LocationSchema = z.object({\n\tworkshopTitle: z.string().nullable().optional(),\n\torigin: z.string().nullable().optional(),\n\tproductHost: z.string().nullable().optional(),\n\texercise: z\n\t\t.object({\n\t\t\ttype: z\n\t\t\t\t.union([z.literal('problem'), z.literal('solution')])\n\t\t\t\t.nullable()\n\t\t\t\t.optional(),\n\t\t\texerciseNumber: z.number().nullable().optional(),\n\t\t\tstepNumber: z.number().nullable().optional(),\n\t\t})\n\t\t.nullable()\n\t\t.optional(),\n\t// Version of the epicshop app for this location/workshop\n\tepicshopVersion: z.string().nullable().optional(),\n\t// Repository status (updates available, commits ahead/behind) for this location/workshop\n\trepoStatus: RepoStatusSchema.nullable().optional(),\n\t// ISO timestamp of when the user last sent an update for this location (server-set)\n\tlastUpdatedAt: z.string().nullable().optional(),\n})\n\nexport type Location = z.infer<typeof LocationSchema>\n\nexport const UserSchema = z.object({\n\tid: z.string(),\n\thasAccess: z.boolean().nullable().optional(),\n\t// TODO: remove the avatarUrl field once people have updated their workshops\n\tavatarUrl: z.string().nullable().optional(),\n\timageUrlSmall: z.string().nullable().optional(),\n\timageUrlLarge: z.string().nullable().optional(),\n\tname: z.string().nullable().optional(),\n\toptOut: z.boolean().nullable().optional(),\n\tloggedInProductHosts: z.array(z.string()).nullable().optional(),\n\t// Single location (for backward compat and single-connection case)\n\tlocation: LocationSchema.nullable().optional(),\n\t// Multiple locations when user is connected from multiple workshops\n\tlocations: z.array(LocationSchema).nullable().optional(),\n})\n\nexport const MessageSchema = z\n\t.object({\n\t\ttype: z.literal('remove-user'),\n\t\tpayload: z.object({ id: z.string() }),\n\t})\n\t.or(z.object({ type: z.literal('add-user'), payload: UserSchema }))\n\t.or(\n\t\tz.object({\n\t\t\ttype: z.literal('presence'),\n\t\t\tpayload: z.object({ users: z.array(UserSchema) }),\n\t\t}),\n\t)\n\nexport type Message = z.infer<typeof MessageSchema>\n\nexport type User = z.infer<typeof UserSchema>\n\nexport const PresenceSchema = z.object({ users: z.array(UserSchema) })\n\n// Product host to emoji mapping for FacePile badges\nexport const productHostEmojis: Record<string, string> = {\n\t'www.epicreact.dev': '🚀',\n\t'www.epicai.pro': '⚡',\n\t'www.epicweb.dev': '🌌',\n}\n\nexport function getProductHostEmoji(\n\thost: string | null | undefined,\n): string | null {\n\tif (!host) return null\n\treturn productHostEmojis[host] ?? null\n}\n","import {\n\tcachified,\n\tmakeSingletonCache,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetAuthInfo,\n\tgetLoggedInProductHosts,\n\tgetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { getEnv } from '@epic-web/workshop-utils/env.server'\nimport {\n\tgetUserInfo,\n\tuserHasAccessToWorkshop,\n} from '@epic-web/workshop-utils/epic-api.server'\nimport { checkForUpdatesCached } from '@epic-web/workshop-utils/git.server'\nimport { type Timings } from '@epic-web/workshop-utils/timing.server'\nimport { getUserId } from '@epic-web/workshop-utils/user.server'\nimport {\n\tPresenceSchema,\n\tpartykitBaseUrl,\n\ttype Location,\n\ttype RepoStatus,\n\ttype User,\n} from './presence.ts'\n\nexport const presenceCache = makeSingletonCache<Array<User>>('PresenceCache')\n\nexport async function getPresentUsers({\n\ttimings,\n\trequest,\n}: { timings?: Timings; request?: Request } = {}): Promise<Array<User>> {\n\tconst presence = await cachified({\n\t\tkey: 'presence',\n\t\tcache: presenceCache,\n\t\ttimings,\n\t\trequest,\n\t\tttl: 1000 * 2,\n\t\tswr: 1000 * 60 * 60 * 24,\n\t\tofflineFallbackValue: { users: [] },\n\t\tcheckValue: PresenceSchema,\n\t\tasync getFreshValue(context) {\n\t\t\ttry {\n\t\t\t\tconst response = await Promise.race([\n\t\t\t\t\tfetch(`${partykitBaseUrl}/presence`),\n\t\t\t\t\tnew Promise<Response>((resolve) =>\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tresolve(new Response('Timeout', { status: 500 }))\n\t\t\t\t\t\t}, 500),\n\t\t\t\t\t),\n\t\t\t\t] as const)\n\t\t\t\tif (response.statusText === 'Timeout') {\n\t\t\t\t\tthrow new Error(`Timeout fetching partykit presence`)\n\t\t\t\t}\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Unexpected response from partykit: ${response.status} ${response.statusText}`,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tconst presence = PresenceSchema.parse(await response.json())\n\t\t\t\treturn presence\n\t\t\t} catch {\n\t\t\t\t// console.error(err)\n\t\t\t\tcontext.metadata.ttl = 300\n\t\t\t\treturn { users: [] }\n\t\t\t}\n\t\t},\n\t})\n\tconst { users } = presence\n\n\tconst authInfo = await getAuthInfo()\n\tconst userId = request\n\t\t? (await getUserId({ request })).id\n\t\t: (authInfo?.id ?? null)\n\n\tconst preferences = await getPreferences()\n\tconst isOptOut = preferences?.presence.optOut ?? false\n\n\t// If no userId, just return other users\n\tif (!userId) {\n\t\treturn uniqueUsers(users)\n\t}\n\n\t// Get logged in product hosts for the local user\n\tconst loggedInProductHosts = await getLoggedInProductHosts()\n\n\t// Get epicshop version and repo status\n\tconst ENV = getEnv()\n\tconst epicshopVersion = ENV.EPICSHOP_APP_VERSION ?? null\n\n\t// Get repo status (updates available, commits ahead/behind)\n\tlet repoStatus: RepoStatus | null = null\n\ttry {\n\t\tconst updateStatus = await checkForUpdatesCached()\n\t\tif ('updatesAvailable' in updateStatus) {\n\t\t\trepoStatus = {\n\t\t\t\tupdatesAvailable: updateStatus.updatesAvailable,\n\t\t\t\tcommitsAhead:\n\t\t\t\t\t'commitsAhead' in updateStatus ? updateStatus.commitsAhead : null,\n\t\t\t\tcommitsBehind:\n\t\t\t\t\t'commitsBehind' in updateStatus ? updateStatus.commitsBehind : null,\n\t\t\t\tlocalCommit:\n\t\t\t\t\t'localCommit' in updateStatus ? updateStatus.localCommit : null,\n\t\t\t\tremoteCommit:\n\t\t\t\t\t'remoteCommit' in updateStatus ? updateStatus.remoteCommit : null,\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors from checking for updates\n\t}\n\n\tconst config = getWorkshopConfig()\n\tconst url = request ? new URL(request.url) : undefined\n\n\t// Build location with version and repo status\n\tconst location: Location = {\n\t\tworkshopTitle: config.title,\n\t\torigin: url ? url.origin : undefined,\n\t\tproductHost: config.product.host,\n\t\tepicshopVersion,\n\t\trepoStatus,\n\t}\n\tif (url) {\n\t\tif (url.pathname.startsWith('/exercise/')) {\n\t\t\tconst [exerciseNumber, stepNumber, type] = url.pathname\n\t\t\t\t.split('/')\n\t\t\t\t.slice(2)\n\t\t\tlocation.exercise = {\n\t\t\t\texerciseNumber: isNaN(Number(exerciseNumber))\n\t\t\t\t\t? null\n\t\t\t\t\t: Number(exerciseNumber),\n\t\t\t\tstepNumber: isNaN(Number(stepNumber)) ? null : Number(stepNumber),\n\t\t\t\ttype:\n\t\t\t\t\ttype === 'problem'\n\t\t\t\t\t\t? 'problem'\n\t\t\t\t\t\t: type === 'solution'\n\t\t\t\t\t\t\t? 'solution'\n\t\t\t\t\t\t\t: null,\n\t\t\t}\n\t\t}\n\t}\n\n\t// If opted out, include user with minimal info but still include location\n\tif (isOptOut) {\n\t\tconst optOutUser: User = {\n\t\t\tid: userId,\n\t\t\toptOut: true,\n\t\t\tloggedInProductHosts,\n\t\t\tlocation,\n\t\t}\n\t\treturn uniqueUsers([...users.filter((u) => u.id !== userId), optOutUser])\n\t}\n\n\t// Build full user info\n\tconst user: User = {\n\t\tid: userId,\n\t\tloggedInProductHosts,\n\t\tlocation,\n\t}\n\n\tif (authInfo) {\n\t\tconst [userInfo, hasAccess] = await Promise.all([\n\t\t\tgetUserInfo({ request, timings }),\n\t\t\tuserHasAccessToWorkshop({ request, timings }),\n\t\t])\n\n\t\tObject.assign(user, {\n\t\t\tname: userInfo?.name,\n\t\t\tavatarUrl: userInfo?.imageUrlLarge,\n\t\t\timageUrlSmall: userInfo?.imageUrlSmall,\n\t\t\timageUrlLarge: userInfo?.imageUrlLarge,\n\t\t\thasAccess,\n\t\t})\n\t}\n\n\treturn uniqueUsers([...users.filter((u) => u.id !== userId), user])\n}\n\n// A user maybe on the same page in multiple tabs\n// so let's make sure we only show them once\nfunction uniqueUsers(users: Array<User>) {\n\tconst seen = new Set()\n\treturn users.filter(Boolean).filter((user) => {\n\t\tif (seen.has(user.id)) {\n\t\t\treturn false\n\t\t}\n\t\tseen.add(user.id)\n\t\treturn true\n\t})\n}\n","import { Index as ConfettiShower } from 'confetti-react'\nimport { ClientOnly } from 'remix-utils/client-only'\n\nexport function Confetti({ id }: { id?: string | null }) {\n\tif (!id) return null\n\n\treturn (\n\t\t<ClientOnly>\n\t\t\t{() => (\n\t\t\t\t<ConfettiShower\n\t\t\t\t\tkey={id}\n\t\t\t\t\trun={Boolean(id)}\n\t\t\t\t\trecycle={false}\n\t\t\t\t\tnumberOfPieces={800}\n\t\t\t\t\twidth={window.innerWidth}\n\t\t\t\t\theight={window.innerHeight}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</ClientOnly>\n\t)\n}\n","export default \"__VITE_ASSET__CMaiXz4u__\"","import * as React from 'react'\nimport iconsSvg from '#app/assets/icons.svg'\nimport { cn } from '#app/utils/misc.tsx'\n\ntype Sizes = 12 | 14 | 16 | 20 | 24 | 28 | 32 | 40\n\n// can't use styles in an external SVG sprite, so animated icons get inlined.\nexport function AnimatedBars({\n\ttitle,\n\tsize = 16,\n\t...props\n}: { title?: string; size?: Sizes } & React.ComponentPropsWithoutRef<'svg'>) {\n\treturn (\n\t\t<svg\n\t\t\twidth={size}\n\t\t\theight={size}\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\taria-hidden={!title}\n\t\t\t{...props}\n\t\t>\n\t\t\t{title ? <title>{title}</title> : null}\n\t\t\t<g fill=\"currentColor\">\n\t\t\t\t<g className=\"nc-loop-dots-16-icon-f\">\n\t\t\t\t\t<circle cx=\"3\" cy=\"8\" fill=\"currentColor\" r=\"2\" />\n\t\t\t\t\t<circle cx=\"8\" cy=\"8\" r=\"2\" />\n\t\t\t\t\t<circle cx=\"13\" cy=\"8\" fill=\"currentColor\" r=\"2\" />\n\t\t\t\t</g>\n\t\t\t\t<style>{`.nc-loop-dots-16-icon-f{--animation-duration:1s}.nc-loop-dots-16-icon-f *{opacity:.4;transform:scale(.7)}.nc-loop-dots-16-icon-f :nth-child(1),.nc-loop-dots-16-icon-f :nth-child(3){animation:nc-loop-dots-anim-2b var(--animation-duration) infinite linear}.nc-loop-dots-16-icon-f :nth-child(1){transform-origin:3px 8px}.nc-loop-dots-16-icon-f :nth-child(2){animation:nc-loop-dots-anim-1b calc(var(--animation-duration)/2) infinite linear;animation-delay:calc(var(--animation-duration)/4);transform-origin:8px 8px}.nc-loop-dots-16-icon-f :nth-child(3){animation-delay:calc(var(--animation-duration)/2);transform-origin:13px 8px}@keyframes nc-loop-dots-anim-1b{0%,100%{opacity:.4;transform:scale(.7)}50%{opacity:1;transform:scale(1)}}@keyframes nc-loop-dots-anim-2b{0%,100%,66%{opacity:.4;transform:scale(.7)}33%{opacity:1;transform:scale(1)}}`}</style>\n\t\t\t</g>\n\t\t</svg>\n\t)\n}\n\nexport type IconName =\n\t| 'Keyboard'\n\t| 'Linked'\n\t| 'Unlinked'\n\t| 'TriangleAlert'\n\t| 'TriangleSmall'\n\t| 'ArrowLeft'\n\t| 'ArrowRight'\n\t| 'Sun'\n\t| 'Moon'\n\t| 'ChevronLeft'\n\t| 'ChevronRight'\n\t| 'ChevronDown'\n\t| 'ChevronUp'\n\t| 'CheckSmall'\n\t| 'TriangleDownSmall'\n\t| 'Question'\n\t| 'Remove'\n\t| 'ExternalLink'\n\t| 'Refresh'\n\t| 'Files'\n\t| 'Clear'\n\t| 'Stop'\n\t| 'Deleted'\n\t| 'Modified'\n\t| 'Added'\n\t| 'Renamed'\n\t| 'Close'\n\t| 'Error'\n\t| 'Notify'\n\t| 'Success'\n\t| 'Sun'\n\t| 'Moon'\n\t| 'Laptop'\n\t| 'Video'\n\t| 'User'\n\t| 'EpicWeb'\n\t| 'EpicWebGradient'\n\t| 'FastForward'\n\t| 'Discord'\n\t| 'Chat'\n\t| 'House'\n\t| 'WifiNoConnection'\n\t| 'Copy'\n\nconst sizeClassName = {\n\tfont: 'w-[1em] h-[1em]',\n\txs: 'w-3 h-3',\n\tsm: 'w-4 h-4',\n\tmd: 'w-5 h-5',\n\tlg: 'w-6 h-6',\n\txl: 'w-7 h-7',\n\t'2xl': 'w-8 h-8',\n} as const\n\ntype Size = keyof typeof sizeClassName\n\nconst childrenSizeClassName = {\n\tfont: 'gap-1.5',\n\txs: 'gap-1.5',\n\tsm: 'gap-1.5',\n\tmd: 'gap-2',\n\tlg: 'gap-2',\n\txl: 'gap-3',\n\t'2xl': 'gap-4',\n} satisfies Record<Size, string>\n\n/**\n * Renders an SVG icon. The icon defaults to the size of the font. To make it\n * align vertically with neighboring text, you can pass the text as a child of\n * the icon and it will be automatically aligned.\n * Alternatively, if you're not ok with the icon being to the left of the text,\n * you need to wrap the icon and text in a common parent and set the parent to\n * display \"flex\" (or \"inline-flex\") with \"items-center\" and a reasonable gap.\n */\nexport function Icon({\n\tname,\n\tsize = 'font',\n\ttitle,\n\tclassName,\n\tchildren,\n\t...props\n}: React.SVGProps<SVGSVGElement> & {\n\tname: IconName\n\ttitle?: string\n\tsize?: Size\n}) {\n\tif (children) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={`inline-flex items-center ${childrenSizeClassName[size]}`}\n\t\t\t>\n\t\t\t\t<Icon name={name} size={size} className={className} {...props} />\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t)\n\t}\n\treturn (\n\t\t<svg\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t>\n\t\t\t{title ? <title>{title}</title> : null}\n\t\t\t<use href={`${iconsSvg}#${name}`} fill=\"transparent\" />\n\t\t</svg>\n\t)\n}\n","import { type ExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport slugify from '@sindresorhus/slugify'\nimport { clsx, type ClassValue } from 'clsx'\nimport dayjsLib from 'dayjs'\nimport relativeTimePlugin from 'dayjs/plugin/relativeTime'\nimport utcPlugin from 'dayjs/plugin/utc'\nimport * as React from 'react'\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport {\n\tLink,\n\tuseFormAction,\n\tuseNavigation,\n\ttype LinkProps,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport { extendTailwindMerge } from 'tailwind-merge'\nimport { Icon } from '#app/components/icons.tsx'\n\nconst useServerSafeLayoutEffect =\n\ttypeof window === 'undefined' ? () => {} : useLayoutEffect\n\ntype AnchorProps = React.DetailedHTMLProps<\n\tReact.AnchorHTMLAttributes<HTMLAnchorElement>,\n\tHTMLAnchorElement\n>\n\nexport const AnchorOrLink = function AnchorOrLink({\n\tref,\n\t...props\n}: AnchorProps &\n\tLinkProps & {\n\t\treload?: boolean\n\t}) {\n\tconst {\n\t\tto,\n\t\thref,\n\n\t\tdownload,\n\t\treload = false,\n\t\tprefetch,\n\t\tchildren,\n\t\t...rest\n\t} = props\n\tlet toUrl = ''\n\tlet shouldUserRegularAnchor = reload || Boolean(download)\n\n\tif (!shouldUserRegularAnchor && typeof href === 'string') {\n\t\tshouldUserRegularAnchor = href.includes(':') || href.startsWith('#')\n\t}\n\n\tif (!shouldUserRegularAnchor && typeof to === 'string') {\n\t\ttoUrl = to\n\t\tshouldUserRegularAnchor = to.includes(':')\n\t}\n\n\tif (!shouldUserRegularAnchor && typeof to === 'object') {\n\t\ttoUrl = `${to.pathname ?? ''}${to.hash ? `#${to.hash}` : ''}${\n\t\t\tto.search ? `?${to.search}` : ''\n\t\t}`\n\t\tshouldUserRegularAnchor = Boolean(to.pathname?.includes(':'))\n\t}\n\n\tif (shouldUserRegularAnchor) {\n\t\treturn (\n\t\t\t<a {...rest} download={download} href={href ?? toUrl} ref={ref}>\n\t\t\t\t{children}\n\t\t\t</a>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<Link prefetch={prefetch} to={to ?? href ?? ''} {...rest} ref={ref}>\n\t\t\t\t{children}\n\t\t\t</Link>\n\t\t)\n\t}\n}\n\nfunction setupDayjs() {\n\tdayjsLib.extend(utcPlugin)\n\tdayjsLib.extend(relativeTimePlugin)\n\treturn dayjsLib\n}\n\nexport function useDayjs() {\n\tconst [dayjs] = useState(() => setupDayjs())\n\treturn dayjs\n}\n\nexport function ensureUndeployed() {\n\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\tthrow new Response(\n\t\t\t'EPICSHOP_DEPLOYED is true, cannot perform this action. Run this locally instead.',\n\t\t\t{\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t)\n\t}\n}\n\nexport function ensureDeployed() {\n\tif (!ENV.EPICSHOP_DEPLOYED) {\n\t\tthrow new Response(\n\t\t\t'EPICSHOP_DEPLOYED is false, cannot perform this action. Run deployed version instead.',\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n}\n\nexport function useAltDown() {\n\tconst [altDown, setAltDown] = React.useState(false)\n\n\tReact.useEffect(() => {\n\t\tconst set = (e: KeyboardEvent) => setAltDown(e.altKey)\n\t\tdocument.addEventListener('keydown', set)\n\t\tdocument.addEventListener('keyup', set)\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keyup', set)\n\t\t\tdocument.removeEventListener('keydown', set)\n\t\t}\n\t}, [])\n\treturn altDown\n}\n\nexport const Heading = function Heading({\n\tref,\n\tid,\n\tchildren,\n\tas: asProp,\n\tclassName,\n\t...props\n}: {\n\tref: React.RefObject<HTMLHeadingElement>\n\tid?: string\n\tchildren: React.ReactNode\n\tas?: React.ElementType\n\tclassName?: string\n}) {\n\tconst Comp = asProp ?? 'h1'\n\tconst slugId = id ?? slugify(children ? String(children) : '')\n\treturn (\n\t\t<Comp\n\t\t\tid={slugId || undefined}\n\t\t\tref={ref}\n\t\t\tclassName={cn('group relative', className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{slugId ? (\n\t\t\t\t<Link\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tto={`#${slugId}`}\n\t\t\t\t\tclassName=\"absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 p-2 opacity-0 transition group-hover:opacity-100 motion-safe:transition\"\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"Linked\" />\n\t\t\t\t</Link>\n\t\t\t) : null}\n\t\t\t{children}\n\t\t</Comp>\n\t)\n}\nexport function getUserImgSrc(imageId?: string | null) {\n\treturn imageId ? `/resources/user-images/${imageId}` : '/img/user.png'\n}\n\nexport function getNoteImgSrc(imageId: string) {\n\treturn `/resources/note-images/${imageId}`\n}\n\nexport function getErrorMessage(\n\terror: unknown,\n\tdefaultMessage: string = 'Unknown Error',\n) {\n\tif (typeof error === 'string') return error\n\tif (\n\t\terror &&\n\t\ttypeof error === 'object' &&\n\t\t'message' in error &&\n\t\ttypeof error.message === 'string'\n\t) {\n\t\treturn error.message\n\t}\n\treturn defaultMessage\n}\n\nconst customTwMerge = extendTailwindMerge({})\n\nexport function cn(...inputs: ClassValue[]) {\n\treturn customTwMerge(clsx(inputs))\n}\n\nexport function getDomainUrl(request: Request) {\n\tconst url = new URL(request.url)\n\tconst host =\n\t\trequest.headers.get('X-Forwarded-Host') ??\n\t\trequest.headers.get('host') ??\n\t\turl.host\n\n\tconst protocol = host.includes('localhost') ? 'http:' : url.protocol\n\treturn `${protocol}//${host}`\n}\n\nexport function getBaseUrl({\n\trequest,\n\tdomain = request ? getDomainUrl(request) : window.location.origin,\n\tport,\n}: {\n\tport: number\n} & (\n\t| {\n\t\t\trequest: Request\n\t\t\tdomain?: never\n\t }\n\t| {\n\t\t\trequest?: never\n\t\t\tdomain: string\n\t }\n)) {\n\tconst url = new URL(domain)\n\turl.port = String(port)\n\treturn url.toString()\n}\n\nexport function getReferrerRoute(request: Request) {\n\t// spelling errors and whatever makes this annoyingly inconsistent\n\t// in my own testing, `referer` returned the right value, but 🤷‍♂️\n\tconst referrer =\n\t\trequest.headers.get('referer') ??\n\t\trequest.headers.get('referrer') ??\n\t\trequest.referrer\n\tconst domain = getDomainUrl(request)\n\tif (referrer.startsWith(domain)) {\n\t\treturn referrer.slice(domain.length)\n\t} else {\n\t\treturn '/'\n\t}\n}\n\n/**\n * Merge multiple headers objects into one (uses set so headers are overridden)\n */\nexport function mergeHeaders(\n\t...headers: Array<ResponseInit['headers'] | null | undefined>\n) {\n\tconst merged = new Headers()\n\tfor (const header of headers) {\n\t\tif (!header) continue\n\t\tfor (const [key, value] of new Headers(header).entries()) {\n\t\t\tmerged.set(key, value)\n\t\t}\n\t}\n\treturn merged\n}\n\n/**\n * Combine multiple header objects into one (uses append so headers are not overridden)\n */\nexport function combineHeaders(\n\t...headers: Array<ResponseInit['headers'] | null | undefined>\n) {\n\tconst combined = new Headers()\n\tfor (const header of headers) {\n\t\tif (!header) continue\n\t\tfor (const [key, value] of new Headers(header).entries()) {\n\t\t\tcombined.append(key, value)\n\t\t}\n\t}\n\treturn combined\n}\n\n/**\n * Combine multiple response init objects into one (uses combineHeaders)\n */\nexport function combineResponseInits(\n\t...responseInits: Array<ResponseInit | null | undefined>\n) {\n\tlet combined: ResponseInit = {}\n\tfor (const responseInit of responseInits) {\n\t\tcombined = {\n\t\t\t...responseInit,\n\t\t\theaders: combineHeaders(combined.headers, responseInit?.headers),\n\t\t}\n\t}\n\treturn combined\n}\n\n/**\n * Returns true if the current navigation is submitting the current route's\n * form. Defaults to the current route's form action and method POST.\n *\n * Defaults state to 'non-idle'\n *\n * NOTE: the default formAction will include query params, but the\n * navigation.formAction will not, so don't use the default formAction if you\n * want to know if a form is submitting without specific query params.\n */\nexport function useIsPending({\n\tformAction,\n\tformMethod = 'POST',\n\tstate = 'non-idle',\n}: {\n\tformAction?: string\n\tformMethod?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE'\n\tstate?: 'submitting' | 'loading' | 'non-idle'\n} = {}) {\n\tconst contextualFormAction = useFormAction()\n\tconst navigation = useNavigation()\n\tconst isPendingState =\n\t\tstate === 'non-idle'\n\t\t\t? navigation.state !== 'idle'\n\t\t\t: navigation.state === state\n\treturn (\n\t\tisPendingState &&\n\t\tnavigation.formAction === (formAction ?? contextualFormAction) &&\n\t\tnavigation.formMethod === formMethod\n\t)\n}\n\n/**\n * This combines useSpinDelay (from https://npm.im/spin-delay) and useIsPending\n * from our own utilities to give you a nice way to show a loading spinner for\n * a minimum amount of time, even if the request finishes right after the delay.\n *\n * This avoids a flash of loading state regardless of how fast or slow the\n * request is.\n */\nexport function useDelayedIsPending({\n\tformAction,\n\tformMethod,\n\tdelay = 400,\n\tminDuration = 300,\n}: Parameters<typeof useIsPending>[0] &\n\tParameters<typeof useSpinDelay>[1] = {}) {\n\tconst isPending = useIsPending({ formAction, formMethod })\n\tconst delayedIsPending = useSpinDelay(isPending, {\n\t\tdelay,\n\t\tminDuration,\n\t})\n\treturn delayedIsPending\n}\n\nfunction callAll<Args extends Array<unknown>>(\n\t...fns: Array<((...args: Args) => unknown) | undefined>\n) {\n\treturn (...args: Args) => fns.forEach((fn) => fn?.(...args))\n}\n\n/**\n * Use this hook with a button and it will make it so the first click sets a\n * `doubleCheck` state to true, and the second click will actually trigger the\n * `onClick` handler. This allows you to have a button that can be like a\n * \"are you sure?\" experience for the user before doing destructive operations.\n */\nexport function useDoubleCheck() {\n\tconst [doubleCheck, setDoubleCheck] = useState(false)\n\n\tfunction getButtonProps(\n\t\tprops?: React.ButtonHTMLAttributes<HTMLButtonElement>,\n\t) {\n\t\tconst onBlur: React.ButtonHTMLAttributes<HTMLButtonElement>['onBlur'] =\n\t\t\t() => setDoubleCheck(false)\n\n\t\tconst onClick: React.ButtonHTMLAttributes<HTMLButtonElement>['onClick'] =\n\t\t\tdoubleCheck\n\t\t\t\t? () => setDoubleCheck(false)\n\t\t\t\t: (e) => {\n\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t\tsetDoubleCheck(true)\n\t\t\t\t\t}\n\n\t\tconst onKeyUp: React.ButtonHTMLAttributes<HTMLButtonElement>['onKeyUp'] = (\n\t\t\te,\n\t\t) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\tsetDoubleCheck(false)\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t...props,\n\t\t\tonBlur: callAll(onBlur, props?.onBlur),\n\t\t\tonClick: callAll(onClick, props?.onClick),\n\t\t\tonKeyUp: callAll(onKeyUp, props?.onKeyUp),\n\t\t}\n\t}\n\n\treturn { doubleCheck, getButtonProps }\n}\n\nexport function useInterval(callback: () => void, delay: number | null) {\n\tconst savedCallback = useRef(callback)\n\n\t// Remember the latest callback if it changes.\n\tuseServerSafeLayoutEffect(() => {\n\t\tsavedCallback.current = callback\n\t}, [callback])\n\n\t// Set up the interval.\n\tuseEffect(() => {\n\t\t// Don't schedule if no delay is specified.\n\t\t// Note: 0 is a valid value for delay.\n\t\tif (delay === null) {\n\t\t\treturn\n\t\t}\n\n\t\tconst id = setInterval(() => {\n\t\t\tsavedCallback.current()\n\t\t}, delay)\n\n\t\treturn () => {\n\t\t\tclearInterval(id)\n\t\t}\n\t}, [delay])\n}\n\n/**\n * Simple debounce implementation\n */\nfunction debounce<Callback extends (...args: Parameters<Callback>) => void>(\n\tfn: Callback,\n\tdelay: number,\n) {\n\tlet timer: ReturnType<typeof setTimeout> | null = null\n\treturn (...args: Parameters<Callback>) => {\n\t\tif (timer) clearTimeout(timer)\n\t\ttimer = setTimeout(() => {\n\t\t\tfn(...args)\n\t\t}, delay)\n\t}\n}\n\n/**\n * Debounce a callback function\n */\nexport function useDebounce<\n\tCallback extends (...args: Parameters<Callback>) => ReturnType<Callback>,\n>(callback: Callback, delay: number) {\n\tconst callbackRef = useRef(callback)\n\tuseEffect(() => {\n\t\tcallbackRef.current = callback\n\t})\n\treturn useMemo(\n\t\t() =>\n\t\t\tdebounce(\n\t\t\t\t(...args: Parameters<Callback>) => callbackRef.current(...args),\n\t\t\t\tdelay,\n\t\t\t),\n\t\t[delay],\n\t)\n}\n\nexport async function downloadFile(url: string, retries: number = 0) {\n\tconst MAX_RETRIES = 3\n\ttry {\n\t\tconst response = await fetch(url)\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Failed to fetch image with status ${response.status}`)\n\t\t}\n\t\tconst contentType = response.headers.get('content-type') ?? 'image/jpg'\n\t\tconst blob = Buffer.from(await response.arrayBuffer())\n\t\treturn { contentType, blob }\n\t} catch (e) {\n\t\tif (retries > MAX_RETRIES) throw e\n\t\treturn downloadFile(url, retries + 1)\n\t}\n}\n\nexport function getExercisePath(exerciseNumber: number, suffix?: 'finished') {\n\tconst exerciseNumberStr = exerciseNumber.toString().padStart(2, '0')\n\tif (!suffix) return `/exercise/${exerciseNumberStr}`\n\n\treturn `/exercise/${exerciseNumberStr}/${suffix}`\n}\n\nexport function getExerciseStepPath(\n\texerciseNumber: number,\n\tstepNumber: number,\n\ttype?: ExerciseStepApp['type'],\n) {\n\tconst exerciseNumberStr = exerciseNumber.toString().padStart(2, '0')\n\tif (!stepNumber) return `/exercise/${exerciseNumberStr}`\n\n\tconst stepNumberStr = stepNumber.toString().padStart(2, '0')\n\tif (!type) return `/exercise/${exerciseNumberStr}/${stepNumberStr}`\n\n\treturn `/exercise/${exerciseNumberStr}/${stepNumberStr}/${type}`\n}\n\nexport function calculateExpirationTime(metadata: {\n\tcreatedTime: number\n\tttl?: number | null\n}): number | null {\n\tconst { createdTime, ttl } = metadata\n\tif (ttl === undefined || ttl === null || ttl === Infinity) {\n\t\treturn null // Never expires\n\t}\n\treturn createdTime + ttl\n}\n\nexport function formatTimeRemaining(expirationTime: number): {\n\ttext: string\n\tisExpired: boolean\n\tisExpiringSoon: boolean\n} {\n\tconst now = Date.now()\n\tconst remaining = expirationTime - now\n\n\tif (remaining <= 0) {\n\t\treturn { text: 'Expired', isExpired: true, isExpiringSoon: false }\n\t}\n\n\tconst seconds = Math.floor(remaining / 1000)\n\tconst minutes = Math.floor(seconds / 60)\n\tconst hours = Math.floor(minutes / 60)\n\tconst days = Math.floor(hours / 24)\n\n\tlet text: string\n\tlet isExpiringSoon: boolean\n\n\tif (days > 0) {\n\t\ttext = `${days}d ${hours % 24}h`\n\t\tisExpiringSoon = days < 1.5\n\t} else if (hours > 0) {\n\t\ttext = `${hours}h ${minutes % 60}m`\n\t\tisExpiringSoon = hours < 2\n\t} else if (minutes > 0) {\n\t\ttext = `${minutes}m ${seconds % 60}s`\n\t\tisExpiringSoon = minutes < 10\n\t} else {\n\t\ttext = `${seconds}s`\n\t\tisExpiringSoon = true\n\t}\n\n\treturn { text, isExpired: false, isExpiringSoon }\n}\n\nexport function formatDuration(ms: number): string {\n\tif (ms < 1000) return `${Math.round(ms)}ms`\n\tif (ms < 60000) return `${Math.round(ms / 1000)}s`\n\tif (ms < 3600000) return `${Math.round(ms / 60000)}m`\n\tif (ms < 86400000) return `${Math.round(ms / 3600000)}h`\n\tif (ms < 604800000) return `${Math.round(ms / 86400000)}d`\n\tif (ms < 2629746000) return `${Math.round(ms / 604800000)}w`\n\tif (ms < 31556952000) return `${Math.round(ms / 2629746000)}mo`\n\treturn `${Math.round(ms / 31556952000)}y`\n}\n\nexport function formatFileSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes} B`\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n\tif (bytes < 1024 * 1024 * 1024) {\n\t\treturn `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n\t}\n\treturn `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`\n}\n","// Dynamic import of Sentry with error handling\nconst Sentry = await import('@sentry/react-router').catch((error) => {\n\tconsole.warn(\n\t\t'Failed to import @sentry/react-router:',\n\t\terror instanceof Error ? error.message : String(error),\n\t\t'- Sentry monitoring will be disabled but the application will continue to work normally',\n\t)\n\treturn null\n})\n\nimport { useEffect, useState } from 'react'\nimport {\n\tisRouteErrorResponse,\n\tuseParams,\n\tuseRouteError,\n\ttype ErrorResponse,\n} from 'react-router'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\n\ntype StatusHandler = (info: {\n\terror: ErrorResponse\n\tparams: Record<string, string | undefined>\n}) => React.ReactNode | null\n\nconst defaultStatusHandlers: Record<number, StatusHandler> = {\n\t400: ({ error }) => (\n\t\t<div>\n\t\t\t<h1>Bad Request</h1>\n\t\t\t<p>{error.data}</p>\n\t\t</div>\n\t),\n\t401: () => (\n\t\t<div>\n\t\t\t<h1>Unauthorized</h1>\n\t\t\t<p>You don't have permission to access this resource.</p>\n\t\t</div>\n\t),\n\t403: () => (\n\t\t<div>\n\t\t\t<h1>Forbidden</h1>\n\t\t\t<p>You don't have permission to access this resource.</p>\n\t\t</div>\n\t),\n\t404: () => (\n\t\t<div>\n\t\t\t<h1>Not Found</h1>\n\t\t\t<p>Sorry, we couldn't find what you were looking for.</p>\n\t\t</div>\n\t),\n\t500: ({ error }) => (\n\t\t<div>\n\t\t\t<h1>Internal Server Error</h1>\n\t\t\t<p>Sorry, something went wrong on our end.</p>\n\t\t\t<p>{error.data}</p>\n\t\t</div>\n\t),\n\t502: () => (\n\t\t<div>\n\t\t\t<h1>Bad Gateway</h1>\n\t\t\t<p>Sorry, we're having a temporary problem. Please try again later.</p>\n\t\t\t<button onClick={() => window.location.reload()}>Refresh</button>\n\t\t</div>\n\t),\n\t503: () => (\n\t\t<div>\n\t\t\t<h1>Service Unavailable</h1>\n\t\t\t<p>Sorry, we're having a temporary problem. Please try again later.</p>\n\t\t\t<button onClick={() => window.location.reload()}>Refresh</button>\n\t\t</div>\n\t),\n}\n\nexport function GeneralErrorBoundary({\n\tclassName = 'container flex items-center justify-center p-20 text-h2',\n\tdefaultStatusHandler = ({ error }) => (\n\t\t<p>\n\t\t\t{error.status} {error.data}\n\t\t</p>\n\t),\n\tstatusHandlers: givenStatusHandlers,\n\tunexpectedErrorHandler = (error) => <p>{getErrorMessage(error)}</p>,\n}: {\n\tclassName?: string\n\tdefaultStatusHandler?: StatusHandler\n\tstatusHandlers?: Record<number, StatusHandler>\n\tunexpectedErrorHandler?: (error: unknown) => React.ReactNode | null\n}) {\n\tconst [isServerDown, setIsServerDown] = useState(false)\n\tconst error = useRouteError()\n\tconst params = useParams()\n\tconst isResponse = isRouteErrorResponse(error)\n\tconst statusHandlers = {\n\t\t...defaultStatusHandlers,\n\t\t...givenStatusHandlers,\n\t}\n\n\tuseEffect(() => {\n\t\tif (isResponse) return\n\t\tif (ENV.EPICSHOP_IS_PUBLISHED) {\n\t\t\tSentry?.captureException(error)\n\t\t}\n\t}, [error, isResponse])\n\n\tuseEffect(() => {\n\t\t// if error is \"Failed to fetch\", trigger a fetch to '/resources/healthcheck' and if it fails, show a message to the user that the server is down\n\t\tif (error instanceof Error && error.message.includes('Failed to fetch')) {\n\t\t\tfetch('/resources/healthcheck').catch(() => {\n\t\t\t\tsetIsServerDown(true)\n\t\t\t})\n\t\t}\n\t}, [error])\n\n\tif (typeof document !== 'undefined') {\n\t\tconsole.error(error)\n\t}\n\n\treturn (\n\t\t<div className={className}>\n\t\t\t{isServerDown ? (\n\t\t\t\t<div className=\"flex flex-col items-center justify-center gap-6\">\n\t\t\t\t\t<h1 className=\"text-h2 font-bold\">Server is down</h1>\n\t\t\t\t\t<p className=\"text-body-md\">\n\t\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t? \"Sorry, we're having a temporary problem. Please try again later.\"\n\t\t\t\t\t\t\t: 'Your server is not running. Please restart the workshop app.'}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t{isRouteErrorResponse(error)\n\t\t\t\t? (statusHandlers?.[error.status] ?? defaultStatusHandler)({\n\t\t\t\t\t\terror,\n\t\t\t\t\t\tparams,\n\t\t\t\t\t})\n\t\t\t\t: unexpectedErrorHandler(error)}\n\t\t</div>\n\t)\n}\n","import { Link } from 'react-router'\nimport { Icon } from './icons.tsx'\n\nexport function ExerciseWarningBanner() {\n\treturn (\n\t\t<div className=\"border-destructive bg-destructive fixed top-0 right-0 left-0 z-50 border-b\">\n\t\t\t<div className=\"relative w-full p-4\">\n\t\t\t\t{/* Full-banner clickable link, visually hidden but covers the banner */}\n\t\t\t\t<Link\n\t\t\t\t\tto=\"/workspace-structure\"\n\t\t\t\t\tclassName=\"absolute inset-0 z-10 block h-full w-full\"\n\t\t\t\t\taria-label=\"Learn more about workspace structure\"\n\t\t\t\t/>\n\t\t\t\t<div className=\"relative z-0 container flex items-center justify-between\">\n\t\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\tname=\"Error\"\n\t\t\t\t\t\t\tclassName=\"text-destructive-foreground h-5 w-5\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<h3 className=\"text-destructive-foreground text-sm font-semibold\">\n\t\t\t\t\t\t\t\tWarning: Changes detected in exercises directory\n\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t<p className=\"text-destructive-foreground/80 text-xs\">\n\t\t\t\t\t\t\t\tYou should typically work in the playground directory, not the\n\t\t\t\t\t\t\t\texercises directory.\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"text-destructive-foreground flex items-center gap-2 text-xs\">\n\t\t\t\t\t\t<span>Learn more</span>\n\t\t\t\t\t\t<Icon name=\"ArrowRight\" className=\"h-3 w-3\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n","import * as DialogPrimitive from '@radix-ui/react-dialog'\nimport * as React from 'react'\nimport { cn } from '#app/utils/misc.tsx'\nimport { Icon } from '../icons'\n\nconst Dialog = DialogPrimitive.Root\n\nconst DialogTrigger = DialogPrimitive.Trigger\n\nconst DialogPortal = DialogPrimitive.Portal\n\nconst DialogClose = DialogPrimitive.Close\n\nfunction DialogOverlay({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n\treturn (\n\t\t<DialogPrimitive.Overlay\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t'bg-background/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 backdrop-blur-sm',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName\n\nfunction DialogContent({\n\tclassName,\n\tchildren,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Content>) {\n\treturn (\n\t\t<DialogPortal>\n\t\t\t<DialogOverlay />\n\t\t\t<DialogPrimitive.Content\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t<DialogPrimitive.Close className=\"ring-offset-background data-[state=open]:bg-accent data-[state=open]:text-muted-foreground focus:ring-ring absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none\">\n\t\t\t\t\t<Icon name=\"Close\" />\n\t\t\t\t\t<span className=\"sr-only\">Close</span>\n\t\t\t\t</DialogPrimitive.Close>\n\t\t\t</DialogPrimitive.Content>\n\t\t</DialogPortal>\n\t)\n}\nDialogContent.displayName = DialogPrimitive.Content.displayName\n\nfunction DialogHeader({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex flex-col space-y-1.5 text-center sm:text-left',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogHeader.displayName = 'DialogHeader'\n\nfunction DialogFooter({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogFooter.displayName = 'DialogFooter'\n\nfunction DialogTitle({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n\treturn (\n\t\t<DialogPrimitive.Title\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t'text-lg leading-none font-semibold tracking-tight',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogTitle.displayName = DialogPrimitive.Title.displayName\n\nfunction DialogDescription({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n\treturn (\n\t\t<DialogPrimitive.Description\n\t\t\tref={ref}\n\t\t\tclassName={cn('text-muted-foreground text-sm', className)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogDescription.displayName = DialogPrimitive.Description.displayName\n\nexport {\n\tDialog,\n\tDialogClose,\n\tDialogContent,\n\tDialogDescription,\n\tDialogFooter,\n\tDialogHeader,\n\tDialogOverlay,\n\tDialogPortal,\n\tDialogTitle,\n\tDialogTrigger,\n}\n","import * as React from 'react'\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n} from './ui/dialog'\n\ninterface KeyboardShortcut {\n\tkeys: string[]\n\tdescription: string\n}\n\ninterface ShortcutCategory {\n\ttitle: string\n\tshortcuts: KeyboardShortcut[]\n}\n\nconst shortcutCategories: ShortcutCategory[] = [\n\t{\n\t\ttitle: 'Navigation',\n\t\tshortcuts: [\n\t\t\t{ keys: ['g', 'h'], description: 'Go to home' },\n\t\t\t{\n\t\t\t\tkeys: ['g', '1-9'],\n\t\t\t\tdescription: 'Go to exercise (e.g., g+1 → /exercise/01)',\n\t\t\t},\n\t\t\t{\n\t\t\t\tkeys: ['g', '1-9', '.', '1-9'],\n\t\t\t\tdescription:\n\t\t\t\t\t'Go to exercise step (e.g., g+1+.+2 → /exercise/01/02/problem)',\n\t\t\t},\n\t\t\t{\n\t\t\t\tkeys: ['g', '1-9', '.', 'f'],\n\t\t\t\tdescription:\n\t\t\t\t\t'Go to exercise finished page (e.g., g+1+.+f → /exercise/01/finished)',\n\t\t\t},\n\t\t\t{ keys: ['g', 'p'], description: 'Go to previous step/page' },\n\t\t\t{ keys: ['g', 'n'], description: 'Go to next step/page' },\n\t\t\t{ keys: ['g', 'a'], description: 'Go to account page' },\n\t\t\t{ keys: ['g', 'd'], description: 'Go to admin page' },\n\t\t\t{ keys: ['g', 'l'], description: 'Go to last exercise solution' },\n\t\t\t{ keys: ['Escape'], description: 'Close sidebar navigation (when open)' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Playback Controls',\n\t\tshortcuts: [\n\t\t\t{ keys: ['Space', 'k'], description: 'Play/pause video' },\n\t\t\t{ keys: ['j'], description: 'Seek backward 10 seconds' },\n\t\t\t{ keys: ['l'], description: 'Seek forward 10 seconds' },\n\t\t\t{ keys: ['←'], description: 'Seek backward 10 seconds' },\n\t\t\t{ keys: ['→'], description: 'Seek forward 10 seconds' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Frame-by-Frame Navigation',\n\t\tshortcuts: [\n\t\t\t{ keys: [','], description: 'Go to previous frame (when paused)' },\n\t\t\t{ keys: ['.'], description: 'Go to next frame (when paused)' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Volume Control',\n\t\tshortcuts: [\n\t\t\t{ keys: ['↑'], description: 'Increase volume by 10%' },\n\t\t\t{ keys: ['↓'], description: 'Decrease volume by 10%' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Playback Speed',\n\t\tshortcuts: [\n\t\t\t{ keys: ['Shift', '>'], description: 'Increase playback speed' },\n\t\t\t{ keys: ['Shift', '<'], description: 'Decrease playback speed' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Fullscreen and Picture-in-Picture',\n\t\tshortcuts: [\n\t\t\t{ keys: ['f'], description: 'Toggle fullscreen mode' },\n\t\t\t{ keys: ['i'], description: 'Toggle picture-in-picture mode' },\n\t\t],\n\t},\n\t{\n\t\ttitle: 'Captions',\n\t\tshortcuts: [{ keys: ['c'], description: 'Toggle captions/subtitles' }],\n\t},\n\t{\n\t\ttitle: 'Quick Seek',\n\t\tshortcuts: [\n\t\t\t{\n\t\t\t\tkeys: ['0-9'],\n\t\t\t\tdescription:\n\t\t\t\t\t'Seek to percentage of video (0 = 0%, 1 = 10%, ..., 9 = 90%)',\n\t\t\t},\n\t\t],\n\t},\n]\n\nfunction KeyboardShortcutsDialog({\n\topen,\n\tonOpenChange,\n}: {\n\topen: boolean\n\tonOpenChange: (open: boolean) => void\n}) {\n\treturn (\n\t\t<Dialog open={open} onOpenChange={onOpenChange}>\n\t\t\t<DialogContent className=\"max-h-[80vh] max-w-2xl overflow-y-auto\">\n\t\t\t\t<DialogHeader>\n\t\t\t\t\t<DialogTitle>Keyboard Shortcuts</DialogTitle>\n\t\t\t\t\t<DialogDescription>\n\t\t\t\t\t\tUse these keyboard shortcuts to navigate and control the video\n\t\t\t\t\t\tplayer\n\t\t\t\t\t</DialogDescription>\n\t\t\t\t</DialogHeader>\n\t\t\t\t<div className=\"space-y-6\">\n\t\t\t\t\t{shortcutCategories.map((category) => (\n\t\t\t\t\t\t<div key={category.title}>\n\t\t\t\t\t\t\t<h3 className=\"text-foreground mb-3 text-sm font-semibold\">\n\t\t\t\t\t\t\t\t{category.title}\n\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t\t{category.shortcuts.map((shortcut, index) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center justify-between gap-4\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground flex-1 text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t{shortcut.description}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex shrink-0 items-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t{shortcut.keys.map((key, keyIndex) => (\n\t\t\t\t\t\t\t\t\t\t\t\t<React.Fragment key={keyIndex}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<kbd className=\"border-border bg-muted rounded border px-2 py-1 font-mono text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</kbd>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{keyIndex < shortcut.keys.length - 1 && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">+</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</React.Fragment>\n\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"border-border mt-4 border-t pt-4\">\n\t\t\t\t\t<p className=\"text-muted-foreground text-xs\">\n\t\t\t\t\t\t<strong>Note:</strong> Shortcuts are ignored when focus is on\n\t\t\t\t\t\tinteractive elements (inputs, buttons, etc.). Press{' '}\n\t\t\t\t\t\t<kbd className=\"border-border bg-muted rounded border px-1.5 py-0.5 font-mono text-xs\">\n\t\t\t\t\t\t\t?\n\t\t\t\t\t\t</kbd>{' '}\n\t\t\t\t\t\tto toggle this dialog.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t)\n}\n\nexport { KeyboardShortcutsDialog }\n","import { useEffect, useRef, useState } from 'react'\nimport { useFetchers, useNavigation } from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport const showProgressBarField = (\n\t<input type=\"hidden\" name=\"show-progress-bar\" value=\"true\" />\n)\n\nfunction EpicProgress() {\n\tconst transition = useNavigation()\n\tconst fetchers = useFetchers().filter(\n\t\t(fetcher) => fetcher.formData?.get('show-progress-bar') === 'true',\n\t)\n\tconst states = [transition.state, ...fetchers.map((f) => f.state)]\n\tconst busy = states.some((s) => s !== 'idle')\n\tconst delayedPending = useSpinDelay(busy, {\n\t\tdelay: 600,\n\t\tminDuration: 400,\n\t})\n\tconst ref = useRef<HTMLDivElement>(null)\n\tconst [animationComplete, setAnimationComplete] = useState(true)\n\n\tconst isIdle = states.every((s) => s === 'idle')\n\tconst isSubmitting = states.some((s) => s === 'submitting')\n\tconst isLoading = states.some((s) => s === 'loading')\n\n\tuseEffect(() => {\n\t\tif (!ref.current) return\n\t\tif (delayedPending) setAnimationComplete(false)\n\n\t\tconst animationPromises = ref.current\n\t\t\t.getAnimations()\n\t\t\t.map(({ finished }) => finished)\n\n\t\tvoid Promise.allSettled(animationPromises).then(() => {\n\t\t\tif (!delayedPending) setAnimationComplete(true)\n\t\t})\n\t}, [delayedPending])\n\n\treturn (\n\t\t<div\n\t\t\trole=\"progressbar\"\n\t\t\taria-hidden={delayedPending ? undefined : true}\n\t\t\taria-valuetext={delayedPending ? 'Loading' : undefined}\n\t\t\tclassName=\"fixed inset-x-0 top-0 left-0 z-50 h-[0.20rem] animate-pulse\"\n\t\t>\n\t\t\t<div\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'bg-highlight h-full w-0 duration-500 ease-in-out',\n\t\t\t\t\tisIdle &&\n\t\t\t\t\t\t(animationComplete\n\t\t\t\t\t\t\t? 'transition-none'\n\t\t\t\t\t\t\t: 'w-full opacity-0 transition-all'),\n\t\t\t\t\tdelayedPending && isSubmitting && 'w-5/12',\n\t\t\t\t\tdelayedPending && isLoading && 'w-8/12',\n\t\t\t\t)}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\nexport { EpicProgress }\n","import { useEffect } from 'react'\nimport { Toaster, toast as showToast } from 'sonner'\nimport { type Toast } from '#app/utils/toast.server.ts'\n\nexport function EpicToaster({ toast }: { toast?: Toast | null }) {\n\treturn (\n\t\t<>\n\t\t\t<Toaster closeButton position=\"top-center\" />\n\t\t\t{toast ? <ShowToast toast={toast} /> : null}\n\t\t</>\n\t)\n}\n\nfunction ShowToast({ toast }: { toast: Toast }) {\n\tconst { id, type, title, description } = toast\n\tuseEffect(() => {\n\t\tsetTimeout(() => {\n\t\t\tshowToast[type](title, { id, description })\n\t\t}, 0)\n\t}, [description, id, title, type])\n\treturn null\n}\n","import * as TooltipPrimitive from '@radix-ui/react-tooltip'\nimport * as React from 'react'\n\nimport { cn } from '#app/utils/misc.tsx'\n\nconst TooltipProvider = TooltipPrimitive.Provider\n\nconst Tooltip = TooltipPrimitive.Root\n\nconst TooltipTrigger = TooltipPrimitive.Trigger\n\nfunction TooltipContent({\n\tclassName,\n\tsideOffset = 4,\n\tref,\n\t...props\n}: React.ComponentProps<typeof TooltipPrimitive.Content>) {\n\treturn (\n\t\t<TooltipPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t'bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md border px-3 py-1.5 text-sm shadow-md',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport function SimpleTooltip({\n\tcontent,\n\tchildren,\n}: {\n\tcontent: React.ReactNode\n\tchildren: React.ReactNode\n}) {\n\tif (!content) return children\n\treturn (\n\t\t<Tooltip>\n\t\t\t<TooltipTrigger asChild>{children}</TooltipTrigger>\n\t\t\t<TooltipContent>{content}</TooltipContent>\n\t\t</Tooltip>\n\t)\n}\n\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }\n","import { type checkForUpdatesCached } from '@epic-web/workshop-utils/git.server'\nimport { useEffect, useRef } from 'react'\nimport { useFetcher } from 'react-router'\nimport { toast } from 'sonner'\nimport { z } from 'zod'\n\nexport function UpdateToast({\n\trepoUpdates,\n}: {\n\trepoUpdates: Awaited<ReturnType<typeof checkForUpdatesCached>>\n}) {\n\tconst { updatesAvailable } = repoUpdates\n\tconst diffLink = 'diffLink' in repoUpdates ? repoUpdates.diffLink : null\n\tconst remoteCommit =\n\t\t'remoteCommit' in repoUpdates ? repoUpdates.remoteCommit : undefined\n\tconst fetcher = useFetcher()\n\tconst fetcherRef = useRef(fetcher)\n\tuseEffect(() => {\n\t\tfetcherRef.current = fetcher\n\t}, [fetcher])\n\n\t// Track the in-progress toast id and update notification id\n\tconst inProgressToastId = useRef<ReturnType<typeof toast.loading> | null>(\n\t\tnull,\n\t)\n\tconst updateNotificationId = useRef<ReturnType<typeof toast.info> | null>(\n\t\tnull,\n\t)\n\tconst updateInProgress = useRef(false)\n\n\tuseEffect(() => {\n\t\tif (updatesAvailable && remoteCommit) {\n\t\t\tconst id = toast.info('New workshop updates available', {\n\t\t\t\tduration: Infinity,\n\t\t\t\tdescription: (\n\t\t\t\t\t<div>\n\t\t\t\t\t\t{`Get the latest updates by clicking the update button. `}\n\t\t\t\t\t\t{diffLink ? (\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={diffLink}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName=\"text-xs underline\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tView changes\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t),\n\t\t\t\tonDismiss: () => {\n\t\t\t\t\t// No-op for now, could call a dismiss endpoint if needed\n\t\t\t\t},\n\t\t\t\taction: {\n\t\t\t\t\tlabel: 'Update',\n\t\t\t\t\tonClick: async () => {\n\t\t\t\t\t\t// Dismiss the update notification immediately\n\t\t\t\t\t\tif (updateNotificationId.current) {\n\t\t\t\t\t\t\ttoast.dismiss(updateNotificationId.current)\n\t\t\t\t\t\t\tupdateNotificationId.current = null\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Show in-progress toast\n\t\t\t\t\t\tif (!inProgressToastId.current) {\n\t\t\t\t\t\t\tinProgressToastId.current = toast.loading('Update in progress...')\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (updateInProgress.current) return\n\t\t\t\t\t\tupdateInProgress.current = true\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst { EPICSHOP_PARENT_PORT, EPICSHOP_PARENT_TOKEN } =\n\t\t\t\t\t\t\t\twindow.ENV || {}\n\t\t\t\t\t\t\tif (!EPICSHOP_PARENT_PORT || !EPICSHOP_PARENT_TOKEN) {\n\t\t\t\t\t\t\t\tthrow new Error('Update API not available')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst res = await fetch(\n\t\t\t\t\t\t\t\t`http://localhost:${EPICSHOP_PARENT_PORT}/__epicshop-restart`,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\t\t\t'x-epicshop-token': EPICSHOP_PARENT_TOKEN,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tif (!res.ok) {\n\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t`Request to update workshop failed: ${res.statusText}`,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst data = await res.json().catch(() => ({}))\n\t\t\t\t\t\t\tconst schema = z.object({\n\t\t\t\t\t\t\t\tstatus: z.enum(['ok', 'error']),\n\t\t\t\t\t\t\t\tmessage: z.string().optional(),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tconst parsed = schema.safeParse(data)\n\t\t\t\t\t\t\tif (!parsed.success) {\n\t\t\t\t\t\t\t\tconsole.error('Invalid response from update API', data)\n\t\t\t\t\t\t\t\tthrow new Error('Invalid response from update API')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst { status, message } = parsed.data\n\t\t\t\t\t\t\tif (status === 'ok') {\n\t\t\t\t\t\t\t\tlet reloaded = false\n\t\t\t\t\t\t\t\ttoast.success('Workshop updated', {\n\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t'Reloading in 2 seconds... You can reload now if you prefer.',\n\t\t\t\t\t\t\t\t\tduration: 2000,\n\t\t\t\t\t\t\t\t\taction: {\n\t\t\t\t\t\t\t\t\t\tlabel: 'Reload now',\n\t\t\t\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\t\t\t\treloaded = true\n\t\t\t\t\t\t\t\t\t\t\twindow.location.reload()\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tonAutoClose: () => {\n\t\t\t\t\t\t\t\t\t\tif (!reloaded) {\n\t\t\t\t\t\t\t\t\t\t\twindow.location.reload()\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ttoast.error('Failed to update workshop', {\n\t\t\t\t\t\t\t\t\tdescription: message || 'Unknown error',\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\ttoast.error('Failed to update workshop', {\n\t\t\t\t\t\t\t\tdescription: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tupdateInProgress.current = false\n\t\t\t\t\t\t\tif (inProgressToastId.current) {\n\t\t\t\t\t\t\t\ttoast.dismiss(inProgressToastId.current)\n\t\t\t\t\t\t\t\tinProgressToastId.current = null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tcancel: {\n\t\t\t\t\tlabel: 'Dismiss',\n\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t// Dismiss the notification toast\n\t\t\t\t\t\tif (updateNotificationId.current) {\n\t\t\t\t\t\t\ttoast.dismiss(updateNotificationId.current)\n\t\t\t\t\t\t\tupdateNotificationId.current = null\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Mute the notification persistently\n\t\t\t\t\t\tvoid fetcherRef.current.submit(\n\t\t\t\t\t\t\t{ intent: 'mute', id: `update-repo-${remoteCommit}` },\n\t\t\t\t\t\t\t{ method: 'post', action: '/admin/notifications' },\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t\tupdateNotificationId.current = id\n\t\t}\n\t}, [updatesAvailable, diffLink, remoteCommit])\n\n\treturn null\n}\n","import { muteNotification } from '@epic-web/workshop-utils/db.server'\nimport { type getUnmutedNotifications } from '@epic-web/workshop-utils/notifications.server'\nimport { useEffect, useRef } from 'react'\nimport { data, type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { toast } from 'sonner'\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tconst id = formData.get('id')\n\tif (typeof id !== 'string') {\n\t\treturn data({ error: 'Invalid notification id' }, { status: 400 })\n\t}\n\tif (intent === 'mute') {\n\t\tawait muteNotification(id)\n\t\treturn data({ success: true })\n\t}\n\treturn data({ error: 'Invalid intent' }, { status: 400 })\n}\n\nexport function Notifications({\n\tunmutedNotifications,\n}: {\n\tunmutedNotifications: Awaited<ReturnType<typeof getUnmutedNotifications>>\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst fetcherRef = useRef(fetcher)\n\tconst toastedIds = useRef<Set<string>>(new Set())\n\n\tuseEffect(() => {\n\t\tfor (const notification of unmutedNotifications) {\n\t\t\tif (toastedIds.current.has(notification.id)) continue\n\t\t\ttoastedIds.current.add(notification.id)\n\n\t\t\ttoast.info(notification.title, {\n\t\t\t\tid: notification.id,\n\t\t\t\tdescription: (\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<p>{notification.message}</p>\n\t\t\t\t\t\t{notification.link && (\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={notification.link}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\tclassName=\"text-xs underline\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tLearn more\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t),\n\t\t\t\tduration: Infinity,\n\t\t\t\taction: {\n\t\t\t\t\tlabel: 'Dismiss',\n\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\tvoid fetcherRef.current.submit(\n\t\t\t\t\t\t\t{ intent: 'mute', id: notification.id },\n\t\t\t\t\t\t\t{ method: 'post', action: '/admin/notifications' },\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}, [unmutedNotifications])\n\n\treturn null\n}\n","import { invariant } from '@epic-web/invariant'\nimport { unstable_useRoute as useRoute } from 'react-router'\nimport { type Route } from '../+types/root.tsx'\n\n/**\n * @returns the loader data from the root loader\n * @throws if the loader data is null\n */\nexport function useRootLoaderData() {\n\tconst route = useRoute('root')\n\tinvariant(\n\t\troute.loaderData,\n\t\t`useRootLoaderData: useRoute('root') loaderData returned null. This can happen if there was an error in the root loader. In this case, the error boundary to should render and we cannot use useRootLoaderData.`,\n\t)\n\treturn route.loaderData\n}\n\n/**\n * @returns the request info from the root loader\n */\nexport function useRequestInfo() {\n\tconst route = useRootLoaderData()\n\treturn route.requestInfo\n}\n\nexport function useApps() {\n\tconst data = useRootLoaderData()\n\treturn data.apps\n}\n\nexport function getRootMatchLoaderData(\n\tmatches: Array<{ id: string; loaderData: unknown } | undefined>,\n) {\n\treturn matches.find((m) => m?.id === 'root')?.loaderData as\n\t\t| Route.ComponentProps['loaderData']\n\t\t| undefined\n}\n","/**\n * This file contains utilities for using client hints for user preference which\n * are needed by the server, but are only known by the browser.\n */\nimport { getHintUtils } from '@epic-web/client-hints'\nimport {\n\tclientHint as colorSchemeHint,\n\tsubscribeToSchemeChange,\n} from '@epic-web/client-hints/color-scheme'\nimport {\n\tclientHint as reducedMotionHint,\n\tsubscribeToMotionChange,\n} from '@epic-web/client-hints/reduced-motion'\nimport { clientHint as timeZoneHint } from '@epic-web/client-hints/time-zone'\nimport * as React from 'react'\nimport { useRevalidator } from 'react-router'\nimport { useRequestInfo } from './root-loader.ts'\n\nconst themeCookieName = 'EpicShop_CH-prefers-color-scheme'\nconst motionCookieName = 'EpicShop_CH-reduced-motion'\nconst hintsUtils = getHintUtils({\n\ttheme: {\n\t\t...colorSchemeHint,\n\t\tcookieName: themeCookieName,\n\t},\n\ttimeZone: {\n\t\t...timeZoneHint,\n\t\tcookieName: 'EpicShop_CH-time-zone',\n\t},\n\treducedMotion: {\n\t\t...reducedMotionHint,\n\t\tcookieName: motionCookieName,\n\t},\n\t// add other hints here\n})\n\nexport const { getHints } = hintsUtils\n\n/**\n * @returns an object with the client hints and their values\n */\nexport function useHints() {\n\tconst requestInfo = useRequestInfo()\n\treturn requestInfo.hints\n}\n\n/**\n * @returns inline script element that checks for client hints and sets cookies\n * if they are not set then reloads the page if any cookie was set to an\n * inaccurate value.\n */\nexport function ClientHintCheck() {\n\tconst { revalidate } = useRevalidator()\n\tReact.useEffect(\n\t\t() => subscribeToSchemeChange(() => revalidate(), themeCookieName),\n\t\t[revalidate],\n\t)\n\tReact.useEffect(\n\t\t() => subscribeToMotionChange(() => revalidate(), motionCookieName),\n\t\t[revalidate],\n\t)\n\n\treturn (\n\t\t<script\n\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t__html: hintsUtils.getClientHintCheckScript(),\n\t\t\t}}\n\t\t/>\n\t)\n}\n","export type ListOfErrors = Array<string | null | undefined> | null | undefined\n\nexport function ErrorList({\n\tid,\n\terrors,\n}: {\n\terrors?: ListOfErrors\n\tid?: string\n}) {\n\tconst errorsToRender = errors?.filter(Boolean)\n\tif (!errorsToRender?.length) return null\n\treturn (\n\t\t<ul id={id} className=\"space-y-1\">\n\t\t\t{errorsToRender.map((e) => (\n\t\t\t\t<li key={e} className=\"text-foreground-destructive text-[10px]\">\n\t\t\t\t\t{e}\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t)\n}\n","// This is a progressive enhancement utility to ensure that the user is redirected\n// to the page they are on if the JavaScript hasn't had a chance to hydrate yet.\n// I think when Remix has middleware, this will be easier to do automatically.\n\nimport { data, redirect, useLocation } from 'react-router'\nimport { safeRedirect } from 'remix-utils/safe-redirect'\nimport { ServerOnly } from 'remix-utils/server-only'\n\nconst PE_REDIRECT_INPUT_NAME = '__PE_redirectTo'\n\nexport function usePERedirectInput() {\n\tconst location = useLocation()\n\treturn (\n\t\t<ServerOnly>\n\t\t\t{() => (\n\t\t\t\t<input\n\t\t\t\t\ttype=\"hidden\"\n\t\t\t\t\tname={PE_REDIRECT_INPUT_NAME}\n\t\t\t\t\tvalue={location.pathname}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</ServerOnly>\n\t)\n}\n\nexport function ensureProgressiveEnhancement(\n\trequest: Request,\n\tformData: FormData,\n\tresponseInit?: () => Parameters<typeof redirect>[1],\n) {\n\tconst redirectTo = formData.get(PE_REDIRECT_INPUT_NAME)\n\tif (typeof redirectTo === 'string') {\n\t\tthrow redirect(safeRedirect(redirectTo), responseInit?.())\n\t}\n\n\t// if request does not accept application/json, it means JS hasn't hydrated yet\n\tif (!acceptsJson(request)) {\n\t\tconst redirectToReferrer = request.headers.get('Referer') ?? '/'\n\t\tthrow redirect(safeRedirect(redirectToReferrer), responseInit?.())\n\t}\n}\n\nfunction acceptsJson(request: Request) {\n\tconst accept = request.headers.get('Accept') ?? ''\n\treturn (\n\t\taccept.includes('application/json') ||\n\t\taccept.includes('*/*') ||\n\t\taccept.includes('application/*') ||\n\t\taccept.includes('*/json')\n\t)\n}\n\nexport function dataWithPE<Data>(\n\trequest: Request,\n\tformData: FormData,\n\t...args: Parameters<typeof data<Data>>\n) {\n\tensureProgressiveEnhancement(request, formData, () => ({\n\t\tstatusText: JSON.stringify(args[0]),\n\t\t...(typeof args[1] === 'number' ? { status: args[1] } : args[1]),\n\t}))\n\treturn data(...args)\n}\n","import * as cookie from 'cookie'\n\nconst cookieName = 'EpicShop_theme'\nexport type Theme = 'light' | 'dark'\n\nexport function getTheme(request: Request): Theme | null {\n\tconst cookieHeader = request.headers.get('cookie')\n\tconst parsed = cookieHeader ? cookie.parse(cookieHeader)[cookieName] : null\n\tif (parsed === 'light' || parsed === 'dark') return parsed\n\treturn null\n}\n\nexport function setTheme(theme: Theme | 'system') {\n\treturn cookie.serialize(cookieName, theme, {\n\t\tpath: '/',\n\t\tmaxAge: theme === 'system' ? 0 : 60 * 60 * 365 * 100,\n\t})\n}\n","import { getFormProps, useForm } from '@conform-to/react'\nimport { parseWithZod } from '@conform-to/zod'\nimport { data, redirect, useFetcher, useFetchers } from 'react-router'\nimport { safeRedirect } from 'remix-utils/safe-redirect'\nimport { z } from 'zod'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { useHints } from '#app/utils/client-hints.tsx'\nimport { ErrorList } from '#app/utils/forms.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { type Route } from './+types/index.tsx'\nimport { setTheme } from './theme-session.server.ts'\n\nconst ROUTE_PATH = '/theme'\n\nconst ThemeFormSchema = z.object({\n\ttheme: z.enum(['system', 'light', 'dark']),\n})\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst referrer = request.headers.get('Referer')\n\treturn redirect(safeRedirect(referrer ?? '/'), {\n\t\theaders: { 'Cache-Control': 'no-cache' },\n\t})\n}\n\nexport async function action({ request }: Route.ActionArgs) {\n\tconst formData = await request.formData()\n\tconst submission = parseWithZod(formData, {\n\t\tschema: ThemeFormSchema,\n\t})\n\tif (submission.status !== 'success') {\n\t\treturn data(submission.reply(), {\n\t\t\t// You can also use the status to determine the HTTP status code\n\t\t\tstatus: submission.status === 'error' ? 400 : 200,\n\t\t})\n\t}\n\tconst { theme } = submission.value\n\n\tconst responseInit = {\n\t\theaders: { 'set-cookie': setTheme(theme) },\n\t}\n\treturn dataWithPE(request, formData, submission.reply(), responseInit)\n}\n\nexport function ThemeSwitch() {\n\tconst requestInfo = useRequestInfo()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst fetcher = useFetcher<Route.ComponentProps['actionData']>()\n\n\tconst [form] = useForm({\n\t\tlastResult: fetcher.data,\n\t\tonValidate({ formData }) {\n\t\t\treturn parseWithZod(formData, { schema: ThemeFormSchema })\n\t\t},\n\t})\n\n\tconst mode = requestInfo.session.theme ?? 'system'\n\tconst nextMode =\n\t\tmode === 'system' ? 'light' : mode === 'light' ? 'dark' : 'system'\n\tconst modeLabel = {\n\t\tlight: <Icon size=\"md\" name=\"Sun\" title=\"Light mode\" />,\n\t\tdark: <Icon size=\"md\" name=\"Moon\" title=\"Dark mode\" />,\n\t\tsystem: <Icon size=\"md\" name=\"Laptop\" title=\"System mode\" />,\n\t}\n\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action={ROUTE_PATH} {...getFormProps(form)}>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t{peRedirectInput}\n\t\t\t\t<input type=\"hidden\" name=\"theme\" value={nextMode} />\n\t\t\t\t<SimpleTooltip content={`Change theme from ${mode} mode`}>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\tvalue=\"update-theme\"\n\t\t\t\t\t\tclassName=\"flex h-8 w-8 cursor-pointer items-center justify-center\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{modeLabel[mode]}\n\t\t\t\t\t</button>\n\t\t\t\t</SimpleTooltip>\n\t\t\t</div>\n\t\t\t<ErrorList errors={form.errors} id={form.errorId} />\n\t\t</fetcher.Form>\n\t)\n}\n\n/**\n * @returns the user's theme preference, or the client hint theme if the user\n * has not set a preference.\n */\nexport function useTheme() {\n\tconst hints = useHints()\n\tconst requestInfo = useRequestInfo()\n\tconst fetchers = useFetchers()\n\tconst fetcher = fetchers.find(\n\t\t(f) => f.formData?.get('intent') === 'update-theme',\n\t)\n\tconst optimisticTheme = fetcher?.formData?.get('theme')\n\tif (optimisticTheme === 'system') return hints.theme\n\tif (optimisticTheme === 'light' || optimisticTheme === 'dark') {\n\t\treturn optimisticTheme\n\t}\n\treturn requestInfo.session.theme ?? hints.theme\n}\n","import \"/home/runner/work/epicshop/epicshop/packages/workshop-app/app/styles/app.css?transform-only\";export default \"__VITE_CSS_URL__2f686f6d652f72756e6e65722f776f726b2f6570696373686f702f6570696373686f702f7061636b616765732f776f726b73686f702d6170702f6170702f7374796c65732f6170702e6373733f7472616e73666f726d2d6f6e6c79__\"","import \"/home/runner/work/epicshop/epicshop/packages/workshop-app/app/styles/tailwind.css?transform-only\";export default \"__VITE_CSS_URL__2f686f6d652f72756e6e65722f776f726b2f6570696373686f702f6570696373686f702f7061636b616765732f776f726b73686f702d6170702f6170702f7374796c65732f7461696c77696e642e6373733f7472616e73666f726d2d6f6e6c79__\"","import * as cookie from 'cookie'\nimport { redirect } from 'react-router'\nimport { combineHeaders } from './misc.tsx'\n\nconst cookieName = 'EpicShop_confetti'\n\nexport function getConfetti(request: Request) {\n\tconst cookieHeader = request.headers.get('cookie')\n\tconst confettiId = cookieHeader\n\t\t? cookie.parse(cookieHeader)[cookieName]\n\t\t: null\n\treturn {\n\t\tconfettiId,\n\t\theaders: confettiId ? createConfettiHeaders(null) : null,\n\t}\n}\n\n/**\n * This defaults the value to something reasonable if you want to show confetti.\n * If you want to clear the cookie, pass null and it will make a set-cookie\n * header that will delete the cookie\n *\n * @param value the value for the cookie in the set-cookie header\n * @returns Headers with a set-cookie header set to the value\n */\nexport function createConfettiHeaders(\n\tvalue: string | null = String(Date.now()),\n) {\n\treturn new Headers({\n\t\t'set-cookie': cookie.serialize(cookieName, value ? value : '', {\n\t\t\tpath: '/',\n\t\t\tmaxAge: value ? 60 : -1,\n\t\t}),\n\t})\n}\n\nexport async function redirectWithConfetti(url: string, init?: ResponseInit) {\n\treturn redirect(url, {\n\t\t...init,\n\t\theaders: combineHeaders(init?.headers, createConfettiHeaders()),\n\t})\n}\n","import { useSyncExternalStore } from 'react'\nimport { useRequestInfo } from './root-loader.ts'\n\nfunction getSnapshot() {\n\treturn window.navigator.onLine\n}\n\nfunction subscribe(callback: () => void) {\n\twindow.addEventListener('online', callback)\n\twindow.addEventListener('offline', callback)\n\treturn () => {\n\t\twindow.removeEventListener('online', callback)\n\t\twindow.removeEventListener('offline', callback)\n\t}\n}\n\nexport function useIsOnline() {\n\tconst requestInfo = useRequestInfo()\n\treturn useSyncExternalStore(subscribe, getSnapshot, () => requestInfo.online)\n}\n","import {\n\tMessageSchema,\n\tpartykitBaseUrl,\n\tpartykitRoom,\n\ttype Message,\n\ttype User,\n} from '@epic-web/workshop-presence/presence'\nimport { usePartySocket } from 'partysocket/react'\nimport {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport { useParams } from 'react-router'\nimport { z } from 'zod'\nimport { useIsOnline } from './online.ts'\nimport { useRequestInfo, useRootLoaderData } from './root-loader.ts'\n\nexport * from '@epic-web/workshop-presence/presence'\n\nconst PresenceContext = createContext<ReturnType<\n\ttypeof usePresenceSocket\n> | null>(null)\n\nexport function usePresencePreferences() {\n\tconst data = useRootLoaderData()\n\treturn data?.preferences?.presence ?? null\n}\n\nexport function useOptionalWorkshopTitle() {\n\tconst data = useRootLoaderData()\n\treturn data?.workshopTitle ?? null\n}\n\nconst ExerciseAppParamsSchema = z.object({\n\ttype: z.union([z.literal('problem'), z.literal('solution')]).optional(),\n\texerciseNumber: z.coerce.number().finite(),\n\tstepNumber: z.coerce.number().finite().optional(),\n})\n\n/**\n * useFirstCallDelayedCallback\n *\n * This hook creates a callback that is delayed on its first call.\n * It's useful for scenarios where you want to delay the execution of a function\n * for a certain amount of time, but only on the initial call.\n *\n * If it's called again before the delay expires, then the prior call is ignored\n * and when the delay expires, the latest call is executed.\n *\n * The motivation here is that the server may get one set of presence and by the\n * time it shows up on the client it's stale. This delays the re-rendering of\n * the UI to avoid a flicker as soon as you land on the page.\n *\n * @param cb The callback function to be delayed\n * @param delay The delay in milliseconds before the callback is executed\n * @returns A new function that wraps the original callback with the delay logic\n */\nfunction useFirstCallDelayedCallback<Args extends unknown[]>(\n\tcb: (...args: Args) => void,\n\tdelay: number,\n) {\n\tconst [timedPromise] = useState(\n\t\t() => new Promise((resolve) => setTimeout(resolve, delay)),\n\t)\n\tconst mounted = useRef(true)\n\tconst currentCallRef = useRef<symbol | null>(null)\n\tconst lastCbRef = useRef(cb)\n\n\tuseEffect(() => {\n\t\tlastCbRef.current = cb\n\t}, [cb])\n\n\tconst delayedCb = useCallback(\n\t\t(...args: Args) => {\n\t\t\tconst thisOne = Symbol()\n\t\t\tcurrentCallRef.current = thisOne\n\t\t\tvoid timedPromise.then(() => {\n\t\t\t\tif (!mounted.current) return\n\t\t\t\tif (currentCallRef.current !== thisOne) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tlastCbRef.current(...args)\n\t\t\t})\n\t\t},\n\t\t[timedPromise],\n\t)\n\n\treturn delayedCb\n}\n\nfunction useProductHost() {\n\tconst data = useRootLoaderData()\n\treturn data?.workshopConfig?.product?.host ?? null\n}\n\nfunction useLoggedInProductHosts() {\n\tconst data = useRootLoaderData()\n\treturn data?.loggedInProductHosts ?? []\n}\n\nfunction useUsersLocation() {\n\tconst workshopTitle = useOptionalWorkshopTitle()\n\tconst requestInfo = useRequestInfo()\n\tconst productHost = useProductHost()\n\tconst rawParams = useParams()\n\tconst paramsResult = ExerciseAppParamsSchema.safeParse(rawParams)\n\tconst params = paramsResult.success ? paramsResult.data : null\n\tconst { ENV, repoUpdates } = useRootLoaderData() ?? {}\n\n\t// Extract epicshopVersion and repoStatus from root loader data\n\tconst epicshopVersion = ENV?.EPICSHOP_APP_VERSION ?? null\n\tconst repoStatus =\n\t\trepoUpdates && 'updatesAvailable' in repoUpdates ? { ...repoUpdates } : null\n\n\treturn {\n\t\tworkshopTitle,\n\t\torigin: requestInfo.origin,\n\t\tproductHost,\n\t\tepicshopVersion,\n\t\trepoStatus,\n\t\t...(params\n\t\t\t? {\n\t\t\t\t\texercise: {\n\t\t\t\t\t\ttype: params.type,\n\t\t\t\t\t\texerciseNumber: params.exerciseNumber,\n\t\t\t\t\t\tstepNumber: params.stepNumber,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: null),\n\t} satisfies User['location']\n}\n\nfunction usePresenceSocket(user?: User | null) {\n\tconst prefs = usePresencePreferences()\n\tconst { userId, presence, userHasAccess } = useRootLoaderData() ?? {}\n\tconst [users, setUsers] = useState(presence?.users ?? [])\n\tconst usersLocation = useUsersLocation()\n\tconst loggedInProductHosts = useLoggedInProductHosts()\n\n\tconst handleMessage = useFirstCallDelayedCallback((evt: MessageEvent) => {\n\t\tconst messageResult = MessageSchema.safeParse(JSON.parse(String(evt.data)))\n\t\tif (!messageResult.success) return\n\t\tif (messageResult.data.type === 'presence') {\n\t\t\tsetUsers(messageResult.data.payload.users)\n\t\t}\n\t}, 2000)\n\n\tconst socket = usePartySocket({\n\t\thost: new URL(partykitBaseUrl).host,\n\t\troom: partykitRoom,\n\t\tonMessage: handleMessage,\n\t})\n\n\t// Find the current user in presence.users (includes epicshopVersion, repoStatus, etc.)\n\tconst currentUserId = user?.id ?? userId?.id\n\tconst currentUserFromPresence = currentUserId\n\t\t? presence?.users?.find((u) => u.id === currentUserId)\n\t\t: null\n\n\t// Use the user data from presence.users as the base (has epicshopVersion, repoStatus, etc.)\n\t// Merge with user prop if provided, then override with dynamic fields\n\tconst baseUser = currentUserFromPresence ?? user ?? {}\n\n\tlet message: Message | null = null\n\tif (currentUserId) {\n\t\tif (prefs?.optOut) {\n\t\t\t// Send opt-out user with minimal info instead of removing entirely\n\t\t\tmessage = {\n\t\t\t\ttype: 'add-user',\n\t\t\t\tpayload: {\n\t\t\t\t\t...baseUser,\n\t\t\t\t\tid: currentUserId,\n\t\t\t\t\thasAccess: userHasAccess,\n\t\t\t\t\toptOut: true,\n\t\t\t\t\tloggedInProductHosts,\n\t\t\t\t\tlocation: usersLocation,\n\t\t\t\t},\n\t\t\t}\n\t\t} else {\n\t\t\t// Use the user data as-is, only update dynamic fields\n\t\t\tmessage = {\n\t\t\t\ttype: 'add-user',\n\t\t\t\tpayload: {\n\t\t\t\t\t...baseUser,\n\t\t\t\t\tid: currentUserId,\n\t\t\t\t\thasAccess: userHasAccess,\n\t\t\t\t\tlocation: usersLocation,\n\t\t\t\t\tloggedInProductHosts,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t}\n\n\tconst messageJson = message ? JSON.stringify(message) : null\n\tuseEffect(() => {\n\t\tif (messageJson) socket.send(messageJson)\n\t}, [messageJson, socket])\n\n\tconst scoredUsers = scoreUsers(\n\t\t{ id: userId?.id, location: usersLocation },\n\t\tusers,\n\t)\n\n\treturn { users: scoredUsers }\n}\n\n/**\n * Get all locations for a user (from locations array or falling back to location)\n */\nfunction getUserLocations(user: User): Array<NonNullable<User['location']>> {\n\tif (user.locations && user.locations.length > 0) {\n\t\treturn user.locations.filter(Boolean) as Array<\n\t\t\tNonNullable<User['location']>\n\t\t>\n\t}\n\tif (user.location) {\n\t\treturn [user.location]\n\t}\n\treturn []\n}\n\n/**\n * Sorts and scores users based on proximity to the current user.\n *\n * Sorting order:\n * 1. Self first\n * 2. Same exercise step (exerciseNumber + stepNumber + type)\n * 3. Same exercise (exerciseNumber)\n * 4. Same workshop (workshopTitle)\n * 5. Same product host\n * 6. Most products logged into\n * 7. Opted-out users last\n */\nfunction scoreUsers(\n\tcurrentUser: { id?: string | null; location: User['location'] },\n\tusers: Array<User>,\n) {\n\tconst { location } = currentUser\n\n\tconst scoredUsers = users.map((user) => {\n\t\t// Calculate score for visual styling (0-1)\n\t\t// Higher score = closer proximity = more prominent display\n\t\tlet score = 0\n\n\t\t// Opted-out users get no score for visual purposes\n\t\tif (user.optOut) {\n\t\t\treturn { user, score: 0 }\n\t\t}\n\n\t\tconst userLocations = getUserLocations(user)\n\n\t\t// Check if any of the user's locations match the current user's location\n\t\tfor (const userLoc of userLocations) {\n\t\t\t// Same workshop title\n\t\t\tif (\n\t\t\t\tlocation?.workshopTitle &&\n\t\t\t\tlocation.workshopTitle === userLoc.workshopTitle\n\t\t\t) {\n\t\t\t\tscore = Math.max(score, 0.4)\n\n\t\t\t\t// Same exercise\n\t\t\t\tif (\n\t\t\t\t\tlocation.exercise?.exerciseNumber != null &&\n\t\t\t\t\tlocation.exercise.exerciseNumber === userLoc.exercise?.exerciseNumber\n\t\t\t\t) {\n\t\t\t\t\tscore = Math.max(score, 0.6)\n\n\t\t\t\t\t// Same step\n\t\t\t\t\tif (\n\t\t\t\t\t\tlocation.exercise.stepNumber != null &&\n\t\t\t\t\t\tlocation.exercise.stepNumber === userLoc.exercise?.stepNumber\n\t\t\t\t\t) {\n\t\t\t\t\t\tscore = Math.max(score, 0.8)\n\n\t\t\t\t\t\t// Same type (problem/solution)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tlocation.exercise.type &&\n\t\t\t\t\t\t\tlocation.exercise.type === userLoc.exercise?.type\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tscore = 1\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tlocation?.productHost &&\n\t\t\t\tlocation.productHost === userLoc.productHost\n\t\t\t) {\n\t\t\t\t// Same product host but different workshop\n\t\t\t\tscore = Math.max(score, 0.2)\n\t\t\t}\n\t\t}\n\n\t\treturn { user, score }\n\t})\n\n\treturn scoredUsers.sort((a, b) => {\n\t\t// Self always first\n\t\tif (a.user.id === currentUser.id) return -1\n\t\tif (b.user.id === currentUser.id) return 1\n\n\t\t// Opted-out users always last\n\t\tif (a.user.optOut && !b.user.optOut) return 1\n\t\tif (!a.user.optOut && b.user.optOut) return -1\n\n\t\t// Same step (exerciseNumber + stepNumber + type match)\n\t\tconst aOnSameStep = userHasSameStep(location, a.user)\n\t\tconst bOnSameStep = userHasSameStep(location, b.user)\n\t\tif (aOnSameStep && !bOnSameStep) return -1\n\t\tif (!aOnSameStep && bOnSameStep) return 1\n\n\t\t// Same exercise (exerciseNumber match)\n\t\tconst aOnSameExercise = userHasSameExercise(location, a.user)\n\t\tconst bOnSameExercise = userHasSameExercise(location, b.user)\n\t\tif (aOnSameExercise && !bOnSameExercise) return -1\n\t\tif (!aOnSameExercise && bOnSameExercise) return 1\n\n\t\t// Same workshop\n\t\tconst aOnSameWorkshop = userHasSameWorkshop(location, a.user)\n\t\tconst bOnSameWorkshop = userHasSameWorkshop(location, b.user)\n\t\tif (aOnSameWorkshop && !bOnSameWorkshop) return -1\n\t\tif (!aOnSameWorkshop && bOnSameWorkshop) return 1\n\n\t\t// Same product host\n\t\tconst aOnSameProductHost = userHasSameProductHost(location, a.user)\n\t\tconst bOnSameProductHost = userHasSameProductHost(location, b.user)\n\t\tif (aOnSameProductHost && !bOnSameProductHost) return -1\n\t\tif (!aOnSameProductHost && bOnSameProductHost) return 1\n\n\t\t// Most products logged into\n\t\tconst aProductCount = a.user.loggedInProductHosts?.length ?? 0\n\t\tconst bProductCount = b.user.loggedInProductHosts?.length ?? 0\n\t\tif (aProductCount !== bProductCount) {\n\t\t\treturn bProductCount - aProductCount\n\t\t}\n\n\t\treturn 0\n\t})\n}\n\nfunction userHasSameStep(\n\tcurrentLocation: User['location'],\n\tuser: User,\n): boolean {\n\tif (!currentLocation?.exercise) return false\n\tconst userLocations = getUserLocations(user)\n\treturn userLocations.some(\n\t\t(loc) =>\n\t\t\tloc.workshopTitle === currentLocation.workshopTitle &&\n\t\t\tloc.exercise?.exerciseNumber ===\n\t\t\t\tcurrentLocation.exercise?.exerciseNumber &&\n\t\t\tloc.exercise?.stepNumber === currentLocation.exercise?.stepNumber &&\n\t\t\tloc.exercise?.type === currentLocation.exercise?.type,\n\t)\n}\n\nfunction userHasSameExercise(\n\tcurrentLocation: User['location'],\n\tuser: User,\n): boolean {\n\tif (!currentLocation?.exercise?.exerciseNumber) return false\n\tconst userLocations = getUserLocations(user)\n\treturn userLocations.some(\n\t\t(loc) =>\n\t\t\tloc.workshopTitle === currentLocation.workshopTitle &&\n\t\t\tloc.exercise?.exerciseNumber === currentLocation.exercise?.exerciseNumber,\n\t)\n}\n\nfunction userHasSameWorkshop(\n\tcurrentLocation: User['location'],\n\tuser: User,\n): boolean {\n\tif (!currentLocation?.workshopTitle) return false\n\tconst userLocations = getUserLocations(user)\n\treturn userLocations.some(\n\t\t(loc) => loc.workshopTitle === currentLocation.workshopTitle,\n\t)\n}\n\nfunction userHasSameProductHost(\n\tcurrentLocation: User['location'],\n\tuser: User,\n): boolean {\n\tif (!currentLocation?.productHost) return false\n\tconst userLocations = getUserLocations(user)\n\treturn userLocations.some(\n\t\t(loc) => loc.productHost === currentLocation.productHost,\n\t)\n}\n\nfunction PresenceOnline({\n\tuser,\n\tchildren,\n}: {\n\tuser?: User | null\n\tchildren: React.ReactNode\n}) {\n\treturn (\n\t\t<PresenceContext.Provider value={usePresenceSocket(user)}>\n\t\t\t{children}\n\t\t</PresenceContext.Provider>\n\t)\n}\n\nfunction PresenceOffline({\n\tuser,\n\tchildren,\n}: {\n\tuser?: User | null\n\tchildren: React.ReactNode\n}) {\n\tconst usersLocation = useUsersLocation()\n\tconst { presence } = useRootLoaderData() ?? {}\n\treturn (\n\t\t<PresenceContext.Provider\n\t\t\tvalue={{\n\t\t\t\tusers: scoreUsers(\n\t\t\t\t\t{ id: user?.id, location: usersLocation },\n\t\t\t\t\tpresence?.users ?? [],\n\t\t\t\t),\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t</PresenceContext.Provider>\n\t)\n}\n\nexport function Presence({\n\tuser,\n\tchildren,\n}: {\n\tuser?: User | null\n\tchildren: React.ReactNode\n}) {\n\tconst isOnline = useIsOnline()\n\tif (isOnline) {\n\t\treturn <PresenceOnline user={user}>{children}</PresenceOnline>\n\t} else {\n\t\treturn <PresenceOffline user={user}>{children}</PresenceOffline>\n\t}\n}\n\nexport function usePresence() {\n\tconst presence = useContext(PresenceContext)\n\tif (!presence) {\n\t\tthrow new Error('usePresence must be used within a PresenceProvider')\n\t}\n\treturn presence\n}\n","import { type getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\n\nexport function getSeoMetaTags({\n\ttitle,\n\tdescription,\n\tinstructor,\n\trequestInfo,\n\togTitle = title,\n\togDescription = description,\n\togImageUrl = requestInfo.domain +\n\t\t'/og?' +\n\t\tnew URLSearchParams({\n\t\t\ttitle: ogTitle,\n\t\t\tsubtitle: ogDescription ?? '',\n\t\t\turlPathname: requestInfo.path,\n\t\t\t// to make cache busting possible, whenever the og image changes, we can change the version\n\t\t\t// note if the inputs change, then the cache will be busted automatically\n\t\t\t// it's only if the image changes that we need to change the version\n\t\t\tversion: 'v4',\n\t\t}).toString(),\n\togImageAlt = title,\n}: {\n\ttitle: string\n\trequestInfo: { domain: string; path: string }\n\tdescription?: string\n\tinstructor: Partial<ReturnType<typeof getWorkshopConfig>['instructor']>\n\togTitle?: string\n\togDescription?: string\n\togImageUrl?: string\n\togImageAlt?: string\n}) {\n\treturn [\n\t\t{ title: title },\n\t\tdescription ? { description } : null,\n\t\tinstructor?.name ? { name: 'author', content: instructor.name } : null,\n\t\t{ name: 'og:site_name', content: title },\n\t\t{ name: 'twitter:card', content: 'summary_large_image' },\n\t\t{ name: 'twitter:creator', content: instructor?.['𝕏'] },\n\t\t{ name: 'og:title', content: ogTitle },\n\t\tdescription ? { name: 'og:description', content: ogDescription } : null,\n\t\t{ name: 'og:type', content: 'website' },\n\t\t{ name: 'og:image:width', content: '1200' },\n\t\t{ name: 'og:image:height', content: '630' },\n\t\t{ name: 'og:image:alt', content: ogImageAlt },\n\t\t{ name: 'og:image', content: ogImageUrl },\n\t].filter(Boolean)\n}\n","import { randomUUID as cuid } from 'crypto'\nimport { createCookieSessionStorage, redirect } from 'react-router'\nimport { z } from 'zod'\nimport { combineHeaders } from './misc.tsx'\n\nexport const toastKey = 'toast'\n\nconst TypeSchema = z.enum(['message', 'success', 'error'])\nconst ToastSchema = z\n\t.object({\n\t\tdescription: z.string(),\n\t\tid: z.string().default(() => cuid()),\n\t\ttitle: z.string().optional(),\n\t\ttype: TypeSchema.default('message'),\n\t})\n\t.transform((toast) => ({\n\t\t...toast,\n\t\ttitle: toast.title ? sanitizeCookieValue(toast.title) : undefined,\n\t\tdescription: sanitizeCookieValue(toast.description),\n\t}))\n\nexport type Toast = z.infer<typeof ToastSchema>\nexport type OptionalToast = Omit<Toast, 'id' | 'type'> & {\n\tid?: string\n\ttype?: z.infer<typeof TypeSchema>\n}\n\nexport const toastSessionStorage = createCookieSessionStorage({\n\tcookie: {\n\t\tname: 'EpicShop_toast',\n\t\tsameSite: 'lax',\n\t\tpath: '/',\n\t\thttpOnly: true,\n\t\tsecrets: ['not-so-secret'],\n\t\tsecure: process.env.NODE_ENV === 'production',\n\t},\n})\n\n/**\n * Sanitizes a string value to ensure it can be safely stored in a cookie.\n * Removes or replaces characters that cannot be converted to ByteString.\n */\nfunction sanitizeCookieValue(value: string): string {\n\t// Remove or replace characters with Unicode values > 255\n\treturn value\n\t\t.split('')\n\t\t.map((char) => {\n\t\t\tconst code = char.charCodeAt(0)\n\t\t\t// If character is > 255, replace with a safe alternative\n\t\t\tif (code > 255) {\n\t\t\t\t// Replace smart quotes with regular quotes\n\t\t\t\tif (code === 8216 || code === 8217) return \"'\" // smart single quote\n\t\t\t\tif (code === 8220 || code === 8221) return '\"' // smart double quote\n\t\t\t\tif (code === 8211 || code === 8212) return '-' // en dash and em dash\n\t\t\t\t// Replace other high Unicode characters with a safe fallback\n\t\t\t\treturn '?'\n\t\t\t}\n\t\t\treturn char\n\t\t})\n\t\t.join('')\n}\n\nexport async function redirectWithToast(\n\turl: string,\n\ttoast: OptionalToast,\n\tinit?: ResponseInit,\n) {\n\treturn redirect(url, {\n\t\t...init,\n\t\theaders: combineHeaders(init?.headers, await createToastHeaders(toast)),\n\t})\n}\n\nexport async function createToastHeaders(optionalToast: OptionalToast) {\n\tconst session = await toastSessionStorage.getSession()\n\tconst toast = ToastSchema.parse(optionalToast)\n\tsession.flash(toastKey, toast)\n\tconst cookie = await toastSessionStorage.commitSession(session)\n\treturn new Headers({ 'set-cookie': cookie })\n}\n\nexport async function getToast(request: Request) {\n\tconst session = await toastSessionStorage.getSession(\n\t\trequest.headers.get('cookie'),\n\t)\n\tconst result = ToastSchema.safeParse(session.get(toastKey))\n\tconst toast = result.success ? result.data : null\n\treturn {\n\t\ttoast,\n\t\theaders: toast\n\t\t\t? new Headers({\n\t\t\t\t\t'set-cookie': await toastSessionStorage.destroySession(session),\n\t\t\t\t})\n\t\t\t: null,\n\t}\n}\n","import path from 'node:path'\nimport { getPresentUsers } from '@epic-web/workshop-presence/presence.server'\nimport { getApps } from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetLoggedInProductHosts,\n\tgetPreferences,\n\tgetMutedNotifications,\n} from '@epic-web/workshop-utils/db.server'\nimport { getEnv } from '@epic-web/workshop-utils/env.server'\nimport {\n\tgetProgress,\n\tgetUserInfo,\n\tuserHasAccessToWorkshop,\n} from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcheckForUpdatesCached,\n\tcheckForExerciseChanges,\n} from '@epic-web/workshop-utils/git.server'\nimport { getUnmutedNotifications } from '@epic-web/workshop-utils/notifications.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport {\n\tgetSetClientIdCookieHeader,\n\tgetUserId,\n} from '@epic-web/workshop-utils/user.server'\nimport { checkConnection } from '@epic-web/workshop-utils/utils.server'\n\nimport * as React from 'react'\nimport {\n\tdata,\n\ttype LinksFunction,\n\tLinks,\n\tMeta,\n\tOutlet,\n\tScripts,\n\tScrollRestoration,\n\tuseLoaderData,\n\tuseNavigation,\n} from 'react-router'\nimport { promiseHash } from 'remix-utils/promise'\nimport { useSpinDelay } from 'spin-delay'\nimport { type Route } from './+types/root.tsx'\nimport { Confetti } from './components/confetti'\nimport { GeneralErrorBoundary } from './components/error-boundary'\nimport { ExerciseWarningBanner } from './components/exercise-warning-banner'\nimport { KeyboardShortcutsDialog } from './components/keyboard-shortcuts-dialog'\nimport { EpicProgress } from './components/progress-bar'\nimport { EpicToaster } from './components/toaster'\nimport { TooltipProvider } from './components/ui/tooltip'\nimport { UpdateToast } from './components/update-repo'\nimport { Notifications } from './routes/admin+/notifications'\nimport { useTheme } from './routes/theme/index'\nimport { getTheme } from './routes/theme/theme-session.server'\nimport appStylesheetUrl from './styles/app.css?url'\nimport tailwindStylesheetUrl from './styles/tailwind.css?url'\nimport { ClientHintCheck, getHints } from './utils/client-hints'\nimport { getConfetti } from './utils/confetti.server'\nimport { cn, combineHeaders, getDomainUrl, useAltDown } from './utils/misc'\nimport { Presence } from './utils/presence'\nimport { getSeoMetaTags } from './utils/seo'\nimport { getToast } from './utils/toast.server'\n\nexport const links: LinksFunction = () => {\n\treturn [\n\t\t{ rel: 'stylesheet', href: '/neogrotesk-font.css' },\n\t\t{\n\t\t\trel: 'stylesheet',\n\t\t\thref: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,200;0,300;0,400;0,500;0,600;1,700&display=swap',\n\t\t},\n\t\t{ rel: 'stylesheet', href: tailwindStylesheetUrl },\n\t\t{ rel: 'stylesheet', href: appStylesheetUrl },\n\t\t{\n\t\t\trel: 'icon',\n\t\t\thref: '/favicon.ico',\n\t\t\tsizes: '48x48',\n\t\t},\n\t\t{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },\n\t]\n}\n\nexport const meta: Route.MetaFunction = ({ loaderData }) => {\n\tif (!loaderData) return []\n\n\treturn getSeoMetaTags({\n\t\tinstructor: loaderData.instructor,\n\t\ttitle: loaderData.workshopTitle,\n\t\tdescription: loaderData.workshopSubtitle,\n\t\trequestInfo: loaderData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('rootLoader')\n\tconst workshopConfig = getWorkshopConfig()\n\tconst {\n\t\ttitle: workshopTitle,\n\t\tsubtitle: workshopSubtitle,\n\t\tinstructor,\n\t} = workshopConfig\n\n\tconst theme = getTheme(request)\n\tconst { confettiId, headers: confettiHeaders } = getConfetti(request)\n\tconst { toast, headers: toastHeaders } = await getToast(request)\n\tconst isOnlinePromise = checkConnection({ request, timings })\n\n\tconst asyncStuff = await promiseHash({\n\t\tuserId: getUserId({ request }),\n\t\tpreferences: getPreferences(),\n\t\tprogress: getProgress({ timings }).catch((e) => {\n\t\t\tconsole.error('Failed to get progress', e)\n\t\t\tconst emptyProgress: Awaited<ReturnType<typeof getProgress>> = []\n\t\t\treturn emptyProgress\n\t\t}),\n\t\tuser: getUserInfo(),\n\t\tuserHasAccess: userHasAccessToWorkshop({ request, timings }),\n\t\tapps: getApps({ request, timings }),\n\t\trepoUpdates: checkForUpdatesCached(),\n\t\tunmutedNotifications: getUnmutedNotifications(),\n\t\texerciseChanges: checkForExerciseChanges(),\n\t\tloggedInProductHosts: getLoggedInProductHosts(),\n\t})\n\n\tconst presentUsers = await getPresentUsers({\n\t\trequest,\n\t\ttimings,\n\t})\n\n\t// Filter out repoUpdates if muted\n\tconst mutedNotifications = await getMutedNotifications()\n\tlet repoUpdates = asyncStuff.repoUpdates\n\tif (\n\t\trepoUpdates &&\n\t\t'remoteCommit' in repoUpdates &&\n\t\trepoUpdates.remoteCommit &&\n\t\tmutedNotifications.includes(`update-repo-${repoUpdates.remoteCommit}`)\n\t) {\n\t\trepoUpdates = { ...repoUpdates, updatesAvailable: false }\n\t}\n\n\treturn data(\n\t\t{\n\t\t\t...asyncStuff,\n\t\t\tworkshopConfig,\n\t\t\tworkshopTitle,\n\t\t\tworkshopSubtitle,\n\t\t\tinstructor,\n\t\t\tapps: asyncStuff.apps.map(({ name, fullPath, relativePath }) => ({\n\t\t\t\tname,\n\t\t\t\tfullPath,\n\t\t\t\trelativePath,\n\t\t\t})),\n\t\t\tENV: getEnv(),\n\t\t\trequestInfo: {\n\t\t\t\tprotocol: new URL(request.url).protocol,\n\t\t\t\thostname: new URL(request.url).hostname,\n\t\t\t\tport: new URL(request.url).port,\n\t\t\t\torigin: new URL(request.url).origin,\n\t\t\t\tdomain: getDomainUrl(request),\n\t\t\t\thints: getHints(request),\n\t\t\t\tpath: new URL(request.url).pathname,\n\t\t\t\tsession: { theme },\n\t\t\t\tseparator: path.sep,\n\t\t\t\tonline: await isOnlinePromise,\n\t\t\t},\n\t\t\ttoast,\n\t\t\tconfettiId,\n\t\t\tpresence: {\n\t\t\t\tusers: presentUsers,\n\t\t\t},\n\t\t\trepoUpdates,\n\t\t\texerciseChanges: asyncStuff.exerciseChanges,\n\t\t},\n\t\t{\n\t\t\theaders: combineHeaders(\n\t\t\t\ttoastHeaders,\n\t\t\t\tconfettiHeaders,\n\t\t\t\t{ 'Server-Timing': timings.toString() },\n\t\t\t\tasyncStuff.userId?.type === 'cookie.randomId'\n\t\t\t\t\t? { 'Set-Cookie': getSetClientIdCookieHeader(asyncStuff.userId.id) }\n\t\t\t\t\t: undefined,\n\t\t\t),\n\t\t},\n\t)\n}\n\nfunction Document({\n\tchildren,\n\tenv = {},\n\tclassName,\n\tstyle,\n}: {\n\tchildren: React.ReactNode\n\tenv?: Record<string, unknown>\n\tclassName: string\n\tstyle?: React.CSSProperties\n}) {\n\treturn (\n\t\t<html lang=\"en\" className={className} style={style}>\n\t\t\t<head>\n\t\t\t\t<ClientHintCheck />\n\t\t\t\t<Meta />\n\t\t\t\t<meta charSet=\"utf-8\" />\n\t\t\t\t<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n\t\t\t\t<Links />\n\t\t\t\t<script\n\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t__html: `window.ENV = ${JSON.stringify(env)}`,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</head>\n\t\t\t<body className=\"bg-background text-foreground scrollbar-thin scrollbar-thumb-scrollbar h-screen-safe\">\n\t\t\t\t{children}\n\t\t\t\t<ScrollRestoration />\n\t\t\t\t<Scripts />\n\t\t\t</body>\n\t\t</html>\n\t)\n}\n\nfunction App() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst navigation = useNavigation()\n\tconst showSpinner = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 400,\n\t\tminDuration: 200,\n\t})\n\tconst altDown = useAltDown()\n\tconst [showKeyboardShortcuts, setShowKeyboardShortcuts] =\n\t\tReact.useState(false)\n\n\tReact.useEffect(() => {\n\t\tconst handleToggle = () => {\n\t\t\tsetShowKeyboardShortcuts((prev) => !prev)\n\t\t}\n\t\twindow.addEventListener('toggle-keyboard-shortcuts', handleToggle)\n\t\treturn () => {\n\t\t\twindow.removeEventListener('toggle-keyboard-shortcuts', handleToggle)\n\t\t}\n\t}, [])\n\n\tconst theme = useTheme()\n\treturn (\n\t\t<Document\n\t\t\tstyle={\n\t\t\t\tdata.preferences?.fontSize\n\t\t\t\t\t? { fontSize: `${data.preferences?.fontSize}px` }\n\t\t\t\t\t: {}\n\t\t\t}\n\t\t\tclassName={cn(\n\t\t\t\t'h-screen-safe antialiased',\n\t\t\t\ttheme,\n\t\t\t\t{ 'cursor-progress': showSpinner },\n\t\t\t\taltDown ? 'alt-down' : null,\n\t\t\t)}\n\t\t\tenv={data.ENV}\n\t\t>\n\t\t\t{data.exerciseChanges &&\n\t\t\t\t!data.preferences?.exerciseWarning?.dismissed && (\n\t\t\t\t\t<ExerciseWarningBanner />\n\t\t\t\t)}\n\t\t\t<Outlet />\n\t\t\t<Confetti id={data.confettiId} />\n\t\t\t<EpicToaster toast={data.toast} />\n\t\t\t<UpdateToast repoUpdates={data.repoUpdates} />\n\t\t\t<EpicProgress />\n\t\t\t<Notifications unmutedNotifications={data.unmutedNotifications} />\n\t\t\t<KeyboardShortcutsDialog\n\t\t\t\topen={showKeyboardShortcuts}\n\t\t\t\tonOpenChange={setShowKeyboardShortcuts}\n\t\t\t/>\n\t\t</Document>\n\t)\n}\n\nexport default function AppWithProviders() {\n\tconst { user } = useLoaderData<typeof loader>()\n\treturn (\n\t\t<Presence user={user}>\n\t\t\t<TooltipProvider>\n\t\t\t\t<App />\n\t\t\t</TooltipProvider>\n\t\t</Presence>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<Document className=\"h-screen-safe\">\n\t\t\t<GeneralErrorBoundary />\n\t\t</Document>\n\t)\n}\n","// This is called a \"splat route\" and as it's in the root `/app/routes/`\n// directory, it's a catchall. If no other routes match, this one will and we\n// can know that the user is hitting a URL that doesn't exist. By throwing a\n// 404 from the loader, we can force the error boundary to render which will\n// ensure the user gets the right status code and we can display a nicer error\n// message for them than the Remix and/or browser default.\n\nimport { type LoaderFunctionArgs, Link, useLocation } from 'react-router'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { Icon } from '#app/components/icons.tsx'\n\nexport async function loader({ params }: LoaderFunctionArgs) {\n\tconst splat = params['*']\n\tconst segments = splat?.split('/') ?? []\n\tif (segments.length > 0 && !isNaN(Number(segments[0]))) {\n\t\tconst newPath = `/exercise/${splat}`\n\t\treturn new Response(null, {\n\t\t\tstatus: 302,\n\t\t\theaders: {\n\t\t\t\tLocation: newPath,\n\t\t\t},\n\t\t})\n\t}\n\n\tthrow new Response('Not found', { status: 404 })\n}\n\nexport default function NotFound() {\n\t// due to the loader, this component will never be rendered, but we'll return\n\t// the error boundary just in case.\n\treturn <ErrorBoundary />\n}\n\nexport function ErrorBoundary() {\n\tconst location = useLocation()\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => (\n\t\t\t\t\t<div className=\"flex flex-col gap-6\">\n\t\t\t\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t\t\t\t<h1>We can't find this page:</h1>\n\t\t\t\t\t\t\t<pre className=\"text-body-lg break-all whitespace-pre-wrap\">\n\t\t\t\t\t\t\t\t{location.pathname}\n\t\t\t\t\t\t\t</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<Link to=\"/\" className=\"text-body-md underline\">\n\t\t\t\t\t\t\t<Icon name=\"ArrowLeft\">Back to home</Icon>\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t</div>\n\t\t\t\t),\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import { useSyncExternalStore } from 'react'\n\nexport function makeMediaQueryStore(\n\tmediaQuery: string,\n\tserverSnapshot: boolean,\n) {\n\tfunction getSnapshot() {\n\t\treturn window.matchMedia(mediaQuery).matches\n\t}\n\n\tfunction subscribe(callback: () => void) {\n\t\tconst mediaQueryList = window.matchMedia(mediaQuery)\n\t\tmediaQueryList.addEventListener('change', callback)\n\t\treturn () => {\n\t\t\tmediaQueryList.removeEventListener('change', callback)\n\t\t}\n\t}\n\n\treturn function useMediaQuery() {\n\t\treturn useSyncExternalStore(subscribe, getSnapshot, () => serverSnapshot)\n\t}\n}\n","import { invariant } from '@epic-web/invariant'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\n\nexport function useWorkshopConfig() {\n\tconst data = useRootLoaderData()\n\tinvariant(data.workshopConfig, 'useWorkshopConfig requires a workshopConfig.')\n\treturn data.workshopConfig\n}\n","import { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useWorkshopConfig } from './workshop-config.tsx'\n\ntype Sizes = 'font' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n\nconst sizeClassName = {\n\tfont: 'w-[1em] h-[1em]',\n\txs: 'w-3 h-3',\n\tsm: 'w-4 h-4',\n\tmd: 'w-5 h-5',\n\tlg: 'w-6 h-6',\n\txl: 'w-7 h-7',\n\t'2xl': 'w-8 h-8',\n} as const\n\nconst childrenSizeClassName = {\n\tfont: 'gap-1.5',\n\txs: 'gap-1.5',\n\tsm: 'gap-1.5',\n\tmd: 'gap-2',\n\tlg: 'gap-2',\n\txl: 'gap-3',\n\t'2xl': 'gap-4',\n} satisfies Record<Sizes, string>\n\nexport function ProductName(props: React.HTMLAttributes<HTMLSpanElement>) {\n\tconst {\n\t\tproduct: { displayName },\n\t} = useWorkshopConfig()\n\treturn <span {...props}>{displayName}</span>\n}\n\nexport function Logo({\n\tsize = 'font',\n\tstyle = 'themed',\n\tclassName,\n\tchildren,\n\t...props\n}: React.SVGProps<SVGSVGElement> & {\n\tsize?: Sizes\n\tstyle?: 'themed' | 'monochrome'\n\tclassName?: string\n\tchildren?: React.ReactNode\n}) {\n\tconst {\n\t\tproduct: { logo, displayName },\n\t} = useWorkshopConfig()\n\tconst theme = useTheme()\n\n\tconst logoElement = logo.includes('.svg') ? (\n\t\t<svg\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t>\n\t\t\t<title>{displayName}</title>\n\t\t\t<use href={`${logo}#${style === 'themed' ? theme : 'monochrome'}`} />\n\t\t</svg>\n\t) : (\n\t\t// @ts-expect-error - svg props can't all be applied to img... meh, probably won't ever be a real issue...\n\t\t<img\n\t\t\tsrc={logo}\n\t\t\talt={displayName}\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t/>\n\t)\n\n\tif (children) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={`inline-flex items-center ${childrenSizeClassName[size]}`}\n\t\t\t>\n\t\t\t\t{logoElement}\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn logoElement\n}\n","import { useEffect, useRef } from 'react'\nimport { useRevalidator } from 'react-router'\nimport { z } from 'zod'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\n\nconst eventSchema = z.object({\n\ttype: z.literal('epicshop:file-change'),\n\tdata: z.object({\n\t\tfilePaths: z.array(z.string()),\n\t}),\n})\n\nfunction useRevalidationWSImpl({ watchPaths }: { watchPaths: Array<string> }) {\n\tconst requestInfo = useRequestInfo()\n\n\tconst revalidator = useRevalidator()\n\tconst latestRevalidatorRef = useRef(revalidator)\n\tuseEffect(() => {\n\t\tlatestRevalidatorRef.current = revalidator\n\t}, [revalidator])\n\n\tconst socketParams = new URLSearchParams()\n\tfor (const path of watchPaths) {\n\t\tsocketParams.append('watch', path)\n\t}\n\tconst socketQuery = socketParams.toString()\n\tconst protocol = requestInfo.protocol === 'https:' ? 'wss:' : 'ws:'\n\tconst host = requestInfo.hostname\n\tconst port = requestInfo.port\n\tconst socketPath = `${protocol}//${host}:${port}/__ws?${socketQuery}`\n\n\tuseEffect(() => {\n\t\tif (!socketQuery) return\n\t\tlet ws: WebSocket | null = null\n\t\tfunction createWebSocket() {\n\t\t\tif (ws) ws.close()\n\n\t\t\ttry {\n\t\t\t\tws = new WebSocket(socketPath)\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('🐨 EpicShop WebSocket failed to connect:', error)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tws.onmessage = (message) => {\n\t\t\t\tconst eventParsed = eventSchema.safeParse(JSON.parse(message.data))\n\t\t\t\tif (!eventParsed.success) return\n\t\t\t\tconst { data: event } = eventParsed\n\t\t\t\tif (event.type !== 'epicshop:file-change') return\n\t\t\t\tconsole.log(\n\t\t\t\t\t'🐨 Revalidating due to file changes:',\n\t\t\t\t\tevent.data.filePaths,\n\t\t\t\t)\n\t\t\t\tvoid latestRevalidatorRef.current.revalidate()\n\t\t\t}\n\n\t\t\tws.onclose = (event) => {\n\t\t\t\tif (event.code === 1006) {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tcreateWebSocket()\n\t\t\t\t\t}, 1000)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tws.onerror = (error) => {\n\t\t\t\tconsole.error('🐨 EpicShop WebSocket error:', error)\n\t\t\t}\n\t\t}\n\n\t\tcreateWebSocket()\n\n\t\t// Cleanup function to close the WebSocket when the component unmounts\n\t\treturn () => {\n\t\t\tws?.close()\n\t\t}\n\t}, [socketQuery, socketPath])\n}\n\nexport const useRevalidationWS = ENV.EPICSHOP_DEPLOYED\n\t? () => null\n\t: useRevalidationWSImpl\n","import { useRootLoaderData } from '#app/utils/root-loader.ts'\n\nexport function useOptionalUser() {\n\tconst data = useRootLoaderData()\n\treturn data.user\n}\n\nexport function useUser() {\n\tconst user = useOptionalUser()\n\tif (!user) {\n\t\tthrow new Error(\n\t\t\t'useUser requires a user. If the user is optional, use useOptionalUser instead.',\n\t\t)\n\t}\n\treturn user\n}\n\nexport function useOptionalDiscordMember() {\n\tconst data = useRootLoaderData()\n\treturn data.user?.discordProfile?.user\n\t\t? {\n\t\t\t\tid: data.user.discordProfile.user.id,\n\t\t\t\tdisplayName:\n\t\t\t\t\tdata.user.discordProfile.nick ??\n\t\t\t\t\tdata.user.discordProfile.user.global_name ??\n\t\t\t\t\tdata.user.name ??\n\t\t\t\t\tdata.user.email,\n\t\t\t\tavatarUrl: data.user.imageUrlLarge,\n\t\t\t}\n\t\t: null\n}\n\nexport function useDiscordMember() {\n\tconst discordMember = useOptionalDiscordMember()\n\tif (!discordMember) {\n\t\tthrow new Error(\n\t\t\t'useDiscordMember requires a discordMember. If the discordMember is optional, use useOptionalDiscordMember instead.',\n\t\t)\n\t}\n\treturn discordMember\n}\n\nexport function useUserHasAccess() {\n\tconst data = useRootLoaderData()\n\treturn data.userHasAccess\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport { requireAuthInfo } from '@epic-web/workshop-utils/db.server'\nimport {\n\tgetProgress,\n\tupdateProgress,\n\ttype Progress,\n} from '@epic-web/workshop-utils/epic-api.server'\nimport clsx from 'clsx'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\nimport {\n\tuseFetcher,\n\tuseFetchers,\n\tuseLocation,\n\tuseNavigation,\n\ttype ActionFunctionArgs,\n} from 'react-router'\nimport { createConfettiHeaders } from '#app/utils/confetti.server.ts'\nimport { combineHeaders, ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nexport function useEpicProgress() {\n\tconst data = useRootLoaderData()\n\tconst progressFetcher = useFetchers().find(\n\t\t(f) => f.formAction === '/progress' && f.formData?.has('complete'),\n\t)\n\tif (!progressFetcher || !data.progress) return data.progress ?? null\n\treturn data.progress.map((p) => {\n\t\tconst optimisticCompleted =\n\t\t\tprogressFetcher.formData?.get('complete') === 'true'\n\t\tconst optimisticLessonSlug = progressFetcher.formData?.get('lessonSlug')\n\t\tif (optimisticLessonSlug === p.epicLessonSlug) {\n\t\t\treturn {\n\t\t\t\t...p,\n\t\t\t\tepicCompletedAt: optimisticCompleted ? Date.now() : null,\n\t\t\t}\n\t\t} else {\n\t\t\treturn p\n\t\t}\n\t})\n}\nexport type SerializedProgress = ReturnType<\n\ttypeof useRequireEpicProgress\n>[number]\nexport function useRequireEpicProgress() {\n\tconst progress = useEpicProgress()\n\tif (!progress) return []\n\treturn progress\n}\n\nexport function useNextExerciseRoute() {\n\tconst currentPathname = useLocation().pathname\n\tconst progress = useEpicProgress()\n\tif (!progress) return null\n\tconst scoreProgress = (a: (typeof progress)[number]) => {\n\t\tif (a.type === 'workshop-instructions') return 0\n\t\tif (a.type === 'workshop-finished') return 10000\n\t\tif (a.type === 'instructions') return a.exerciseNumber * 100\n\t\tif (a.type === 'step') return a.exerciseNumber * 100 + a.stepNumber\n\t\tif (a.type === 'finished') return a.exerciseNumber * 100 + 100\n\n\t\tif (a.type === 'unknown') return 100000\n\t\treturn -1\n\t}\n\tconst sortedProgress = progress.sort((a, b) => {\n\t\treturn scoreProgress(a) - scoreProgress(b)\n\t})\n\tconst nextProgress = sortedProgress.find((p) => !p.epicCompletedAt)\n\tif (!nextProgress) return null\n\n\tif (nextProgress.type === 'unknown') return null\n\tif (nextProgress.type === 'workshop-instructions') return '/'\n\tif (nextProgress.type === 'workshop-finished') return '/finished'\n\n\tconst ex = nextProgress.exerciseNumber.toString().padStart(2, '0')\n\tif (nextProgress.type === 'instructions') return `/exercise/${ex}`\n\tif (nextProgress.type === 'finished') return `/exercise/${ex}/finished`\n\n\tconst st = nextProgress.stepNumber.toString().padStart(2, '0')\n\n\tif (nextProgress.type === 'step') {\n\t\tconst problemRoute = `/exercise/${ex}/${st}/problem`\n\t\tconst solutionRoute = `/exercise/${ex}/${st}/solution`\n\t\tif (currentPathname === problemRoute || currentPathname === solutionRoute) {\n\t\t\treturn solutionRoute\n\t\t}\n\t\treturn problemRoute\n\t}\n\n\treturn null\n}\n\nconst percentageClassNames = {\n\t0: '',\n\t1: 'before:h-[10%]',\n\t2: 'before:h-[20%]',\n\t3: 'before:h-[30%]',\n\t4: 'before:h-[40%]',\n\t5: 'before:h-[50%]',\n\t6: 'before:h-[60%]',\n\t7: 'before:h-[70%]',\n\t8: 'before:h-[80%]',\n\t9: 'before:h-[90%]',\n\t10: 'before:h-[100%]',\n}\n\nexport function useExerciseProgressClassName(exerciseNumber: number) {\n\tconst progress = useEpicProgress()\n\tif (!progress?.length) return null\n\tconst exerciseProgress = progress.filter(\n\t\t(p) =>\n\t\t\t(p.type === 'instructions' ||\n\t\t\t\tp.type === 'step' ||\n\t\t\t\tp.type === 'finished') &&\n\t\t\tp.exerciseNumber === exerciseNumber,\n\t)\n\tif (!exerciseProgress.length) return null\n\n\tconst percentComlete =\n\t\texerciseProgress.reduce(\n\t\t\t(acc, p) => (p.epicCompletedAt ? acc + 1 : acc),\n\t\t\t0,\n\t\t) / exerciseProgress.length\n\n\tconst numerator = Math[percentComlete > 0.1 ? 'floor' : 'ceil'](\n\t\tpercentComlete * 10,\n\t) as 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10\n\n\treturn `relative ${percentageClassNames[numerator]} before:bg-highlight before:absolute before:left-0 before:top-0 before:w-[4px]`\n}\n\nexport function useProgressItemClassName(\n\tprogressItemSearch: ProgressItemSearch,\n) {\n\tconst progressItem = useProgressItem(progressItemSearch)\n\tif (!progressItem?.epicCompletedAt) return null\n\treturn `relative before:h-[100%] before:bg-highlight before:absolute before:left-0 before:top-0 before:w-[4px]`\n}\n\ntype WorkshopProgressType = Extract<\n\tProgress['type'],\n\t'workshop-instructions' | 'workshop-finished'\n>\ntype ExerciseProgressType = Extract<\n\tProgress['type'],\n\t'instructions' | 'finished'\n>\ntype StepProgressType = Extract<Progress['type'], 'step'>\n\nexport type ProgressItemSearch =\n\t| {\n\t\t\texerciseNumber: number\n\t\t\tstepNumber?: never\n\t\t\ttype: ExerciseProgressType\n\t }\n\t| {\n\t\t\texerciseNumber: number\n\t\t\tstepNumber: number\n\t\t\ttype: StepProgressType\n\t }\n\t| {\n\t\t\ttype: WorkshopProgressType\n\t\t\texerciseNumber?: never\n\t\t\tstepNumber?: never\n\t }\n\nexport function useProgressItem({\n\texerciseNumber,\n\tstepNumber,\n\ttype,\n}: ProgressItemSearch) {\n\tconst progress = useEpicProgress()\n\tif (!progress?.length) return null\n\n\tif (type === 'workshop-finished' || type === 'workshop-instructions') {\n\t\treturn progress.find((p) => p.type === type) ?? null\n\t} else if (type === 'instructions' || type === 'finished') {\n\t\treturn (\n\t\t\tprogress.find(\n\t\t\t\t(p) => p.type === type && p.exerciseNumber === exerciseNumber,\n\t\t\t) ?? null\n\t\t)\n\t} else if (type === 'step') {\n\t\treturn (\n\t\t\tprogress.find(\n\t\t\t\t(p) =>\n\t\t\t\t\tp.type === type &&\n\t\t\t\t\tp.exerciseNumber === exerciseNumber &&\n\t\t\t\t\tp.stepNumber === stepNumber,\n\t\t\t) ?? null\n\t\t)\n\t}\n\treturn null\n}\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tawait requireAuthInfo({ request })\n\tconst formData = await request.formData()\n\tconst complete = formData.get('complete') === 'true'\n\tconst lessonSlug = formData.get('lessonSlug')\n\tinvariantResponse(\n\t\ttypeof lessonSlug === 'string' && lessonSlug.length > 0,\n\t\t'lessonSlug must be a string',\n\t\t{ status: 400 },\n\t)\n\tconst beforeProgress = await getProgress({ request }).catch((e) => {\n\t\tconsole.error('Failed to get progress', e)\n\t\treturn []\n\t})\n\tconst result = await updateProgress({ lessonSlug, complete }, { request })\n\n\tconst lessonProgress = beforeProgress.find(\n\t\t(p) => p.epicLessonSlug === lessonSlug,\n\t)\n\tfunction getCompletionAnnouncement() {\n\t\tif (!complete) return null\n\t\tif (!lessonProgress) return null\n\t\tconst allOtherAreFinished = beforeProgress.every(\n\t\t\t(p) =>\n\t\t\t\tp.epicCompletedAt || p.epicLessonSlug === lessonProgress.epicLessonSlug,\n\t\t)\n\t\tif (allOtherAreFinished) return 'You completed the workshop!'\n\n\t\tif (\n\t\t\tlessonProgress.type === 'workshop-instructions' ||\n\t\t\tlessonProgress.type === 'unknown' ||\n\t\t\tlessonProgress.type === 'workshop-finished'\n\t\t) {\n\t\t\treturn null\n\t\t}\n\t\tconst { exerciseNumber } = lessonProgress\n\t\tconst otherExerciseLessons = beforeProgress.filter(\n\t\t\t(p) =>\n\t\t\t\t(p.type === 'step' ||\n\t\t\t\t\tp.type === 'instructions' ||\n\t\t\t\t\tp.type === 'finished') &&\n\t\t\t\tp.exerciseNumber === exerciseNumber &&\n\t\t\t\tp.epicLessonSlug !== lessonSlug,\n\t\t)\n\t\tconst otherAreFinished = otherExerciseLessons.every(\n\t\t\t(p) => p.epicCompletedAt,\n\t\t)\n\t\treturn otherAreFinished ? `You completed exercise ${exerciseNumber}!` : null\n\t}\n\tconst announcement = getCompletionAnnouncement()\n\n\treturn dataWithPE(request, formData, result, {\n\t\theaders: combineHeaders(\n\t\t\tannouncement ? createConfettiHeaders() : null,\n\t\t\tannouncement\n\t\t\t\t? await createToastHeaders({\n\t\t\t\t\t\ttitle: 'Congratulations!',\n\t\t\t\t\t\tdescription: announcement,\n\t\t\t\t\t\ttype: 'success',\n\t\t\t\t\t})\n\t\t\t\t: null,\n\t\t),\n\t})\n}\n\nexport function ProgressToggle({\n\tclassName,\n\t...progressItemSearch\n}: { className?: string } & ProgressItemSearch) {\n\tconst progressFetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst progressItem = useProgressItem(progressItemSearch)\n\tconst animationRef = React.useRef<HTMLDivElement>(null)\n\tconst buttonRef = React.useRef<HTMLButtonElement>(null)\n\n\tconst optimisticCompleted = progressFetcher.formData?.has('complete')\n\t\t? progressFetcher.formData.get('complete') === 'true'\n\t\t: Boolean(progressItem?.epicCompletedAt)\n\n\tconst [startAnimation, setStartAnimation] = React.useState(false)\n\n\tconst location = useLocation()\n\tconst navigation = useNavigation()\n\n\tconst navigationLocationStateFrom = navigation.location?.state?.from\n\tconst navigationLocationPathname = navigation.location?.pathname\n\n\tconst locationPathname = location.pathname\n\tReact.useEffect(() => {\n\t\tif (navigationLocationStateFrom === 'continue next lesson button') {\n\t\t\tif (locationPathname === navigationLocationPathname) {\n\t\t\t\tsetStartAnimation(true)\n\t\t\t\tbuttonRef.current?.focus()\n\t\t\t}\n\t\t}\n\t}, [\n\t\tlocation.key,\n\t\tlocationPathname,\n\t\tnavigationLocationPathname,\n\t\tnavigationLocationStateFrom,\n\t])\n\n\tReact.useEffect(() => {\n\t\tlet latest = true\n\t\tif (!startAnimation) return\n\n\t\t// wait a bit for the animation to start\n\t\tvoid new Promise((resolve) => setTimeout(resolve, 200)).then(async () => {\n\t\t\tif (!latest) return\n\t\t\tif (!animationRef.current) return\n\n\t\t\tconst animationPromises = animationRef.current\n\t\t\t\t.getAnimations()\n\t\t\t\t.map(({ finished }) => finished)\n\n\t\t\treturn Promise.allSettled(animationPromises).then(() => {\n\t\t\t\tif (!latest) return\n\t\t\t\tsetStartAnimation(false)\n\t\t\t})\n\t\t})\n\t\treturn () => {\n\t\t\tlatest = false\n\t\t}\n\t}, [startAnimation])\n\n\tif (ENV.EPICSHOP_DEPLOYED || !progressItem) return null\n\n\treturn (\n\t\t<progressFetcher.Form method=\"POST\" action=\"/progress\">\n\t\t\t{peRedirectInput}\n\t\t\t<input\n\t\t\t\ttype=\"hidden\"\n\t\t\t\tname=\"lessonSlug\"\n\t\t\t\tvalue={progressItem.epicLessonSlug}\n\t\t\t/>\n\t\t\t<input\n\t\t\t\ttype=\"hidden\"\n\t\t\t\tname=\"complete\"\n\t\t\t\tvalue={(!optimisticCompleted).toString()}\n\t\t\t/>\n\n\t\t\t<motion.button\n\t\t\t\tref={buttonRef}\n\t\t\t\tonClick={() => {\n\t\t\t\t\tsetStartAnimation(!optimisticCompleted)\n\t\t\t\t}}\n\t\t\t\ttype=\"submit\"\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'group relative flex w-full items-center justify-between overflow-hidden transition hover:bg-[hsl(var(--foreground)/0.02)] focus:bg-[hsl(var(--foreground)/0.02)]',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{optimisticCompleted ? 'Mark as incomplete' : 'Mark as complete'}\n\t\t\t\t{startAnimation ? (\n\t\t\t\t\t<motion.div\n\t\t\t\t\t\tref={animationRef}\n\t\t\t\t\t\tclassName=\"bg-foreground/20 absolute right-0 h-20 w-20 rounded-full\"\n\t\t\t\t\t\tinitial={{\n\t\t\t\t\t\t\tscale: 0.5,\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\tscale: [0.5, 2],\n\t\t\t\t\t\t\topacity: [0, 1, 0],\n\t\t\t\t\t\t}}\n\t\t\t\t\t\ttransition={{\n\t\t\t\t\t\t\tduration: 1,\n\t\t\t\t\t\t\tease: 'easeInOut',\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t\t<motion.div\n\t\t\t\t\taria-hidden\n\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t'relative flex h-8 w-8 items-center justify-center overflow-hidden rounded-full border transition',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t'bg-foreground text-background duration-1000':\n\t\t\t\t\t\t\t\toptimisticCompleted,\n\t\t\t\t\t\t\t'group-hover:bg-background duration-100': !optimisticCompleted,\n\t\t\t\t\t\t},\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{optimisticCompleted ? (\n\t\t\t\t\t\t'✓'\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"absolute -translate-y-10 opacity-25 transition group-hover:translate-y-0\">\n\t\t\t\t\t\t\t✓\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</motion.div>\n\t\t\t</motion.button>\n\t\t</progressFetcher.Form>\n\t)\n}\n","import {\n\textractNumbersAndTypeFromAppNameOrPath,\n\tgetExercises,\n\tgetPlaygroundAppName,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { clsx } from 'clsx'\nimport { motion, useAnimationControls } from 'framer-motion'\nimport * as React from 'react'\nimport {\n\tLink,\n\tNavLink,\n\tOutlet,\n\tuseLoaderData,\n\tuseParams,\n\tdata,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n} from 'react-router'\nimport { useHydrated } from 'remix-utils/use-hydrated'\nimport { Icon } from '#app/components/icons.tsx'\nimport { makeMediaQueryStore } from '#app/components/media-query.ts'\nimport { Logo } from '#app/components/product.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTrigger,\n} from '#app/components/ui/dialog.tsx'\nimport {\n\tSimpleTooltip,\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from '#app/components/ui/tooltip.tsx'\nimport { useOptionalUser, useUserHasAccess } from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { cn, getExercisePath, getExerciseStepPath } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport {\n\tgetProductHostEmoji,\n\tproductHostEmojis,\n\tusePresence,\n\ttype Location,\n\ttype User,\n} from '#app/utils/presence.tsx'\nimport {\n\tuseExerciseProgressClassName,\n\tuseNextExerciseRoute,\n\tuseProgressItemClassName,\n\ttype ProgressItemSearch,\n} from '../progress.tsx'\nimport { ThemeSwitch } from '../theme/index.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('appLayoutLoader')\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst [exercises, playgroundAppName] = await Promise.all([\n\t\tgetExercises({ request, timings }),\n\t\tgetPlaygroundAppName(),\n\t])\n\n\tconst playgroundNumbersAndType = extractNumbersAndTypeFromAppNameOrPath(\n\t\tplaygroundAppName ?? '',\n\t)\n\tconst playground = {\n\t\tappName: playgroundAppName,\n\t\texerciseNumber: Number(playgroundNumbersAndType?.exerciseNumber),\n\t\tstepNumber: Number(playgroundNumbersAndType?.stepNumber),\n\t\ttype: playgroundNumbersAndType?.type,\n\t}\n\n\tconst result = data(\n\t\t{\n\t\t\tworkshopTitle,\n\t\t\texercises: exercises.map((e) => ({\n\t\t\t\texerciseNumber: e.exerciseNumber,\n\t\t\t\ttitle: e.title,\n\t\t\t\tsolutions: e.solutions.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tproblems: e.problems.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tsteps: e.steps.map(({ stepNumber, problem, solution }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle: problem?.title ?? solution?.title ?? 'Unknown',\n\t\t\t\t\tname: problem?.name ?? solution?.name ?? 'Unknown',\n\t\t\t\t\tproblem: problem\n\t\t\t\t\t\t? { name: problem.name, title: problem.title }\n\t\t\t\t\t\t: null,\n\t\t\t\t\tsolution: solution\n\t\t\t\t\t\t? { name: solution.name, title: solution.title }\n\t\t\t\t\t\t: null,\n\t\t\t\t})),\n\t\t\t})),\n\t\t\tplayground,\n\t\t\tisMenuOpened:\n\t\t\t\trequest.headers.get('cookie')?.includes('es_menu_open=true') ?? false,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\tVary: 'Cookie',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n\treturn result\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\tVary: 'Cookie',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst opacities = ['opacity-70', 'opacity-80', 'opacity-90', 'opacity-100']\nconst shadows = [\n\t'shadow-[0_0_2px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_4px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_7px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_10px_0_rgba(0,0,0,0.3)]',\n]\nfunction getScoreClassNames(score: number) {\n\tconst opacityNumber = Math.round(score * opacities.length - 1)\n\tconst shadowNumber = Math.round(score * shadows.length - 1)\n\treturn cn(\n\t\t'shadow-purple-700 hover:opacity-100 focus:opacity-100 dark:shadow-purple-200',\n\t\topacities[opacityNumber] ?? 'opacity-60',\n\t\tshadows[shadowNumber] ?? 'shadow-none',\n\t\tscore === 1 ? 'animate-pulse hover:animate-none focus:animate-none' : null,\n\t)\n}\n\nfunction FacePile({ isMenuOpened }: { isMenuOpened: boolean }) {\n\tconst loggedInUser = useOptionalUser()\n\tconst { users } = usePresence()\n\tconst {\n\t\tproduct: { displayNameShort },\n\t} = useWorkshopConfig()\n\tconst limit = isMenuOpened ? 17 : 0\n\tconst numberOverLimit = users.length - limit\n\tconst shouldShowNumberOverLimit = numberOverLimit > (isMenuOpened ? 1 : 0)\n\n\tif (!users.length) return null\n\n\tconst tiffany =\n\t\tisMenuOpened && users.length === 1 ? (\n\t\t\t<Link\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tto=\"https://www.youtube.com/watch?v=w6Q3mHyzn78\"\n\t\t\t>\n\t\t\t\t<img\n\t\t\t\t\talt=\"Tiffany Tunes\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\tgetScoreClassNames(1),\n\t\t\t\t\t)}\n\t\t\t\t\tsrc=\"/img/tiffany.png\"\n\t\t\t\t/>\n\t\t\t</Link>\n\t\t) : null\n\tconst overLimitLabel = `${numberOverLimit}${\n\t\tisMenuOpened ? ' more ' : ' '\n\t}${displayNameShort} Dev${numberOverLimit === 1 ? '' : 's'} working now`\n\treturn (\n\t\t<div className=\"flex flex-wrap items-center gap-2\">\n\t\t\t<TooltipProvider>\n\t\t\t\t{(shouldShowNumberOverLimit ? users.slice(0, limit) : users).map(\n\t\t\t\t\t({ user, score }) => {\n\t\t\t\t\t\tconst scoreClassNames = getScoreClassNames(score)\n\t\t\t\t\t\tconst locations = getUserLocations(user)\n\t\t\t\t\t\tconst imageUrl = user.imageUrlSmall || user.avatarUrl\n\t\t\t\t\t\tconst hasAccess = user.hasAccess\n\t\t\t\t\t\tconst local = locations.some((loc) =>\n\t\t\t\t\t\t\tloc.origin?.includes('localhost'),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst productHostEmojis = getUniqueProductHostEmojis(locations)\n\t\t\t\t\t\tconst loggedInEmojis = getLoggedInProductEmojis(\n\t\t\t\t\t\t\tuser.loggedInProductHosts,\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\t// Handle opted-out users\n\t\t\t\t\t\tif (user.optOut) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Tooltip key={user.id}>\n\t\t\t\t\t\t\t\t\t<TooltipTrigger asChild tabIndex={0}>\n\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"relative\"\n\t\t\t\t\t\t\t\t\t\t\taria-label=\"Anonymous user (opted out)\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-muted flex h-8 w-8 items-center justify-center rounded-full border opacity-50',\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t\t\t<span className=\"flex flex-col items-center justify-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t{loggedInEmojis ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-xs\">{loggedInEmojis}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\tAnonymous (opted out of sharing)\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet doingLabel: string\n\t\t\t\t\t\tif (hasAccess) {\n\t\t\t\t\t\t\tdoingLabel = local ? 'working' : 'referencing'\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdoingLabel = local ? 'previewing' : 'reviewing'\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Tooltip key={user.id}>\n\t\t\t\t\t\t\t\t<TooltipTrigger asChild tabIndex={0}>\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tclassName=\"relative\"\n\t\t\t\t\t\t\t\t\t\taria-label={user.name || `${displayNameShort} Dev`}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{imageUrl ? (\n\t\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\t\talt={user.name || displayNameShort}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tsrc={imageUrl}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'flex h-8 w-8 items-center justify-center rounded-full border',\n\t\t\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t{productHostEmojis ? (\n\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"absolute -top-1 -left-1 text-xs leading-none\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Workshop products\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{productHostEmojis}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t\t<span className=\"flex flex-col items-center justify-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t\t\t\t\t\t\t{loggedInEmojis ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-xs\">{loggedInEmojis}</span>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t{user.name || `${displayNameShort} Dev`}\n\t\t\t\t\t\t\t\t\t\t\t{locations.length > 0\n\t\t\t\t\t\t\t\t\t\t\t\t? ` is ${doingLabel} ${\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tscore === 1 && loggedInUser?.id !== user.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'with you'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t\t\t\t\t\t\t} on`\n\t\t\t\t\t\t\t\t\t\t\t\t: null}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t{locations.map((loc, index) => {\n\t\t\t\t\t\t\t\t\t\t\tconst locationLabel = getLocationLabel(loc)\n\t\t\t\t\t\t\t\t\t\t\tif (!locationLabel) return null\n\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\t\tkey={`${loc.workshopTitle}-${index}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'flex flex-col items-center',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlocations.length > 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'border-border mt-1 border-t pt-1 first:mt-0 first:border-t-0 first:pt-0'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{locationLabel.line1 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{getProductHostEmoji(loc.productHost)}{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{locationLabel.line1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{locationLabel.line2 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{locationLabel.line2}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t)}\n\t\t\t\t{tiffany}\n\t\t\t\t{shouldShowNumberOverLimit ? (\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild tabIndex={0}>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\taria-label={overLimitLabel}\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'bg-accent text-accent-foreground flex items-center justify-center rounded-full border text-xs',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'h-8 w-8' : 'h-6 w-6',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t'pointer-events-none overflow-hidden text-center text-ellipsis whitespace-nowrap',\n\t\t\t\t\t\t\t\t\t\tisMenuOpened ? 'w-8' : 'w-6',\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? `+${numberOverLimit}` : numberOverLimit}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>{overLimitLabel}</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t) : null}\n\t\t\t</TooltipProvider>\n\t\t</div>\n\t)\n}\n\nfunction getLoggedInProductEmojis(\n\thosts: string[] | null | undefined,\n): string | null {\n\tif (!hosts || hosts.length === 0) return null\n\treturn hosts\n\t\t.map((host) => productHostEmojis[host])\n\t\t.filter(Boolean)\n\t\t.join(' ')\n}\n\nfunction getUserLocations(user: User): Location[] {\n\tif (user.locations && user.locations.length > 0) {\n\t\treturn user.locations.filter(Boolean) as Location[]\n\t}\n\tif (user.location) {\n\t\treturn [user.location]\n\t}\n\treturn []\n}\n\nfunction getUniqueProductHostEmojis(locations: Location[]): string | null {\n\tconst uniqueHosts = new Set<string>()\n\tfor (const loc of locations) {\n\t\tif (loc.productHost) {\n\t\t\tuniqueHosts.add(loc.productHost)\n\t\t}\n\t}\n\tif (uniqueHosts.size === 0) return null\n\treturn Array.from(uniqueHosts)\n\t\t.map((host) => getProductHostEmoji(host))\n\t\t.filter(Boolean)\n\t\t.join('')\n}\n\nconst useIsWide = makeMediaQueryStore('(min-width: 640px)', true)\n\nexport default function App() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst isWide = useIsWide()\n\tconst isHydrated = useHydrated()\n\n\tconst [isMenuOpened, setMenuOpenedState] = React.useState(data.isMenuOpened)\n\tuseRevalidationWS({ watchPaths: ['./exercises/README.mdx'] })\n\n\tfunction setMenuOpened(value: boolean) {\n\t\tsetMenuOpenedState(value)\n\t\tdocument.cookie = `es_menu_open=${value.toString()}; path=/; SameSite=Lax;`\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col\">\n\t\t\t{user ? null : <NoUserBanner />}\n\t\t\t{/*\n\t\t\t\tthis isn't placed in a conditional with isWide because the server render\n\t\t\t\tdoesn't know whether it should be around or not so we just use CSS to hide it\n\t\t\t\tif it's not supposed to show up.\n\n\t\t\t\tWe don't just use media queries for the wider screen nav because we want\n\t\t\t\tto avoid running all the logic in there unnecessarily.\n\t\t\t*/}\n\t\t\t{isHydrated && isWide ? null : (\n\t\t\t\t<MobileNavigation\n\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\tonMenuOpenChange={setMenuOpened}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\t// this nonsense is here because we want the panels to be scrollable rather\n\t\t\t\t// than having the entire page be scrollable (at least on wider screens)\n\t\t\t\tclassName={cn('flex grow flex-col sm:flex-row', {\n\t\t\t\t\t'h-[calc(100vh-128px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\t!user,\n\t\t\t\t\t'h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\tuser,\n\t\t\t\t\t'h-[unset]': !isWide && isMenuOpened,\n\t\t\t\t})}\n\t\t\t>\n\t\t\t\t{isWide ? (\n\t\t\t\t\t<Navigation\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tonMenuOpenChange={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-full w-full max-w-full sm:max-w-[calc(100%-56px)]',\n\t\t\t\t\t\tisMenuOpened ? 'hidden md:block' : '',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Outlet />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction getLocationLabel(location: User['location']) {\n\tif (!location) return null\n\n\tconst { exercise } = location\n\n\tconst exercisePortion = [\n\t\texercise\n\t\t\t? [exercise.exerciseNumber, exercise.stepNumber]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.map((s) => s.toString().padStart(2, '0'))\n\t\t\t\t\t.join('/')\n\t\t\t: null,\n\t\texercise?.type,\n\t]\n\t\t.filter(Boolean)\n\t\t.join(' - ')\n\treturn { line1: location.workshopTitle, line2: exercisePortion }\n}\n\nfunction NoUserBanner() {\n\tconst isWide = useIsWide()\n\tconst {\n\t\tproduct: { host, displayName },\n\t} = useWorkshopConfig()\n\tconst userHasAccess = useUserHasAccess()\n\tconst details = (\n\t\t<div>\n\t\t\t{ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t<div>\n\t\t\t\t\t{`This is the deployed version. `}\n\t\t\t\t\t<>\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tto={ENV.EPICSHOP_GITHUB_REPO}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tRun locally\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t{` for full experience.`}\n\t\t\t\t\t</>{' '}\n\t\t\t\t</div>\n\t\t\t) : userHasAccess ? (\n\t\t\t\t<div>\n\t\t\t\t\t<Link to=\"/login\" className=\"underline\">\n\t\t\t\t\t\tLogin\n\t\t\t\t\t</Link>{' '}\n\t\t\t\t\tor{' '}\n\t\t\t\t\t<a href={`https://${host}/login`} className=\"underline\">\n\t\t\t\t\t\tjoin for free\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\tfor the full experience.\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t)\n\treturn (\n\t\t<div className=\"z-10 flex h-16 items-center justify-between border-b bg-linear-to-tr from-blue-500 to-indigo-500 pl-4 text-white\">\n\t\t\t{isWide ? (\n\t\t\t\t<>\n\t\t\t\t\t<div className=\"hidden flex-1 flex-wrap items-center gap-4 sm:flex\">\n\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t<div className=\"flex flex-1 flex-wrap items-center\">\n\t\t\t\t\t\t\t<p className=\"mr-2\">\n\t\t\t\t\t\t\t\tWelcome to the{' '}\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{displayName}\n\t\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\t\tWorkshop app!\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t{details}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{userHasAccess ? null : (\n\t\t\t\t\t\t<div className=\"hidden h-full flex-col items-center sm:flex md:flex-row\">\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Join {displayName}</span>\n\t\t\t\t\t\t\t\t<span>↗︎</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={ENV.EPICSHOP_DEPLOYED ? `https://${host}/login` : '/login'}\n\t\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"User\" size=\"lg\" />\n\t\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Login</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<div className=\"flex flex-1 flex-wrap items-center gap-4 sm:hidden\">\n\t\t\t\t\t\t<a href={`https://${host}`}>\n\t\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<Dialog>\n\t\t\t\t\t\t\t<DialogTrigger>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" size=\"lg\" className=\"animate-pulse\" />\n\t\t\t\t\t\t\t</DialogTrigger>\n\t\t\t\t\t\t\t<DialogContent>\n\t\t\t\t\t\t\t\t<DialogHeader>\n\t\t\t\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t\t\t\t<span className=\"text-lg font-semibold\">{displayName}</span>\n\t\t\t\t\t\t\t\t</DialogHeader>\n\t\t\t\t\t\t\t\t<DialogDescription>\n\t\t\t\t\t\t\t\t\tWelcome to the{' '}\n\t\t\t\t\t\t\t\t\t<Link to={`https://${host}`} className=\"underline\">\n\t\t\t\t\t\t\t\t\t\t{displayName}\n\t\t\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\t\t\tWorkshop app!\n\t\t\t\t\t\t\t\t</DialogDescription>\n\t\t\t\t\t\t\t\t{details}\n\t\t\t\t\t\t\t</DialogContent>\n\t\t\t\t\t\t</Dialog>\n\t\t\t\t\t</div>\n\t\t\t\t\t{userHasAccess ? null : (\n\t\t\t\t\t\t<div className=\"flex h-full items-center\">\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Join</span>\n\t\t\t\t\t\t\t\t<span>↗︎</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={ENV.EPICSHOP_DEPLOYED ? `https://${host}/login` : '/login'}\n\t\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"User\" size=\"lg\" />\n\t\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Login</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n\nconst itemVariants = {\n\thidden: { opacity: 0, x: -20 },\n\tvisible: { opacity: 1, x: 0 },\n}\nfunction NavigationExerciseListItem({\n\texerciseNumber,\n\tchildren,\n}: {\n\texerciseNumber: number\n\tchildren: React.ReactNode\n}) {\n\tconst progressClassName = useExerciseProgressClassName(exerciseNumber)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"inline-block pl-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nfunction NavigationExerciseStepListItem({\n\tchildren,\n\t...progressItemSearch\n}: {\n\tchildren: React.ReactNode\n} & ProgressItemSearch) {\n\tconst progressClassName = useProgressItemClassName(progressItemSearch)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"inline-block pl-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nfunction MobileNavigation({\n\tisMenuOpened,\n\tonMenuOpenChange: setMenuOpened,\n}: {\n\tisMenuOpened: boolean\n\tonMenuOpenChange: (change: boolean) => void\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst nextExerciseRoute = useNextExerciseRoute()\n\tconst params = useParams()\n\tconst isOnline = useIsOnline()\n\tconst { users } = usePresence()\n\n\t// items\n\tconst listVariants = {\n\t\tvisible: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tduration: 0.05,\n\t\t\t\twhen: 'beforeChildren',\n\t\t\t\tstaggerChildren: 0.03,\n\t\t\t},\n\t\t},\n\t\thidden: {\n\t\t\topacity: 0,\n\t\t},\n\t}\n\n\treturn (\n\t\t<nav className=\"flex w-full border-b sm:hidden\">\n\t\t\t<div className=\"w-full\">\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn('flex items-center', {\n\t\t\t\t\t\t'flex-col': isMenuOpened,\n\t\t\t\t\t\t'h-14': !isMenuOpened,\n\t\t\t\t\t})}\n\t\t\t\t>\n\t\t\t\t\t<NavToggle\n\t\t\t\t\t\ttitle={data.workshopTitle}\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tsetMenuOpened={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t\t{isMenuOpened && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\tclassName=\"scrollbar-thin scrollbar-thumb-scrollbar flex w-full grow flex-col justify-between overflow-x-auto p-6\"\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\tto=\"/\"\n\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 text-2xl font-bold whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{data.exercises.map(({ exerciseNumber, title, steps }) => {\n\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber) === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst showPlayground =\n\t\t\t\t\t\t\t\t\t\t!isActive &&\n\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber === exerciseNumber\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<NavigationExerciseListItem\n\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1 text-2xl font-bold\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t{showPlayground ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.type,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t🛝\n\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"mt-2 ml-4 flex flex-col\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"instructions\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background relative px-2 py-0.5 pr-3 text-xl font-medium whitespace-nowrap outline-none after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!params.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntro\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{steps\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map(({ stepNumber, title, problem, solution }) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-0.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"leading-tight font-semibold\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{stepNumber.toString().padStart(2, '0')}.{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mt-0.5 ml-3 flex gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{problem && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'problem',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tProblem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{problem.name ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? ' 🛝'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{solution && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'solution',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSolution\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{solution.name ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? ' 🛝'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber, 'finished')}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background relative px-2 py-0.5 pr-3 text-base font-medium whitespace-nowrap outline-none after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background': isActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t📝 Elaboration\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t</NavigationExerciseListItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t<div className=\"mt-6\">\n\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\tto=\"/finished\"\n\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t'relative text-lg font-bold whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background bg-black text-white after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"]':\n\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t📝 Workshop Feedback\n\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div className=\"grow\" />\n\t\t\t\t\t{isOnline ? null : (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'You are offline'}>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex h-14 animate-pulse items-center justify-start p-4',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'w-full border-t' : 'border-l',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\tname=\"WifiNoConnection\"\n\t\t\t\t\t\t\t\t\tclassName=\"text-foreground-destructive\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? 'You are offline' : null}\n\t\t\t\t\t\t\t\t</Icon>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex items-center justify-start p-4',\n\t\t\t\t\t\t\tisMenuOpened && users.length > 4 ? 'min-h-14' : 'h-14',\n\t\t\t\t\t\t\tisMenuOpened ? 'w-full border-t' : 'border-l',\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<FacePile isMenuOpened={isMenuOpened} />\n\t\t\t\t\t</div>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user ? (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'Your account'}>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex h-14 shrink-0 items-center justify-start space-x-3 px-4 py-4 text-center no-underline hover:underline',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t'border-l': !isMenuOpened,\n\t\t\t\t\t\t\t\t\t\t'w-full border-t': isMenuOpened,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tto=\"/account\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{user.imageUrlSmall ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\talt={user.name ?? user.email}\n\t\t\t\t\t\t\t\t\t\tsrc={user.imageUrlSmall}\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-full rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Icon name=\"User\" className=\"shrink-0\" size=\"lg\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tYour Account\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Your account</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user && nextExerciseRoute ? (\n\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\tcontent={isMenuOpened ? null : 'Continue to next lesson'}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={nextExerciseRoute}\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex h-14 w-full items-center space-x-3 border-l px-4 py-4 pl-[18px] no-underline hover:underline',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstate={{ from: 'continue next lesson button' }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"FastForward\" className=\"shrink-0\" size=\"md\" />\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tContinue to next lesson\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Continue to next lesson</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex h-14 w-14 items-center justify-center self-start p-4 sm:mb-4 sm:w-full',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t'w-full border-t': isMenuOpened,\n\t\t\t\t\t\t\t\t'border-l': !isMenuOpened,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ThemeSwitch />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</nav>\n\t)\n}\n\nconst OPENED_MENU_WIDTH = 400\n\nfunction Navigation({\n\tisMenuOpened,\n\tonMenuOpenChange: setMenuOpened,\n}: {\n\tisMenuOpened: boolean\n\tonMenuOpenChange: (change: boolean) => void\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst nextExerciseRoute = useNextExerciseRoute()\n\tconst params = useParams()\n\tconst isOnline = useIsOnline()\n\tconst { users } = usePresence()\n\n\tconst exercise = data.exercises.find(\n\t\t(e) => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tconst app =\n\t\tparams.type === 'solution'\n\t\t\t? exercise?.solutions.find(\n\t\t\t\t\t(s) => s.stepNumber === Number(params.stepNumber),\n\t\t\t\t)\n\t\t\t: params.type === 'problem'\n\t\t\t\t? exercise?.problems.find(\n\t\t\t\t\t\t(p) => p.stepNumber === Number(params.stepNumber),\n\t\t\t\t\t)\n\t\t\t\t: null\n\n\t// container\n\tconst menuControls = useAnimationControls()\n\tconst menuVariants = {\n\t\tclose: { width: 56 },\n\t\topen: { width: OPENED_MENU_WIDTH },\n\t}\n\n\t// items\n\tconst listVariants = {\n\t\tvisible: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tduration: 0.05,\n\t\t\t\twhen: 'beforeChildren',\n\t\t\t\tstaggerChildren: 0.03,\n\t\t\t},\n\t\t},\n\t\thidden: {\n\t\t\topacity: 0,\n\t\t},\n\t}\n\n\treturn (\n\t\t<nav className=\"hidden border-r sm:flex\">\n\t\t\t<motion.div\n\t\t\t\tinitial={isMenuOpened ? 'open' : 'close'}\n\t\t\t\tvariants={menuVariants}\n\t\t\t\tanimate={menuControls}\n\t\t\t>\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t\t<NavToggle\n\t\t\t\t\t\ttitle={data.workshopTitle}\n\t\t\t\t\t\tmenuControls={menuControls}\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tsetMenuOpened={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t\t{isMenuOpened && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\tstyle={{ width: OPENED_MENU_WIDTH }}\n\t\t\t\t\t\t\tclassName=\"scrollbar-thin scrollbar-thumb-scrollbar flex grow flex-col justify-between overflow-y-auto p-6\"\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\tto=\"/\"\n\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 text-2xl font-bold whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{data.exercises.map(({ exerciseNumber, title, steps }) => {\n\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber) === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst showPlayground =\n\t\t\t\t\t\t\t\t\t\t!isActive &&\n\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber === exerciseNumber\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<NavigationExerciseListItem\n\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1 text-2xl font-bold\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t{showPlayground ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.type,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t🛝\n\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"mt-2 ml-4 flex flex-col\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"instructions\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background relative px-2 py-0.5 pr-3 text-xl font-medium whitespace-nowrap outline-none after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!params.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntro\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{steps\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map(({ stepNumber, title, problem, solution }) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-0.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"leading-tight font-semibold\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{stepNumber.toString().padStart(2, '0')}.{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mt-0.5 ml-3 flex gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{problem && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'problem',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tProblem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{problem.name ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? ' 🛝'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{solution && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'solution',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative px-2 py-0.5 pr-3 whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSolution\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{solution.name ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? ' 🛝'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={getExercisePath(exerciseNumber, 'finished')}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background relative px-2 py-0.5 pr-3 text-base font-medium whitespace-nowrap outline-none after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background': isActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t📝 Elaboration\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t</NavigationExerciseListItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t<div className=\"mt-6\">\n\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\tto=\"/finished\"\n\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t'relative text-lg font-bold whitespace-nowrap outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t'after:bg-background bg-black text-white after:absolute after:-right-2.5 after:-bottom-2.5 after:h-5 after:w-5 after:scale-75 after:rotate-45 after:content-[\"\"]':\n\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t📝 Workshop Feedback\n\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t)}\n\t\t\t\t\t{!isMenuOpened && (\n\t\t\t\t\t\t<div className=\"flex grow flex-col justify-center\">\n\t\t\t\t\t\t\t<div className=\"orientation-sideways w-full font-mono text-sm leading-none font-medium uppercase\">\n\t\t\t\t\t\t\t\t{exercise?.title ? (\n\t\t\t\t\t\t\t\t\t<Link to={getExercisePath(Number(params.exerciseNumber))}>\n\t\t\t\t\t\t\t\t\t\t{exercise.title}\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{exercise?.title && app?.title ? ' — ' : null}\n\t\t\t\t\t\t\t\t{app?.title ? (\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={getExerciseStepPath(\n\t\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber),\n\t\t\t\t\t\t\t\t\t\t\tapp.stepNumber,\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{app.title}\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{isOnline ? null : (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'You are offline'}>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex w-full animate-pulse items-center border-t p-4',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'justify-start' : 'justify-center',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\tname=\"WifiNoConnection\"\n\t\t\t\t\t\t\t\t\tclassName=\"text-foreground-destructive\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"whitespace-nowrap\">You are offline</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</Icon>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex w-full items-center justify-start border-t p-4 transition-[height]',\n\t\t\t\t\t\t\tisMenuOpened && users.length > 4 ? 'h-28' : 'h-14',\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstyle={isMenuOpened ? { width: OPENED_MENU_WIDTH } : {}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<FacePile isMenuOpened={isMenuOpened} />\n\t\t\t\t\t</div>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user ? (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'Your account'}>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName=\"flex h-14 w-full shrink-0 items-center justify-start space-x-3 border-t px-4 py-4 text-center no-underline hover:underline\"\n\t\t\t\t\t\t\t\tto=\"/account\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{user.imageUrlSmall ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\talt={user.name ?? user.email}\n\t\t\t\t\t\t\t\t\t\tsrc={user.imageUrlSmall}\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-full rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Icon name=\"User\" className=\"shrink-0\" size=\"lg\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tYour Account\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Your account</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user && nextExerciseRoute ? (\n\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\tcontent={isMenuOpened ? null : 'Continue to next lesson'}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={nextExerciseRoute}\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex h-14 w-full items-center space-x-3 border-t px-4 py-4 pl-[18px] no-underline hover:underline',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstate={{ from: 'continue next lesson button' }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"FastForward\" className=\"shrink-0\" size=\"md\" />\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tContinue to next lesson\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Continue to next lesson</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"mb-4 w-full self-start border-t pt-[15px] pl-3\">\n\t\t\t\t\t\t<ThemeSwitch />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</motion.div>\n\t\t</nav>\n\t)\n}\n\nfunction NavToggle({\n\ttitle,\n\tisMenuOpened,\n\tsetMenuOpened,\n\tmenuControls,\n}: {\n\ttitle: string\n\tisMenuOpened: boolean\n\tsetMenuOpened: (value: boolean) => void\n\tmenuControls?: ReturnType<typeof useAnimationControls>\n}) {\n\tconst initialOpenRef = React.useRef(isMenuOpened)\n\tconst menuButtonRef = React.useRef<HTMLButtonElement>(null)\n\tconst path01Variants = {\n\t\topen: { d: 'M3.06061 2.99999L21.0606 21' },\n\t\tclosed: { d: 'M0 9.5L24 9.5' },\n\t}\n\tconst path02Variants = {\n\t\topen: { d: 'M3.00006 21.0607L21 3.06064' },\n\t\tmoving: { d: 'M0 14.5L24 14.5' },\n\t\tclosed: { d: 'M0 14.5L15 14.5' },\n\t}\n\tconst path01Controls = useAnimationControls()\n\tconst path02Controls = useAnimationControls()\n\n\tasync function toggleMenu() {\n\t\tvoid menuControls?.start(isMenuOpened ? 'close' : 'open')\n\t\tsetMenuOpened(!isMenuOpened)\n\t\tif (isMenuOpened) {\n\t\t\tvoid path01Controls.start(path01Variants.closed)\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path02Controls.start(path02Variants.closed)\n\t\t} else {\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path01Controls.start(path01Variants.open)\n\t\t\tvoid path02Controls.start(path02Variants.open)\n\t\t}\n\t}\n\n\tReact.useEffect(() => {\n\t\tif (!isMenuOpened) return\n\n\t\tfunction handleKeyUp(event: KeyboardEvent) {\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\tmenuButtonRef.current?.click()\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('keyup', handleKeyUp)\n\t\treturn () => document.removeEventListener('keyup', handleKeyUp)\n\t}, [isMenuOpened])\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'relative inline-flex h-14 shrink-0 items-center justify-between overflow-hidden border-r sm:w-full sm:border-r-0 sm:border-b',\n\t\t\t\t{\n\t\t\t\t\t'w-full': isMenuOpened,\n\t\t\t\t},\n\t\t\t)}\n\t\t>\n\t\t\t<button\n\t\t\t\tref={menuButtonRef}\n\t\t\t\tclassName=\"flex h-14 w-14 items-center justify-center\"\n\t\t\t\taria-label=\"Open Navigation menu\"\n\t\t\t\tonClick={toggleMenu}\n\t\t\t>\n\t\t\t\t<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path01Variants[initialOpenRef.current ? 'open' : 'closed']}\n\t\t\t\t\t\tanimate={path01Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path02Variants[initialOpenRef.current ? 'open' : 'closed']}\n\t\t\t\t\t\tanimate={path02Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t</button>\n\t\t\t{isMenuOpened && (\n\t\t\t\t<motion.p\n\t\t\t\t\ttransition={{ delay: 0.2 }}\n\t\t\t\t\tinitial={{ opacity: 0, y: 5 }}\n\t\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\t\tclassName=\"absolute right-5 font-mono text-sm whitespace-nowrap uppercase\"\n\t\t\t\t>\n\t\t\t\t\t<Link to=\"/\">{title}</Link>\n\t\t\t\t</motion.p>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n","import { clsx } from 'clsx'\nimport { Link } from 'react-router'\nimport { cn } from '#app/utils/misc.tsx'\n\nfunction PendingState() {\n\treturn <span className=\"inline-block animate-spin\">🌀</span>\n}\n\nfunction SuccessState() {\n\treturn <span>✅</span>\n}\n\nfunction ErrorState() {\n\treturn <span>❌</span>\n}\n\nexport function getButtonClassName({\n\tvarient,\n\tclip = true,\n}: {\n\tvarient: 'primary' | 'big' | 'mono'\n\tclip?: boolean\n}) {\n\tconst baseClassName =\n\t\t'inline-flex bg-foreground text-background outline-none hover:bg-background hover:text-foreground focus:bg-background focus:text-foreground'\n\tconst primaryClassName = 'px-8 py-4 font-bold'\n\tconst bigClassName = 'px-8 py-4 text-xl font-bold'\n\tconst monoClassName = 'px-8 py-4 font-mono text-sm uppercase'\n\tconst className = clsx(baseClassName, {\n\t\t'clip-path-button': clip,\n\t\t[primaryClassName]: varient === 'primary',\n\t\t[bigClassName]: varient === 'big',\n\t\t[monoClassName]: varient === 'mono',\n\t})\n\treturn className\n}\n\nexport function Button({\n\tvarient,\n\tstatus = 'idle',\n\t...props\n}: React.ComponentPropsWithoutRef<'button'> &\n\tParameters<typeof getButtonClassName>[0] & {\n\t\tstatus?: 'pending' | 'success' | 'error' | 'idle'\n\t}) {\n\tconst companion = {\n\t\tpending: <PendingState />,\n\t\tsuccess: <SuccessState />,\n\t\terror: <ErrorState />,\n\t\tidle: null,\n\t}[status]\n\treturn (\n\t\t<div className=\"clip-path-button-outer border-foreground bg-foreground w-fit border-2\">\n\t\t\t<button\n\t\t\t\t{...props}\n\t\t\t\tclassName={clsx(\n\t\t\t\t\tprops.className,\n\t\t\t\t\tgetButtonClassName({ varient }),\n\t\t\t\t\t'flex justify-center gap-4',\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<div>{props.children}</div>\n\t\t\t\t{companion}\n\t\t\t</button>\n\t\t</div>\n\t)\n}\n\nexport function ButtonLink({\n\tvarient,\n\t...props\n}: React.ComponentPropsWithoutRef<typeof Link> &\n\tParameters<typeof getButtonClassName>[0]) {\n\treturn (\n\t\t<div className=\"clip-path-button-outer border-foreground bg-foreground w-fit border-2\">\n\t\t\t<Link\n\t\t\t\t{...props}\n\t\t\t\tclassName={clsx(props.className, getButtonClassName({ varient }))}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\nexport function LinkButton({\n\tclassName,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'>) {\n\treturn <button {...props} className={clsx('underline', className)} />\n}\n\nexport const iconButtonClassName = `inline-flex h-8 w-8 items-center justify-center rounded border focus:outline-none focus:ring-2 focus:ring-ring`\nexport function IconButton({\n\tchildren,\n\tclassName = '',\n\t...props\n}: React.ComponentPropsWithoutRef<'button'>) {\n\treturn (\n\t\t<button {...props} className={cn(iconButtonClassName, className)}>\n\t\t\t{children}\n\t\t</button>\n\t)\n}\n","import { deleteCache } from '@epic-web/workshop-utils/cache.server'\nimport {\n\tlogout,\n\trequireAuthInfo,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { redirect, type LoaderFunctionArgs, Form, Link } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport {\n\tuseOptionalDiscordMember,\n\tuseUser,\n\tuseUserHasAccess,\n} from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { cn, ensureUndeployed } from '#app/utils/misc.tsx'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tawait requireAuthInfo({ request })\n\treturn {}\n}\n\nexport async function action({ request }: { request: Request }) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tif (intent === 'logout') {\n\t\tawait logout()\n\t\tawait deleteCache()\n\t\treturn redirectWithToast('/login', {\n\t\t\ttype: 'success',\n\t\t\ttitle: 'Logged out',\n\t\t\tdescription: 'Goodbye! Come back soon!',\n\t\t})\n\t} else if (intent === 'presence-opt-out') {\n\t\tconst optOut = formData.get('optOut') === 'true'\n\t\tawait setPreferences({ presence: { optOut } })\n\t\treturn redirectWithToast('/account', {\n\t\t\ttitle: optOut ? 'Opted out' : 'Opted in',\n\t\t\tdescription: `You are now ${optOut ? 'invisible' : 'visible'}.`,\n\t\t\ttype: 'success',\n\t\t})\n\t}\n\n\treturn redirect('/account')\n}\n\nfunction useConnectDiscordURL() {\n\tconst {\n\t\tproduct: { host },\n\t} = useWorkshopConfig()\n\treturn `https://${host}/discord`\n}\n\nexport default function Account() {\n\tconst user = useUser()\n\tconst config = useWorkshopConfig()\n\tconst discordMember = useOptionalDiscordMember()\n\tconst connectDiscordURL = useConnectDiscordURL()\n\tconst userHasAccess = useUserHasAccess()\n\n\treturn (\n\t\t<main className=\"container flex h-full w-full max-w-3xl grow flex-col items-center justify-center gap-4\">\n\t\t\t{user.imageUrlLarge ? (\n\t\t\t\t<img\n\t\t\t\t\tclassName=\"h-36 w-36 rounded-full\"\n\t\t\t\t\talt={discordMember?.displayName ?? user.name ?? user.email}\n\t\t\t\t\tsrc={user.imageUrlLarge}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<Icon name=\"User\" className=\"shrink-0\" size=\"lg\" />\n\t\t\t)}\n\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<h1 className=\"mb-1 text-2xl\">Your Account</h1>\n\t\t\t\t{config.product.slug ? (\n\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\tcontent={\n\t\t\t\t\t\t\tuserHasAccess\n\t\t\t\t\t\t\t\t? 'You have access to this workshop'\n\t\t\t\t\t\t\t\t: 'You do not have full access to this workshop'\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\tname={userHasAccess ? 'Success' : 'Error'}\n\t\t\t\t\t\t\tsize=\"lg\"\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\tuserHasAccess\n\t\t\t\t\t\t\t\t\t? 'bg-success text-success-foreground'\n\t\t\t\t\t\t\t\t\t: 'bg-warning text-warning-foreground',\n\t\t\t\t\t\t\t\t'rounded-full p-1',\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t) : null}\n\t\t\t</div>\n\n\t\t\t{!userHasAccess && config.product.slug ? (\n\t\t\t\t<div className=\"prose\">\n\t\t\t\t\t<callout-warning className=\"notification\">\n\t\t\t\t\t\tPlease{' '}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={`https://${config.product.host}/workshops/${config.product.slug}`}\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tupgrade\n\t\t\t\t\t\t</a>{' '}\n\t\t\t\t\t\tyour account to get full access to this workshop.\n\t\t\t\t\t</callout-warning>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<p className=\"text-center text-gray-700 dark:text-gray-300\">\n\t\t\t\t{user.name\n\t\t\t\t\t? `Hi ${\n\t\t\t\t\t\t\tdiscordMember?.displayName ?? user.name\n\t\t\t\t\t\t}, your device is logged in with ${user.email}.`\n\t\t\t\t\t: `Your device is logged in with ${user.email}.`}\n\t\t\t</p>\n\t\t\t{discordMember ? (\n\t\t\t\t<>\n\t\t\t\t\t<p className=\"text-center text-gray-700 dark:text-gray-300\">\n\t\t\t\t\t\tAnd you are connected to discord as{' '}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={`https://discord.com/users/${discordMember.id}`}\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{discordMember.displayName}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t.\n\t\t\t\t\t</p>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<Link\n\t\t\t\t\t\tto={connectDiscordURL}\n\t\t\t\t\t\tclassName=\"inline-flex items-center gap-2 underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Discord\" size=\"lg\" />\n\t\t\t\t\t\tConnect Discord\n\t\t\t\t\t</Link>\n\t\t\t\t\t<SimpleTooltip content=\"This will give you access to the exclusive Discord channels for Epic Web\">\n\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<Form method=\"post\">\n\t\t\t\t\t<Button varient=\"mono\" name=\"intent\" value=\"logout\">\n\t\t\t\t\t\tLog device out\n\t\t\t\t\t</Button>\n\t\t\t\t</Form>\n\t\t\t\t<SimpleTooltip\n\t\t\t\t\tcontent={\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\tNote: it is your <i className=\"italic\">device</i> that's logged\n\t\t\t\t\t\t\tin, not your browser.\n\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\tSo all browsers on this device will be logged in with the same\n\t\t\t\t\t\t\taccount on this device.\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t</SimpleTooltip>\n\t\t\t</div>\n\t\t\t<hr className=\"w-full\" />\n\t\t\t<ul className=\"flex list-inside list-disc flex-col gap-2 self-start\">\n\t\t\t\t<li>\n\t\t\t\t\t<Link\n\t\t\t\t\t\tto={`https://${config.product.host}/profile`}\n\t\t\t\t\t\tclassName=\"inline-flex gap-1 underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<span>Manage your account</span>\n\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t</Link>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<Link to=\"/preferences\" className=\"underline\">\n\t\t\t\t\t\tManage your preferences\n\t\t\t\t\t</Link>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<Link to=\"/support\" className=\"underline\">\n\t\t\t\t\t\tGet support\n\t\t\t\t\t</Link>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</main>\n\t)\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { type CacheEntry } from '@epic-web/cachified'\nimport { getAppFromFile } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcachified,\n\tcompiledCodeCache,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getDirModifiedTime } from '@epic-web/workshop-utils/modified-time.server'\nimport { type Timings } from '@epic-web/workshop-utils/timing.server'\nimport * as esbuild from 'esbuild'\n\nasync function getForceFresh(\n\tfilePath: string,\n\tcacheEntry:\n\t\t| CacheEntry\n\t\t| null\n\t\t| undefined\n\t\t| Promise<CacheEntry | null | undefined>,\n) {\n\tcacheEntry = await cacheEntry\n\tif (!cacheEntry) return true\n\tconst app = await getAppFromFile(filePath)\n\tif (!app) return true\n\tconst appModified = await getDirModifiedTime(app.fullPath)\n\tconst cacheModified = cacheEntry.metadata.createdTime\n\treturn !cacheModified || appModified > cacheModified || undefined\n}\n\nexport async function compileTs(\n\tfilePath: string,\n\tfullPath: string,\n\t{\n\t\tesbuildOptions,\n\t\tforceFresh,\n\t\trequest,\n\t\ttimings,\n\t}: {\n\t\tforceFresh?: boolean\n\t\trequest?: Request\n\t\ttimings?: Timings\n\t\tesbuildOptions?: esbuild.BuildOptions\n\t} = {},\n) {\n\tconst key = `${filePath}::${fullPath}`\n\treturn cachified({\n\t\tkey,\n\t\trequest,\n\t\ttimings,\n\t\tforceFresh:\n\t\t\tforceFresh ||\n\t\t\t(await getForceFresh(filePath, compiledCodeCache.get(key))) ||\n\t\t\t(await getForceFresh(fullPath, compiledCodeCache.get(key))),\n\t\tcache: compiledCodeCache,\n\t\tgetFreshValue: async () => {\n\t\t\tconst result = await esbuild.build({\n\t\t\t\tstdin: {\n\t\t\t\t\tcontents: await fs.promises.readFile(filePath, 'utf-8'),\n\t\t\t\t\t// NOTE: if the fileAppName is specified, then we're resolving to a different\n\t\t\t\t\t// app than the one we're serving the file from. We do this so the tests\n\t\t\t\t\t// can live in the solution directory, but be run against the problem\n\t\t\t\t\tresolveDir: fullPath,\n\t\t\t\t\tsourcefile: path.basename(filePath),\n\t\t\t\t\tloader: 'tsx',\n\t\t\t\t},\n\t\t\t\tdefine: {\n\t\t\t\t\t'process.env': JSON.stringify({ NODE_ENV: 'development' }),\n\t\t\t\t},\n\t\t\t\tbundle: true,\n\t\t\t\twrite: false,\n\t\t\t\tformat: 'esm',\n\t\t\t\tplatform: 'browser',\n\t\t\t\tjsx: 'automatic',\n\t\t\t\tminify: false,\n\t\t\t\tsourcemap: 'inline',\n\t\t\t\t...esbuildOptions,\n\t\t\t})\n\t\t\treturn result\n\t\t},\n\t})\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport {\n\tgetAppByName,\n\tgetApps,\n\tisPlaygroundApp,\n\tisProblemApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { type Timings } from '@epic-web/workshop-utils/timing.server'\nimport fsExtra from 'fs-extra'\nimport { type Params } from 'react-router'\n\nfunction parseAppNameFromReferer(request: Request) {\n\ttry {\n\t\tconst url = new URL(request.headers.get('referer') ?? '')\n\t\tconst appName = url.pathname.split('/').pop()\n\t\treturn appName ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nexport async function resolveApps({\n\trequest,\n\tparams,\n\ttimings,\n}: {\n\trequest: Request\n\tparams: Params\n\ttimings: Timings\n}) {\n\tconst appName = params.appName ?? parseAppNameFromReferer(request)\n\n\tinvariantResponse(appName, 'appName param required')\n\tconst app = await getAppByName(appName, { request, timings })\n\n\tlet fileAppName: string | null = app?.name ?? null\n\tif (isProblemApp(app)) {\n\t\tfileAppName = isProblemApp(app) ? app.solutionName : null\n\t}\n\tif (isPlaygroundApp(app)) {\n\t\tconst appBasis = await getAppByName(app.appName)\n\t\tfileAppName = isProblemApp(appBasis) ? appBasis.solutionName : null\n\t}\n\tif (fileAppName) {\n\t\tconst apps = await getApps({ request, timings })\n\t\tconst fileApp = fileAppName\n\t\t\t? apps.find((app) => app.name === fileAppName)\n\t\t\t: app\n\t\treturn { app, fileApp }\n\t} else {\n\t\treturn { app, fileApp: app }\n\t}\n}\n\nfunction unique<ItemType>(\n\tvalue: ItemType,\n\tindex: number,\n\tself: Array<ItemType>,\n) {\n\treturn self.indexOf(value) === index\n}\n\nexport async function firstExisting(...files: Array<string>) {\n\tfor (const file of files.filter(unique)) {\n\t\tif (await fsExtra.pathExists(file)) {\n\t\t\treturn file\n\t\t}\n\t}\n\treturn null\n}\n","import path from 'path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport etag from 'etag'\nimport fsExtra from 'fs-extra'\nimport mimeTypes from 'mime-types'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\nimport { compileTs } from '#app/utils/compile-app.server.ts'\nimport {\n\tcombineHeaders,\n\tensureUndeployed,\n\tgetBaseUrl,\n} from '#app/utils/misc.tsx'\nimport { firstExisting, resolveApps } from './__utils.ts'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('app-file')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.dev.type === 'script') {\n\t\treturn redirect(getBaseUrl({ request, port: app.dev.portNumber }))\n\t}\n\tconst splat = params['*']\n\tinvariantResponse(splat, 'splat required')\n\n\tconst filePath = await firstExisting(\n\t\tpath.join(app.fullPath, splat),\n\t\tpath.join(fileApp.fullPath, splat),\n\t)\n\tif (!filePath) {\n\t\tthrow new Response('File not found', { status: 404 })\n\t}\n\tif (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {\n\t\t// compile ts/tsx files\n\t\tconst { outputFiles, errors } = await compileTs(filePath, app.fullPath, {\n\t\t\trequest,\n\t\t\ttimings,\n\t\t})\n\t\tif (errors.length) {\n\t\t\tconsole.error(`Failed to compile file \"${filePath}\"`)\n\t\t\tconsole.error(errors)\n\t\t\tthrow new Response(errors.join('\\n'), { status: 500 })\n\t\t}\n\t\tif (!outputFiles?.[0]) {\n\t\t\tthrow new Response('Failed to compile file', { status: 500 })\n\t\t}\n\t\tconst file = outputFiles[0].text\n\t\treturn getFileResponse(file, { 'Content-Type': 'text/javascript' })\n\t} else {\n\t\tconst file = await fsExtra.readFile(filePath)\n\t\tconst mimeType = mimeTypes.lookup(filePath) || 'text/plain'\n\t\treturn getFileResponse(file, { 'Content-Type': mimeType })\n\t}\n\n\tfunction getFileResponse(file: Buffer | string, headers: HeadersInit = {}) {\n\t\tconst etagValue = etag(file)\n\t\tconst ifNoneMatch = request.headers.get('if-none-match')\n\t\tif (ifNoneMatch === etagValue) {\n\t\t\treturn new Response(null, { status: 304 })\n\t\t}\n\t\t// @ts-ignore 🤷‍♂️ CLI doesn't like this but editor is fine 🙃\n\t\treturn new Response(file, {\n\t\t\theaders: combineHeaders(\n\t\t\t\t{\n\t\t\t\t\t'Content-Length': Buffer.byteLength(file).toString(),\n\t\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t\t\tETag: etagValue,\n\t\t\t\t},\n\t\t\t\theaders,\n\t\t\t),\n\t\t})\n\t}\n}\n","import path from 'node:path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport fsExtra from 'fs-extra'\nimport {\n\tredirect,\n\ttype ActionFunctionArgs,\n\ttype LoaderFunctionArgs,\n} from 'react-router'\nimport { z } from 'zod'\nimport { compileTs } from '#app/utils/compile-app.server.ts'\nimport { ensureUndeployed, getBaseUrl } from '#app/utils/misc.tsx'\nimport { resolveApps } from './__utils'\n\nexport async function loader(args: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst api = await getApiModule(args)\n\tinvariantResponse(\n\t\tapi.mod.loader,\n\t\t'Attempted to make a GET request to the api endpoint but the api module does not export a loader function',\n\t\t{ status: 405 },\n\t)\n\ttry {\n\t\tconst result = await api.mod.loader(args)\n\t\treturn result\n\t} catch (error) {\n\t\tapi.cleanupError(error)\n\t}\n}\n\nexport async function action(args: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst api = await getApiModule(args)\n\tinvariantResponse(\n\t\tapi.mod.action,\n\t\t'Attempted to make a non-GET request to the api endpoint but the api module does not export an action function',\n\t\t{ status: 405 },\n\t)\n\ttry {\n\t\tconst result = await api.mod.action(args)\n\t\treturn result\n\t} catch (error) {\n\t\tapi.cleanupError(error)\n\t}\n}\n\nconst ApiModuleSchema = z.object({\n\tloader: z.function().optional(),\n\taction: z.function().optional(),\n})\n\nasync function getApiModule({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('app-api')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.dev.type === 'script') {\n\t\tthrow redirect(getBaseUrl({ request, port: app.dev.portNumber }))\n\t}\n\n\tconst apiFiles = (await fsExtra.readdir(app.fullPath))\n\t\t.filter((file: string) => /^api\\.server\\.(ts|tsx|js|jsx)$/.test(file))\n\t\t.map((f) => path.join(app.fullPath, f))\n\tconst apiFile = apiFiles[0]\n\tif (!apiFile) {\n\t\tthrow new Response(\n\t\t\t`No api.server.(ts|tsx|js|jsx) file found in \"${app.fullPath}\"`,\n\t\t\t{ status: 404 },\n\t\t)\n\t}\n\tif (apiFiles.length > 1) {\n\t\tthrow new Response(\n\t\t\t`Only one api.server.(ts|tsx|js|jsx) file is allowed, found ${apiFiles.join(', ')}`,\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\n\tconst { outputFiles, errors } = await compileTs(apiFile, app.fullPath, {\n\t\tesbuildOptions: {\n\t\t\tplatform: 'node',\n\t\t\t// packages external causes issues in Node 20 because Node tries to resolve the package.json from the data URL 🤷‍♂️\n\t\t\t// packages: 'external', // figure out how to turn this on in the future...\n\t\t\t// just adds noise to errors and doesn't appear to help with debugging\n\t\t\tsourcemap: false,\n\t\t\t// remove the process.env define\n\t\t\tdefine: {},\n\t\t},\n\t\trequest,\n\t\ttimings,\n\t})\n\tif (errors.length) {\n\t\tconsole.error(`Failed to compile file \"${apiFile}\"`)\n\t\tconsole.error(errors)\n\t\tthrow new Response(errors.join('\\n'), { status: 500 })\n\t}\n\tif (!outputFiles?.[0]) {\n\t\tthrow new Response(`Failed to compile file \"${apiFile}\"`, { status: 500 })\n\t}\n\tconst apiCode = outputFiles[0].text\n\tconst dataUrl = `data:text/javascript;base64,${Buffer.from(apiCode).toString('base64')}`\n\tconst mod = await import(/* @vite-ignore */ dataUrl).catch(cleanupError)\n\tconst apiModule = ApiModuleSchema.safeParse(mod)\n\tif (!apiModule.success) {\n\t\tthrow new Response(\n\t\t\t`Invalid api module. It should export a loader and/or action: ${apiModule.error.message}`,\n\t\t\t{ status: 500 },\n\t\t)\n\t}\n\treturn {\n\t\tmod: apiModule.data,\n\t\tcleanupError,\n\t}\n\n\tfunction cleanupError(error: unknown) {\n\t\tif (apiFile && error instanceof Error && error.stack) {\n\t\t\terror.stack = error.stack.replace(dataUrl, apiFile)\n\t\t}\n\t\tthrow error\n\t}\n}\n","import { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\nimport { ensureUndeployed, getBaseUrl } from '#app/utils/misc.tsx'\nimport { resolveApps } from './__utils.ts'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('epic_ws script')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.dev.type === 'script') {\n\t\treturn redirect(getBaseUrl({ request, port: app.dev.portNumber }))\n\t}\n\tconst relevantPaths = Array.from(new Set([app.fullPath, fileApp.fullPath]))\n\tconst watchParams = new URLSearchParams()\n\tfor (const path of relevantPaths) {\n\t\twatchParams.append('watch', path)\n\t}\n\n\tconst js = /* javascript */ `\n\tfunction epicLiveReloadConnect(config) {\n\t\tconst protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n\t\tconst host = location.hostname;\n\t\tconst port = location.port;\n\t\tconst socketPath = protocol + \"//\" + host + \":\" + port + \"/__ws?\" + ${JSON.stringify(watchParams.toString())};\n\t\tconst ws = new WebSocket(socketPath);\n\t\tws.onmessage = (message) => {\n\t\t\tconst event = JSON.parse(message.data);\n\t\t\tif (event.type !== 'epicshop:file-change') return;\n\t\t\tconst { filePaths } = event.data;\n\t\t\tconsole.log(\n\t\t\t\t['🐨 Reloading', window.frameElement?.getAttribute('title'), 'due to file changes:']\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(' '),\n\t\t\t\tfilePaths\n\t\t\t);\n\t\t\twindow.location.reload();\n\t\t};\n\t\tws.onopen = () => {\n\t\t\tif (config && typeof config.onOpen === \"function\") {\n\t\t\t\tconfig.onOpen();\n\t\t\t}\n\t\t};\n\t\tws.onclose = (event) => {\n\t\t\tif (event.code === 1006) {\n\t\t\t\tconsole.log(\"EpicShop dev server web socket closed. Reconnecting...\");\n\t\t\t\tsetTimeout(\n\t\t\t\t\t() =>\n\t\t\t\t\t\tepicLiveReloadConnect({\n\t\t\t\t\t\t\tonOpen: () => window.location.reload(),\n\t\t\t\t\t\t}),\n\t\t\t\t\t1000\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\t\tws.onerror = (error) => {\n\t\t\tconsole.log(\"EpicShop dev server web socket error:\");\n\t\t\tconsole.error(error);\n\t\t};\n\t}\n\tepicLiveReloadConnect();\n\t`\n\treturn new Response(js, {\n\t\theaders: {\n\t\t\t'Content-Length': Buffer.byteLength(js).toString(),\n\t\t\t'Content-Type': 'text/javascript',\n\t\t},\n\t})\n}\n","import path from 'path'\nimport {\n\tgetAppByName,\n\tgetExercise,\n\tisExampleApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\tisProblemApp,\n\tisSolutionApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport fsExtra from 'fs-extra'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\nimport { ensureUndeployed, getBaseUrl } from '#app/utils/misc.tsx'\nimport { resolveApps } from './__utils.ts'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('app')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tconst baseApp = isPlaygroundApp(app) ? await getAppByName(app.appName) : app\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (app.dev.type === 'script') {\n\t\treturn redirect(getBaseUrl({ request, port: app.dev.portNumber }), {\n\t\t\theaders: { 'Server-Timing': getServerTimeHeader(timings) },\n\t\t})\n\t}\n\tif (app.dev.type !== 'browser' && app.dev.type !== 'export') {\n\t\tthrow new Response(\n\t\t\t`App \"${app.name}\" is not a browser or export app, its dev type is: \"${app.dev.type}\"`,\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\tconst htmlFile = path.join(app.fullPath, 'index.html')\n\tconst hasHtml = await fsExtra.pathExists(htmlFile)\n\tif (hasHtml) {\n\t\tconst html = await fsExtra.readFile(htmlFile)\n\t\treturn new Response(html, {\n\t\t\theaders: {\n\t\t\t\t'Content-Length': Buffer.byteLength(html).toString(),\n\t\t\t\t'Content-Type': 'text/html',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t})\n\t}\n\tconst indexFiles = (await fsExtra.readdir(app.fullPath)).filter(\n\t\t(file: string) => file.startsWith('index.'),\n\t)\n\tconst indexCss = indexFiles.find((file: string) => file.endsWith('index.css'))\n\tconst indexJs = indexFiles.find((file: string) => file.endsWith('index.js'))\n\tconst indexTs = indexFiles.find((file: string) => file.endsWith('index.ts'))\n\tconst indexTsx = indexFiles.find((file: string) => file.endsWith('index.tsx'))\n\tconst scripts = [indexJs, indexTs, indexTsx].filter(Boolean)\n\tif (scripts.length > 1) {\n\t\tthrow new Response(\n\t\t\t`Only one index.(js|ts|tsx) file is allowed, found ${scripts.join(', ')}`,\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\tconst appTitle = app.title\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst baseAppTitle = isExerciseStepApp(baseApp)\n\t\t? [\n\t\t\t\t`${baseApp.stepNumber.toString().padStart(2, '0')}. ${baseApp.title}`,\n\t\t\t\t`${baseApp.exerciseNumber.toString().padStart(2, '0')}. ${\n\t\t\t\t\t(await getExercise(baseApp.exerciseNumber, { request, timings }))\n\t\t\t\t\t\t?.title ?? 'Unknown'\n\t\t\t\t}`,\n\t\t\t\tworkshopTitle,\n\t\t\t]\n\t\t: [baseApp?.title ?? 'N/A']\n\tconst title = (\n\t\tisExerciseStepApp(app)\n\t\t\t? [\n\t\t\t\t\tisProblemApp(app) ? '💪' : isSolutionApp(app) ? '🏁' : null,\n\t\t\t\t\t...baseAppTitle,\n\t\t\t\t]\n\t\t\t: isPlaygroundApp(app)\n\t\t\t\t? ['🛝', ...baseAppTitle]\n\t\t\t\t: isExampleApp(app)\n\t\t\t\t\t? ['📚', ...baseAppTitle]\n\t\t\t\t\t: [appTitle]\n\t)\n\t\t.filter(Boolean)\n\t\t.join(' | ')\n\n\t// Generate different HTML for export apps vs browser apps\n\tconst isExportApp = app.dev.type === 'export'\n\tconst html = isExportApp\n\t\t? generateExportAppHtml({\n\t\t\t\tpathname: app.dev.pathname,\n\t\t\t\ttitle,\n\t\t\t\tindexCss,\n\t\t\t\tscripts,\n\t\t\t})\n\t\t: generateBrowserAppHtml({\n\t\t\t\tpathname: app.dev.pathname,\n\t\t\t\ttitle,\n\t\t\t\tindexCss,\n\t\t\t\tscripts,\n\t\t\t})\n\n\treturn new Response(html, {\n\t\theaders: {\n\t\t\t'Content-Length': Buffer.byteLength(html).toString(),\n\t\t\t'Content-Type': 'text/html',\n\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t},\n\t})\n}\n\nfunction generateBrowserAppHtml({\n\tpathname,\n\ttitle,\n\tindexCss,\n\tscripts,\n}: {\n\tpathname: string\n\ttitle: string\n\tindexCss: string | undefined\n\tscripts: Array<string>\n}) {\n\treturn /* html */ `\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<base href=\"${pathname}\" />\n\t\t<meta charset=\"utf-8\">\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t\t<title>${title}</title>\n\t\t<link rel=\"stylesheet\" href=\"/app-default.css\">\n\t\t${indexCss ? `<link rel=\"stylesheet\" href=\"${indexCss}\">` : ''}\n\t</head>\n\t<body>\n\t\t${scripts\n\t\t\t.map((script) => `<script type=\"module\" src=\"${script}\"></script>`)\n\t\t\t.join('\\n')}\n\t\t<script type=\"module\" src=\"epic_ws.js\"></script>\n\t</body>\n</html>\n`\n}\n\nfunction generateExportAppHtml({\n\tpathname,\n\ttitle,\n\tindexCss,\n\tscripts,\n}: {\n\tpathname: string\n\ttitle: string\n\tindexCss: string | undefined\n\tscripts: Array<string>\n}) {\n\tconst scriptFile = scripts[0] || 'index.js'\n\n\treturn /* html */ `\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<base href=\"${pathname}\" />\n\t\t<meta charset=\"utf-8\">\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t\t<title>${title}</title>\n\t\t<link rel=\"stylesheet\" href=\"/app-default.css\">\n\t\t<link rel=\"stylesheet\" href=\"/export-app.css\">\n\t\t${indexCss ? `<link rel=\"stylesheet\" href=\"${indexCss}\">` : ''}\n\t</head>\n\t<body>\n\t\t<div id=\"epicshop-export-app-root\">\n\t\t\t<div id=\"epicshop-console-output\">\n\t\t\t\t<h2>Console Output</h2>\n\t\t\t\t<div id=\"epicshop-console-entries\"></div>\n\t\t\t</div>\n\t\t\t<div id=\"epicshop-exports\">\n\t\t\t\t<h2>Exports</h2>\n\t\t\t\t<div id=\"epicshop-exports-entries\"></div>\n\t\t\t</div>\n\t\t</div>\n\t\t<script type=\"module\">\n\t\t\t// Hijack console methods to capture output\n\t\t\tconst consoleEntriesEl = document.getElementById('epicshop-console-entries');\n\t\t\tconst exportsEntriesEl = document.getElementById('epicshop-exports-entries');\n\n\t\t\tconst originalConsole = {\n\t\t\t\tlog: console.log.bind(console),\n\t\t\t\twarn: console.warn.bind(console),\n\t\t\t\terror: console.error.bind(console),\n\t\t\t\tinfo: console.info.bind(console),\n\t\t\t\tdebug: console.debug.bind(console),\n\t\t\t};\n\n\t\t\tfunction isPromise(value) {\n\t\t\t\treturn value && typeof value === 'object' && typeof value.then === 'function';\n\t\t\t}\n\n\t\t\tfunction formatValue(value, seen = new WeakSet()) {\n\t\t\t\tif (value === null) return '<span class=\"value-null\">null</span>';\n\t\t\t\tif (value === undefined) return '<span class=\"value-undefined\">undefined</span>';\n\n\t\t\t\tconst type = typeof value;\n\n\t\t\t\tif (type === 'string') {\n\t\t\t\t\treturn '<span class=\"value-string\">\"' + escapeHtml(value) + '\"</span>';\n\t\t\t\t}\n\t\t\t\tif (type === 'number') {\n\t\t\t\t\tif (Number.isNaN(value)) return '<span class=\"value-number\">NaN</span>';\n\t\t\t\t\tif (!Number.isFinite(value)) return '<span class=\"value-number\">' + (value > 0 ? 'Infinity' : '-Infinity') + '</span>';\n\t\t\t\t\treturn '<span class=\"value-number\">' + value + '</span>';\n\t\t\t\t}\n\t\t\t\tif (type === 'boolean') {\n\t\t\t\t\treturn '<span class=\"value-boolean\">' + value + '</span>';\n\t\t\t\t}\n\t\t\t\tif (type === 'bigint') {\n\t\t\t\t\treturn '<span class=\"value-bigint\">' + value + 'n</span>';\n\t\t\t\t}\n\t\t\t\tif (type === 'symbol') {\n\t\t\t\t\treturn '<span class=\"value-symbol\">' + value.toString() + '</span>';\n\t\t\t\t}\n\t\t\t\tif (type === 'function') {\n\t\t\t\t\tconst name = value.name || 'anonymous';\n\t\t\t\t\treturn '<span class=\"value-function\">[Function: ' + escapeHtml(name) + ']</span>';\n\t\t\t\t}\n\n\t\t\t\tif (type === 'object') {\n\t\t\t\t\tif (seen.has(value)) {\n\t\t\t\t\t\treturn '<span class=\"value-circular\">[Circular]</span>';\n\t\t\t\t\t}\n\t\t\t\t\tseen.add(value);\n\n\t\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\t\tif (value.length === 0) return '<span class=\"value-array\">[]</span>';\n\t\t\t\t\t\tconst items = value.map(v => formatValue(v, seen)).join(', ');\n\t\t\t\t\t\treturn '<span class=\"value-array\">[' + items + ']</span>';\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value instanceof Error) {\n\t\t\t\t\t\treturn '<span class=\"value-error\">' + escapeHtml(value.stack || value.message) + '</span>';\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value instanceof Date) {\n\t\t\t\t\t\treturn '<span class=\"value-date\">' + value.toISOString() + '</span>';\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value instanceof RegExp) {\n\t\t\t\t\t\treturn '<span class=\"value-regexp\">' + value.toString() + '</span>';\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value instanceof Map) {\n\t\t\t\t\t\tif (value.size === 0) return '<span class=\"value-map\">Map(0) {}</span>';\n\t\t\t\t\t\tconst entries = Array.from(value.entries()).map(([k, v]) => {\n\t\t\t\t\t\t\treturn formatValue(k, seen) + ' => ' + formatValue(v, seen);\n\t\t\t\t\t\t}).join(', ');\n\t\t\t\t\t\treturn '<span class=\"value-map\">Map(' + value.size + ') { ' + entries + ' }</span>';\n\t\t\t\t\t}\n\n\t\t\t\t\tif (value instanceof Set) {\n\t\t\t\t\t\tif (value.size === 0) return '<span class=\"value-set\">Set(0) {}</span>';\n\t\t\t\t\t\tconst items = Array.from(value).map(v => formatValue(v, seen)).join(', ');\n\t\t\t\t\t\treturn '<span class=\"value-set\">Set(' + value.size + ') { ' + items + ' }</span>';\n\t\t\t\t\t}\n\n\t\t\t\t\t// Plain object\n\t\t\t\t\tconst keys = Object.keys(value);\n\t\t\t\t\tif (keys.length === 0) return '<span class=\"value-object\">{}</span>';\n\t\t\t\t\tconst entries = keys.map(key => {\n\t\t\t\t\t\treturn '<span class=\"value-key\">' + escapeHtml(key) + '</span>: ' + formatValue(value[key], seen);\n\t\t\t\t\t}).join(', ');\n\t\t\t\t\treturn '<span class=\"value-object\">{ ' + entries + ' }</span>';\n\t\t\t\t}\n\n\t\t\t\treturn escapeHtml(String(value));\n\t\t\t}\n\n\t\t\tfunction escapeHtml(str) {\n\t\t\t\treturn String(str)\n\t\t\t\t\t.replace(/&/g, '&amp;')\n\t\t\t\t\t.replace(/</g, '&lt;')\n\t\t\t\t\t.replace(/>/g, '&gt;')\n\t\t\t\t\t.replace(/\"/g, '&quot;')\n\t\t\t\t\t.replace(/'/g, '&#039;');\n\t\t\t}\n\n\t\t\t// Parse error stack to extract code frame information\n\t\t\tfunction parseErrorForCodeFrame(error) {\n\t\t\t\t// Handle null/undefined/primitive values\n\t\t\t\tif (error === null || error === undefined) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessage: String(error),\n\t\t\t\t\t\tstack: '',\n\t\t\t\t\t\tlocation: null,\n\t\t\t\t\t\tisSyntaxError: false,\n\t\t\t\t\t\tisNonError: true\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Handle primitive values (strings, numbers, etc.)\n\t\t\t\tif (typeof error !== 'object') {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessage: String(error),\n\t\t\t\t\t\tstack: '',\n\t\t\t\t\t\tlocation: null,\n\t\t\t\t\t\tisSyntaxError: false,\n\t\t\t\t\t\tisNonError: true\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst stack = error.stack || '';\n\t\t\t\tconst message = error.message || String(error);\n\n\t\t\t\t// Try to extract file location from stack\n\t\t\t\tconst locationMatch = stack.match(/at\\\\s+(?:.*\\\\s+)?\\\\(?([^)]+):(\\\\d+):(\\\\d+)\\\\)?/);\n\t\t\t\tlet location = null;\n\t\t\t\tif (locationMatch) {\n\t\t\t\t\tlocation = {\n\t\t\t\t\t\tfile: locationMatch[1],\n\t\t\t\t\t\tline: parseInt(locationMatch[2], 10),\n\t\t\t\t\t\tcolumn: parseInt(locationMatch[3], 10)\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Check for syntax error patterns\n\t\t\t\tconst isSyntaxError = error instanceof SyntaxError ||\n\t\t\t\t\tmessage.includes('SyntaxError') ||\n\t\t\t\t\tmessage.includes('Unexpected token') ||\n\t\t\t\t\tmessage.includes('Unexpected identifier') ||\n\t\t\t\t\tmessage.includes('Cannot use import');\n\n\t\t\t\treturn { message, stack, location, isSyntaxError, isNonError: false };\n\t\t\t}\n\n\t\t\tfunction formatError(error) {\n\t\t\t\tconst { message, stack, location, isSyntaxError, isNonError } = parseErrorForCodeFrame(error);\n\n\t\t\t\tlet html = '<div class=\"error-container\">';\n\n\t\t\t\t// Error type badge - handle non-Error rejection values\n\t\t\t\tlet errorType;\n\t\t\t\tif (isNonError) {\n\t\t\t\t\terrorType = 'Rejected';\n\t\t\t\t} else if (isSyntaxError) {\n\t\t\t\t\terrorType = 'Syntax Error';\n\t\t\t\t} else {\n\t\t\t\t\terrorType = (error && error.name) || 'Error';\n\t\t\t\t}\n\t\t\t\thtml += '<div class=\"error-type\">' + escapeHtml(errorType) + '</div>';\n\n\t\t\t\t// Error message\n\t\t\t\thtml += '<div class=\"error-message\">' + escapeHtml(message) + '</div>';\n\n\t\t\t\t// Location info\n\t\t\t\tif (location) {\n\t\t\t\t\thtml += '<div class=\"error-location\">at ' + escapeHtml(location.file) + ':' + location.line + ':' + location.column + '</div>';\n\t\t\t\t}\n\n\t\t\t\t// Stack trace (collapsible)\n\t\t\t\tif (stack && stack !== message) {\n\t\t\t\t\thtml += '<details class=\"error-stack-details\">';\n\t\t\t\t\thtml += '<summary>Stack trace</summary>';\n\t\t\t\t\thtml += '<pre class=\"error-stack\">' + escapeHtml(stack) + '</pre>';\n\t\t\t\t\thtml += '</details>';\n\t\t\t\t}\n\n\t\t\t\thtml += '</div>';\n\t\t\t\treturn html;\n\t\t\t}\n\n\t\t\tfunction createConsoleEntry(type, args) {\n\t\t\t\tconst entry = document.createElement('div');\n\t\t\t\tentry.className = 'console-entry console-' + type;\n\n\t\t\t\tconst typeLabel = document.createElement('span');\n\t\t\t\ttypeLabel.className = 'console-type';\n\t\t\t\ttypeLabel.textContent = type.toUpperCase();\n\t\t\t\tentry.appendChild(typeLabel);\n\n\t\t\t\tconst content = document.createElement('span');\n\t\t\t\tcontent.className = 'console-content';\n\n\t\t\t\t// Special handling for errors\n\t\t\t\tif (type === 'error' && args.length > 0 && args[args.length - 1] instanceof Error) {\n\t\t\t\t\tconst nonErrorArgs = args.slice(0, -1);\n\t\t\t\t\tconst errorArg = args[args.length - 1];\n\t\t\t\t\tif (nonErrorArgs.length > 0) {\n\t\t\t\t\t\tcontent.innerHTML = nonErrorArgs.map(arg => formatValue(arg)).join(' ') + ' ';\n\t\t\t\t\t}\n\t\t\t\t\tcontent.innerHTML += formatError(errorArg);\n\t\t\t\t} else {\n\t\t\t\t\tcontent.innerHTML = args.map(arg => {\n\t\t\t\t\t\tif (arg instanceof Error) {\n\t\t\t\t\t\t\treturn formatError(arg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn formatValue(arg);\n\t\t\t\t\t}).join(' ');\n\t\t\t\t}\n\n\t\t\t\tentry.appendChild(content);\n\t\t\t\tconsoleEntriesEl.appendChild(entry);\n\n\t\t\t\t// Scroll to bottom\n\t\t\t\tconsoleEntriesEl.scrollTop = consoleEntriesEl.scrollHeight;\n\t\t\t}\n\n\t\t\t// Override console methods\n\t\t\t['log', 'warn', 'error', 'info', 'debug'].forEach(method => {\n\t\t\t\tconsole[method] = function(...args) {\n\t\t\t\t\toriginalConsole[method](...args);\n\t\t\t\t\tcreateConsoleEntry(method, args);\n\t\t\t\t};\n\t\t\t});\n\n\t\t\t// Function to create an export entry element\n\t\t\tfunction createExportEntry(key, initialContent, className = '') {\n\t\t\t\tconst entry = document.createElement('div');\n\t\t\t\tentry.className = 'export-entry' + (className ? ' ' + className : '');\n\n\t\t\t\tconst nameEl = document.createElement('span');\n\t\t\t\tnameEl.className = 'export-name';\n\t\t\t\tnameEl.textContent = key;\n\t\t\t\tentry.appendChild(nameEl);\n\n\t\t\t\tconst colonEl = document.createElement('span');\n\t\t\t\tcolonEl.className = 'export-colon';\n\t\t\t\tcolonEl.textContent = ': ';\n\t\t\t\tentry.appendChild(colonEl);\n\n\t\t\t\tconst valueEl = document.createElement('span');\n\t\t\t\tvalueEl.className = 'export-value';\n\t\t\t\tvalueEl.innerHTML = initialContent;\n\t\t\t\tentry.appendChild(valueEl);\n\n\t\t\t\treturn { entry, valueEl };\n\t\t\t}\n\n\t\t\t// Function to display exports with Promise support\n\t\t\tasync function displayExports(exports) {\n\t\t\t\texportsEntriesEl.innerHTML = '';\n\n\t\t\t\tconst keys = Object.keys(exports);\n\t\t\t\tif (keys.length === 0) {\n\t\t\t\t\tconst emptyMsg = document.createElement('div');\n\t\t\t\t\temptyMsg.className = 'export-empty';\n\t\t\t\t\temptyMsg.textContent = 'No named exports found';\n\t\t\t\t\texportsEntriesEl.appendChild(emptyMsg);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tconst value = exports[key];\n\n\t\t\t\t\tif (isPromise(value)) {\n\t\t\t\t\t\t// Show pending state for promises\n\t\t\t\t\t\tconst { entry, valueEl } = createExportEntry(\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\t'<span class=\"value-promise\"><span class=\"promise-badge\">Promise</span> <span class=\"promise-status pending\">⏳ pending...</span></span>',\n\t\t\t\t\t\t\t'export-promise'\n\t\t\t\t\t\t);\n\t\t\t\t\t\texportsEntriesEl.appendChild(entry);\n\n\t\t\t\t\t\t// Await the promise and update\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst resolvedValue = await value;\n\t\t\t\t\t\t\tvalueEl.innerHTML = '<span class=\"value-promise\"><span class=\"promise-badge\">Promise</span> <span class=\"promise-status resolved\">✓ resolved:</span> ' + formatValue(resolvedValue) + '</span>';\n\t\t\t\t\t\t\tentry.classList.remove('export-promise');\n\t\t\t\t\t\t\tentry.classList.add('export-promise-resolved');\n\t\t\t\t\t\t} catch (rejectedError) {\n\t\t\t\t\t\t\tvalueEl.innerHTML = '<span class=\"value-promise\"><span class=\"promise-badge\">Promise</span> <span class=\"promise-status rejected\">✗ rejected:</span> ' + formatError(rejectedError) + '</span>';\n\t\t\t\t\t\t\tentry.classList.remove('export-promise');\n\t\t\t\t\t\t\tentry.classList.add('export-promise-rejected');\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst { entry } = createExportEntry(key, formatValue(value));\n\t\t\t\t\t\texportsEntriesEl.appendChild(entry);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Display module load error\n\t\t\tfunction displayModuleError(error) {\n\t\t\t\texportsEntriesEl.innerHTML = '';\n\n\t\t\t\tconst errorDiv = document.createElement('div');\n\t\t\t\terrorDiv.className = 'module-error';\n\t\t\t\terrorDiv.innerHTML = '<h3>Failed to load module</h3>' + formatError(error);\n\t\t\t\texportsEntriesEl.appendChild(errorDiv);\n\t\t\t}\n\n\t\t\t// Dynamically import the index file and display exports\n\t\t\ttry {\n\t\t\t\tconst module = await import('./${scriptFile}');\n\t\t\t\tawait displayExports(module);\n\t\t\t} catch (error) {\n\t\t\t\toriginalConsole.error('Failed to import module:', error);\n\t\t\t\tdisplayModuleError(error);\n\t\t\t}\n\t\t</script>\n\t\t<script type=\"module\" src=\"epic_ws.js\"></script>\n\t</body>\n</html>\n`\n}\n","import path from 'path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport {\n\tgetExercise,\n\tisExerciseStepApp,\n\tisProblemApp,\n\tisSolutionApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { userHasAccessToWorkshop } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport fsExtra from 'fs-extra'\nimport { type LoaderFunctionArgs } from 'react-router'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\nimport { resolveApps } from './__utils.ts'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('app_test_loader')\n\tconst userHasAccess = await userHasAccessToWorkshop({\n\t\trequest,\n\t})\n\tconst { testName } = params\n\tinvariantResponse(testName, 'Test name is required')\n\tconst { fileApp, app } = await resolveApps({ request, params, timings })\n\tif (!fileApp || !app) {\n\t\tthrow new Response(`Apps not found`, { status: 404 })\n\t}\n\tif (\n\t\tapp.test.type !== 'browser' ||\n\t\t(app.dev.type !== 'browser' && app.dev.type !== 'export')\n\t) {\n\t\treturn redirectWithToast(\n\t\t\t'/',\n\t\t\t{\n\t\t\t\ttype: 'error',\n\t\t\t\ttitle: 'Unsupported',\n\t\t\t\tdescription: `Cannot load this app's tests in the browser`,\n\t\t\t},\n\t\t\t{ headers: { 'Server-Timing': getServerTimeHeader(timings) } },\n\t\t)\n\t}\n\n\tconst testFile = app.test.testFiles.find((file) => file === testName)\n\tif (!testFile) {\n\t\tthrow new Response(`Test \"${testName}\" not found`, {\n\t\t\tstatus: 404,\n\t\t\theaders: { 'Server-Timing': getServerTimeHeader(timings) },\n\t\t})\n\t}\n\tif (!/(js|ts|tsx)$/.test(testFile)) {\n\t\t// TODO: support other test file types?\n\t\tthrow new Response(`Test \"${testName}\" is not a script`, {\n\t\t\tstatus: 400,\n\t\t\theaders: { 'Server-Timing': getServerTimeHeader(timings) },\n\t\t})\n\t}\n\n\tconst testScriptPath = `${app.dev.pathname}${testFile}`\n\tconst testScriptSrc = /* javascript */ `\nfunction logStatus(message) {\n\tif (window.parent !== window) {\n\t\twindow.parent.postMessage(\n\t\t\t{ type: 'epicshop:test-status-update', ...message },\n\t\t\t'*',\n\t\t)\n\t} else {\n\t\tif (message.status === 'fail') {\n\t\t\tconsole.error(message)\n\t\t} else if (message.status === 'pending') {\n\t\t\tconsole.info(message)\n\t\t} else if (message.status === 'pass') {\n\t\t\tconsole.log(message)\n\t\t}\n\t}\n}\nconst testFile = ${JSON.stringify(testFile)}\nlogStatus({status: 'pending', timestamp: Date.now()})\nimport(${JSON.stringify(testScriptPath)}).then(\n\t() => {\n\t\tlogStatus({ status: 'pass', timestamp: Date.now() })\n\t},\n\terror => {\n\t\tlogStatus({\n\t\t\tstatus: 'fail',\n\t\t\terror:\n\t\t\t\ttypeof error === 'string'\n\t\t\t\t\t? error\n\t\t\t\t\t: typeof error === 'object' && error && 'message' in error\n\t\t\t\t\t? error.message\n\t\t\t\t\t: 'unknown error',\n\t\t\ttimestamp: Date.now(),\n\t\t})\n\t\tthrow error\n\t},\n)\n`\n\n\tconst testScriptTag = userHasAccess\n\t\t? `<script type=\"module\">${testScriptSrc}</script>`\n\t\t: `<h1>Access Denied</h1><p>You must login or register for the workshop to run the tests</p>`\n\n\tconst htmlFile = path.join(app.fullPath, 'index.html')\n\tconst hasHtml = await fsExtra.pathExists(htmlFile)\n\tif (hasHtml) {\n\t\tconst html = (await fsExtra.readFile(htmlFile)).toString()\n\t\tconst testableHtml = html.includes('</body/>')\n\t\t\t? html.replace(`</body>`, `\\n${testScriptTag}\\n</body>`)\n\t\t\t: `${html}\\n${testScriptTag}`\n\t\treturn new Response(testableHtml, {\n\t\t\theaders: {\n\t\t\t\t'Content-Length': Buffer.byteLength(testableHtml).toString(),\n\t\t\t\t'Content-Type': 'text/html',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t})\n\t}\n\n\tconst indexFiles = (await fsExtra.readdir(app.fullPath)).filter(\n\t\t(file: string) => file.startsWith('index.'),\n\t)\n\tconst indexCss = indexFiles.find((file: string) => file.endsWith('index.css'))\n\n\tconst appTitle = app.title\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst title = (\n\t\tisExerciseStepApp(app)\n\t\t\t? [\n\t\t\t\t\tisProblemApp(app) ? '🧪💪' : isSolutionApp(app) ? '🧪🏁' : null,\n\t\t\t\t\t`${app.stepNumber.toString().padStart(2, '0')}. ${app.title}`,\n\t\t\t\t\t`${app.exerciseNumber.toString().padStart(2, '0')}. ${\n\t\t\t\t\t\t(await getExercise(app.exerciseNumber, { request, timings }))\n\t\t\t\t\t\t\t?.title ?? 'Unknown'\n\t\t\t\t\t}`,\n\t\t\t\t\tworkshopTitle,\n\t\t\t\t]\n\t\t\t: ['🧪', appTitle]\n\t)\n\t\t.filter(Boolean)\n\t\t.join(' | ')\n\tconst html = /* html */ `\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<base href=\"${app.dev.pathname}\" />\n\t\t<meta charset=\"utf-8\">\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t\t<title>${title}</title>\n\t\t<link rel=\"stylesheet\" href=\"/app-default.css\">\n\t\t${indexCss ? `<link rel=\"stylesheet\" href=\"${indexCss}\">` : ''}\n\t</head>\n\t<body>\n\t\t${testScriptTag}\n\t\t<script type=\"module\" src=\"epic_ws.js\"></script>\n\t</body>\n</html>\n`\n\treturn new Response(html, {\n\t\theaders: {\n\t\t\t'Content-Length': Buffer.byteLength(html).toString(),\n\t\t\t'Content-Type': 'text/html',\n\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t},\n\t})\n}\n","import { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { Link } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport {\n\tuseOptionalDiscordMember,\n\tuseOptionalUser,\n} from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nfunction useConnectDiscordURL() {\n\tconst {\n\t\tproduct: { host },\n\t} = useWorkshopConfig()\n\treturn `https://${host}/discord`\n}\n\nexport function useDiscordCTALink() {\n\tconst user = useOptionalUser()\n\tconst discordMember = useOptionalDiscordMember()\n\tconst connectDiscordURL = useConnectDiscordURL()\n\n\tif (!user) {\n\t\treturn '/login'\n\t}\n\tif (!discordMember) {\n\t\treturn connectDiscordURL\n\t}\n\n\treturn 'https://discord.com/channels/715220730605731931/1161045224907341972'\n}\n\nexport function DiscordCTA() {\n\tconst user = useOptionalUser()\n\tconst discordMember = useOptionalDiscordMember()\n\tconst connectDiscordURL = useConnectDiscordURL()\n\tif (!user) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-wrap items-center justify-center gap-2 text-xl\">\n\t\t\t\t<Link to=\"/login\" className=\"inline-flex items-center gap-2 underline\">\n\t\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t\t\tLogin\n\t\t\t\t</Link>{' '}\n\t\t\t\t<span>\n\t\t\t\t\tto get access to the exclusive{' '}\n\t\t\t\t\t<Link to=\"/discord\" className=\"underline\">\n\t\t\t\t\t\tdiscord channel\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t)\n\t}\n\tif (!discordMember) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-wrap items-center justify-center gap-2 text-xl\">\n\t\t\t\t<Link\n\t\t\t\t\tto={connectDiscordURL}\n\t\t\t\t\tclassName=\"flex items-center gap-2 underline\"\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t\t\tConnect Discord\n\t\t\t\t</Link>{' '}\n\t\t\t\t<span>\n\t\t\t\t\tto get access to the exclusive{' '}\n\t\t\t\t\t<Link to=\"/discord\" className=\"underline\">\n\t\t\t\t\t\tdiscord channel\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<div className=\"flex items-center justify-center gap-2 text-xl underline\">\n\t\t\t<Link to=\"discord://discord.com/channels/715220730605731931/1161045224907341972\">\n\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t</Link>\n\t\t\t<Link\n\t\t\t\tto=\"https://discord.com/channels/715220730605731931/1161045224907341972\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t>\n\t\t\t\tOpen Discord\n\t\t\t</Link>\n\t\t</div>\n\t)\n}\n\nexport default function DiscordRoute() {\n\treturn (\n\t\t<div className=\"container flex h-full max-w-3xl flex-col items-center justify-center gap-4 p-12\">\n\t\t\t<DiscordCTA />\n\t\t\t<p>\n\t\t\t\tThe{' '}\n\t\t\t\t<Link\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\tto=\"https://kentcdodds.com/discord\"\n\t\t\t\t>\n\t\t\t\t\tEpic Web Community on Discord\n\t\t\t\t</Link>{' '}\n\t\t\t\tis a great place to hang out with other developers who are working\n\t\t\t\tthrough this workshop. You can ask questions, get help, and solidify\n\t\t\t\twhat you're learning by helping others.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<small className=\"text-sm\">\n\t\t\t\t\tIf you've not joined the Epic Web Community on Discord yet, you'll be\n\t\t\t\t\trequired to go through a short onboarding process first. A friendly\n\t\t\t\t\tbot will explain the process when you{' '}\n\t\t\t\t\t<Link\n\t\t\t\t\t\tto=\"https://kcd.im/discord\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\tjoin\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</small>\n\t\t\t</p>\n\t\t</div>\n\t)\n}\n","import { getExercises } from '@epic-web/workshop-utils/apps.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { Outlet } from 'react-router'\nimport { serverOnly$ } from 'vite-env-only/macros'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: serverOnly$(async (request) => {\n\t\tconst exercises = await getExercises({ request })\n\t\treturn exercises.flatMap((e) => [\n\t\t\t{ route: `/exercise/${e.exerciseNumber.toString().padStart(2, '0')}` },\n\t\t\t...e.steps.flatMap((s) =>\n\t\t\t\t['problem', 'solution'].map((type) => ({\n\t\t\t\t\troute: `/exercise/${e.exerciseNumber.toString().padStart(2, '0')}/${s.stepNumber.toString().padStart(2, '0')}/${type}`,\n\t\t\t\t})),\n\t\t\t),\n\t\t\t{\n\t\t\t\troute: `/exercise/${e.exerciseNumber.toString().padStart(2, '0')}/finished`,\n\t\t\t},\n\t\t])\n\t}),\n}\n\nexport default function ExercisesLayout() {\n\treturn (\n\t\t<div className=\"flex h-full grow\">\n\t\t\t<Outlet />\n\t\t</div>\n\t)\n}\n","import {\n\tPlayerPreferencesSchema,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport RealMuxPlayer, {\n\ttype MuxPlayerRefAttributes,\n\tMinResolution,\n\tMaxResolution,\n} from '@mux/mux-player-react'\nimport * as React from 'react'\nimport {\n\tdata,\n\ttype ActionFunctionArgs,\n\tuseFetcher,\n\tuseFetchers,\n} from 'react-router'\nimport { z } from 'zod'\nimport { useDebounce } from '#app/utils/misc.tsx'\nimport './mux-player.css'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\n\nconst PlaybackTimeSchema = z\n\t.object({\n\t\ttime: z.number(),\n\t\texpiresAt: z.string(),\n\t})\n\t.transform((data) => {\n\t\treturn { time: Number(data.time), expiresAt: new Date(data.expiresAt) }\n\t})\n\nexport function usePlayerPreferences() {\n\tconst rootData = useRootLoaderData()\n\tconst fetchers = useFetchers()\n\tconst pendingPreferencesFetcher = fetchers.find(\n\t\t(f) => f.formAction === '/video-player',\n\t)\n\tif (pendingPreferencesFetcher && pendingPreferencesFetcher.state !== 'idle') {\n\t\tconst submittingData = pendingPreferencesFetcher.json\n\t\tif (submittingData) {\n\t\t\tconst optimisticPlayerPrefs = {\n\t\t\t\t...rootData.preferences?.player,\n\t\t\t\t...(submittingData as z.input<typeof PlayerPreferencesSchema>),\n\t\t\t} as z.input<typeof PlayerPreferencesSchema>\n\t\t\treturn optimisticPlayerPrefs\n\t\t}\n\t}\n\treturn rootData.preferences?.player ?? null\n}\n\ntype MuxPlayerProps = React.ComponentProps<typeof RealMuxPlayer>\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tconst result = PlayerPreferencesSchema.safeParse(await request.json())\n\tif (!result.success) {\n\t\treturn data({ status: 'error', error: result.error.flatten() } as const, {\n\t\t\tstatus: 400,\n\t\t})\n\t}\n\tawait setPreferences({ player: result.data })\n\treturn { status: 'success' } as const\n}\n\nfunction useLatest<Value>(value: Value) {\n\tconst ref = React.useRef(value)\n\tReact.useEffect(() => {\n\t\tref.current = value\n\t}, [value])\n\treturn ref\n}\n\nexport function MuxPlayer({\n\tmuxPlayerRef,\n\t...props\n}: MuxPlayerProps & {\n\tmuxPlayerRef: React.RefObject<MuxPlayerRefAttributes | null>\n}) {\n\tconst playerPreferences = usePlayerPreferences()\n\tconst playerPreferencesFetcher = useFetcher<typeof action>()\n\tconst [metadataLoaded, setMetadataLoaded] = React.useState(false)\n\tconst currentTimeSessionKey = `${props.playbackId}:currentTime`\n\tconst [currentTime, setCurrentTime] = React.useState(0)\n\n\tconst fetcherRef = useLatest(playerPreferencesFetcher)\n\tconst playerPreferencesRef = useLatest(playerPreferences)\n\n\tReact.useEffect(() => {\n\t\tif (typeof document === 'undefined') return\n\t\tconst stored = sessionStorage.getItem(currentTimeSessionKey)\n\t\tif (!stored) return\n\t\ttry {\n\t\t\tconst { time, expiresAt } = PlaybackTimeSchema.parse(JSON.parse(stored))\n\t\t\tif (expiresAt.getTime() < Date.now()) throw new Error('Time expired')\n\t\t\tsetCurrentTime(time)\n\t\t} catch {\n\t\t\tsessionStorage.removeItem(currentTimeSessionKey)\n\t\t}\n\t}, [currentTimeSessionKey])\n\n\tconst updatePreferences = useDebounce(() => {\n\t\tconst player = muxPlayerRef.current\n\t\tif (!player) return\n\t\tconst subs = Array.from(player.textTracks ?? []).find(\n\t\t\t(t) => t.kind === 'subtitles',\n\t\t)\n\t\tconst newPrefs = {\n\t\t\tplaybackRate: player.playbackRate,\n\t\t\tvolumeRate: player.volume,\n\t\t\tsubtitle: subs\n\t\t\t\t? { id: subs.id, mode: subs.mode }\n\t\t\t\t: { id: null, mode: 'disabled' },\n\t\t} satisfies z.input<typeof PlayerPreferencesSchema>\n\n\t\t// don't update the preferences if there's no change...\n\t\tif (isDeepEqual(newPrefs, playerPreferencesRef.current)) return\n\n\t\tvoid fetcherRef.current.submit(newPrefs, {\n\t\t\tmethod: 'POST',\n\t\t\taction: '/video-player',\n\t\t\tencType: 'application/json',\n\t\t})\n\t}, 300)\n\n\tReact.useEffect(() => {\n\t\t// as the video player gets loaded, mux fires a bunch of change events which\n\t\t// we don't want. So we wait until the metadata is loaded before we start\n\t\t// listening to the events.\n\t\tif (!metadataLoaded) return\n\n\t\tconst textTracks = muxPlayerRef.current?.textTracks\n\t\tif (!textTracks) return\n\n\t\tconst subtitlePref = playerPreferencesRef.current?.subtitle\n\t\tif (subtitlePref?.id) {\n\t\t\tconst preferredTextTrack = textTracks.getTrackById(subtitlePref.id)\n\t\t\tif (preferredTextTrack) {\n\t\t\t\tpreferredTextTrack.mode = subtitlePref.mode ?? 'hidden'\n\t\t\t}\n\t\t}\n\n\t\ttextTracks.addEventListener('change', updatePreferences)\n\t\treturn () => {\n\t\t\ttextTracks.removeEventListener('change', updatePreferences)\n\t\t}\n\t}, [metadataLoaded, muxPlayerRef, playerPreferencesRef, updatePreferences])\n\n\treturn (\n\t\t<div className=\"flex aspect-video flex-col\">\n\t\t\t<RealMuxPlayer\n\t\t\t\tref={muxPlayerRef}\n\t\t\t\tplaybackRates={[\n\t\t\t\t\t0.5, 0.75, 0.8, 0.9, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 3.5,\n\t\t\t\t\t// lol, someone really asked for this and I think it's funny so let's do it\n\t\t\t\t\t// https://x.com/zackerydev/status/1710840197879918840\n\t\t\t\t\t4,\n\t\t\t\t]}\n\t\t\t\tvolume={playerPreferences?.volumeRate ?? 1}\n\t\t\t\tplaybackRate={playerPreferences?.playbackRate ?? 1}\n\t\t\t\tthumbnailTime={currentTime}\n\t\t\t\tonRateChange={updatePreferences}\n\t\t\t\tonVolumeChange={updatePreferences}\n\t\t\t\tstreamType=\"on-demand\"\n\t\t\t\tdefaultHiddenCaptions={true}\n\t\t\t\tcurrentTime={currentTime}\n\t\t\t\tonTimeUpdate={() =>\n\t\t\t\t\tsessionStorage.setItem(\n\t\t\t\t\t\tcurrentTimeSessionKey,\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\ttime: muxPlayerRef.current?.currentTime,\n\t\t\t\t\t\t\texpiresAt: new Date(Date.now() + 1000 * 60 * 30).toISOString(),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\taccentColor=\"#427cf0\"\n\t\t\t\ttargetLiveWindow={NaN} // this has gotta be a bug. Without this prop, we get SSR warnings 🤷‍♂️\n\t\t\t\tminResolution={getMinResolutionValue(playerPreferences?.minResolution)}\n\t\t\t\tmaxResolution={getMaxResolutionValue(playerPreferences?.maxResolution)}\n\t\t\t\tonLoadedMetadata={() => setMetadataLoaded(true)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\nfunction isDeepEqual(obj1: unknown, obj2: unknown) {\n\tif (obj1 === obj2) return true\n\tif (typeof obj1 !== typeof obj2) return false\n\tif (typeof obj1 !== 'object' || typeof obj2 !== 'object') return false\n\tif (obj1 === null || obj2 === null) return false\n\tif (Array.isArray(obj1) !== Array.isArray(obj2)) return false\n\tif (Array.isArray(obj1) && Array.isArray(obj2)) {\n\t\tif (obj1.length !== obj2.length) return false\n\t\tfor (let i = 0; i < obj1.length; i++) {\n\t\t\tif (!isDeepEqual(obj1[i], obj2[i])) return false\n\t\t}\n\t\treturn true\n\t}\n\tconst keys1 = Object.keys(obj1)\n\tconst keys2 = Object.keys(obj2)\n\tif (keys1.length !== keys2.length) return false\n\tfor (const key of keys1) {\n\t\t// @ts-expect-error 🤷‍♂️ it's fine\n\t\tif (!isDeepEqual(obj1[key], obj2[key])) return false\n\t}\n\treturn true\n}\n\nfunction getMinResolutionValue(resolution: number | undefined) {\n\tif (!resolution) return undefined\n\tif (resolution <= 480) return MinResolution.noLessThan480p\n\tif (resolution <= 540) return MinResolution.noLessThan540p\n\tif (resolution <= 720) return MinResolution.noLessThan720p\n\tif (resolution <= 1080) return MinResolution.noLessThan1080p\n\tif (resolution <= 1440) return MinResolution.noLessThan1440p\n\treturn MinResolution.noLessThan2160p\n}\n\nfunction getMaxResolutionValue(resolution: number | undefined) {\n\tif (!resolution) return undefined\n\tif (resolution <= 720) return MaxResolution.upTo720p\n\tif (resolution <= 1080) return MaxResolution.upTo1080p\n\tif (resolution <= 1440) return MaxResolution.upTo1440p\n\treturn MaxResolution.upTo2160p\n}\n","// originally this was based on baffle-react, but it was unnecessarily bloated\n// and very out-dated. I've replaced it with a simple Characters component that\n// does the same thing we were using baffle-react for\nimport { useEffect, useRef, useState } from 'react'\nimport { useHints } from '#app/utils/client-hints.tsx'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport function Loading({\n\tclassName,\n\tchildren = 'Loading',\n}: {\n\tclassName?: string\n\tchildren?: React.ReactNode\n}) {\n\tconst { reducedMotion } = useHints()\n\tif (reducedMotion === 'reduce') {\n\t\treturn <div className=\"animate-pulse\">{children}</div>\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex items-center gap-2 font-mono text-sm font-medium uppercase',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\trole=\"status\"\n\t\t>\n\t\t\t<div aria-hidden=\"true\">\n\t\t\t\t<Characters />\n\t\t\t</div>\n\t\t\t{children}\n\t\t\t<div aria-hidden=\"true\">\n\t\t\t\t<Characters />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nconst characters = '█<▓█ ▒░/▒░ █░>▒▓/ █▒▒ ▓▒▓/█<░▒ ▓/░>'\nconst randomCharacter = () =>\n\tcharacters[Math.floor(Math.random() * characters.length)]\nexport function Characters() {\n\tconst [char1, setChar1] = useState(characters[0])\n\tconst [char2, setChar2] = useState(characters[1])\n\n\tuseInterval(() => {\n\t\tsetChar1(randomCharacter())\n\t\tsetChar2(randomCharacter())\n\t}, 80)\n\n\treturn (\n\t\t<span>\n\t\t\t{char1}\n\t\t\t{char2}\n\t\t</span>\n\t)\n}\n\nfunction useInterval(callback: () => void, delay: number | null = 1000) {\n\tconst savedCallback = useRef<() => void>(null)\n\n\t// Remember the latest function.\n\tuseEffect(() => {\n\t\tsavedCallback.current = callback\n\t}, [callback])\n\n\t// Set up the interval.\n\tuseEffect(() => {\n\t\tfunction tick() {\n\t\t\tsavedCallback.current?.()\n\t\t}\n\t\tif (delay !== null) {\n\t\t\tconst id = setInterval(tick, delay)\n\t\t\treturn () => clearInterval(id)\n\t\t}\n\t}, [delay])\n}\n","import { type EpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport { type MuxPlayerRefAttributes } from '@mux/mux-player-react'\nimport * as React from 'react'\nimport { Await, Link } from 'react-router'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { MuxPlayer } from '#app/routes/video-player/index.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { Icon } from './icons.tsx'\nimport { Loading } from './loading.tsx'\nimport { useOptionalUser } from './user.tsx'\nimport { useWorkshopConfig } from './workshop-config.tsx'\n\nconst EpicVideoInfoContext = React.createContext<\n\tPromise<EpicVideoInfos> | null | undefined\n>(null)\n\nexport function EpicVideoInfoProvider({\n\tchildren,\n\tepicVideoInfosPromise,\n}: {\n\tchildren: React.ReactNode\n\tepicVideoInfosPromise?: Promise<EpicVideoInfos> | null\n}) {\n\treturn (\n\t\t<EpicVideoInfoContext.Provider value={epicVideoInfosPromise}>\n\t\t\t{children}\n\t\t</EpicVideoInfoContext.Provider>\n\t)\n}\n\nfunction extractEpicTitle(urlString: string) {\n\tlet url: URL = new URL('https://epicweb.dev')\n\ttry {\n\t\turl = new URL(urlString)\n\t} catch (error) {\n\t\tconsole.error(error)\n\t\treturn 'Epic Video'\n\t}\n\tconst urlSegments = url.pathname.split('/').filter(Boolean)\n\tconst isSolution = urlSegments.includes('solution')\n\tlet titleSegment = urlSegments.pop()\n\tconst nonTitles = ['problem', 'solution', 'embed', 'exercise']\n\tconst isTitleSegment = (str?: string) => str && !nonTitles.includes(str)\n\twhile (!isTitleSegment(titleSegment)) titleSegment = urlSegments.pop()\n\n\tif (!titleSegment) return 'Epic Video'\n\n\t// Chop off anything after ~ if no spaces follow anywhere after the ~\n\t// that's common for EpicAI videos\n\ttitleSegment = titleSegment.replace(/~[^ ]*$/, '')\n\n\tconst titleWords = titleSegment.split('-')\n\t// prettier-ignore\n\tconst lowerCaseWords = [\n\t\t'the', 'a', 'an', 'and', 'but', 'or', 'for', 'nor', 'on', 'at', 'to',\n\t\t'from', 'by', 'of', 'in', 'with', 'as', 'npm', 'git', 'ssh', 'cli'\n\t]\n\t// prettier-ignore\n\tconst literalWords = [\n\t\t'OAuth', 'UI', 'UX', 'API', 'CSS', 'HTML', 'JS', 'TS', 'SVG', 'AI', 'CSRF',\n\t\t'CORS', 'HTTP', 'HTTPS', 'URL', 'URI', 'DB', 'SQL', 'JSON', 'YAML', 'YML',\n\n\t\t'useActionData', 'useAsyncError', 'useAsyncValue', 'useBeforeUnload',\n\t\t'useFetcher', 'useFetchers', 'useFormAction', 'useHref', 'useLoaderData',\n\t\t'useLocation', 'useMatches', 'useNavigate', 'useNavigation',\n\t\t'useNavigationType', 'useOutlet', 'useOutletContext', 'useParams',\n\t\t'useResolvedPath', 'useRevalidator', 'useRouteError', 'useRouteLoaderData',\n\t\t'useSearchParams', 'useSubmit', 'useCallback', 'useContext',\n\t\t'useDebugValue', 'useDeferredValue', 'useEffect', 'useId',\n\t\t'useImperativeHandle', 'useInsertionEffect', 'useLayoutEffect', 'useMemo',\n\t\t'useReducer', 'useRef', 'useState', 'useSyncExternalStore', 'useTransition',\n\t\t'useForm','useFieldset', 'useFieldList', 'useEventSource', 'useHydrated',\n\t\t'useAuthenticityToken', 'useShouldHydrate', 'useGlobalNavigationState',\n\t\t'useLocales', 'useDelegatedAnchors', 'useDebounceFetcher', 'useFetcherType',\n\t]\n\tconst title = titleWords\n\t\t.filter(Boolean)\n\t\t.map((word, index) => {\n\t\t\tconst lowerWord = word.toLowerCase()\n\t\t\tconst literalWord = literalWords.find(\n\t\t\t\t(w) => w.toLowerCase() === lowerWord,\n\t\t\t)\n\t\t\tif (literalWord) return literalWord\n\t\t\tif (lowerCaseWords.includes(lowerWord) && index > 0) {\n\t\t\t\treturn lowerWord\n\t\t\t}\n\t\t\treturn lowerWord[0]?.toUpperCase() + lowerWord.slice(1)\n\t\t})\n\t\t.join(' ')\n\tif (isSolution) {\n\t\treturn `${title} (🏁 solution)`\n\t}\n\treturn title\n}\n\nexport function VideoEmbed({\n\turl,\n\ttitle = 'Video Embed',\n\tloadingContent = (\n\t\t<Loading>\n\t\t\t<span>Loading \"{title}\"</span>\n\t\t</Loading>\n\t),\n}: {\n\turl: string\n\ttitle?: string\n\tloadingContent?: React.ReactNode\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"relative aspect-video w-full shrink-0 shadow-lg\">\n\t\t\t\t<div className=\"not-prose text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center p-8\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{'Unable to load the video '}\n\t\t\t\t\t\t\t<a href={url} className=\"underline\">\n\t\t\t\t\t\t\t\t{`\"${title ?? url}\"`}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{' when offline'}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<div className=\"relative aspect-video w-full shrink-0 shadow-lg\">\n\t\t\t{iframeLoaded ? null : (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center p-8\">\n\t\t\t\t\t{loadingContent}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\tsrc={url}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\ttitle={title}\n\t\t\t\tsandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n\t\t\t\tallowFullScreen\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\nfunction VideoLink({\n\turl,\n\ttitle,\n\tduration,\n\tdurationEstimate,\n}: {\n\turl: string\n\ttitle: string\n\tduration?: number | null\n\tdurationEstimate?: number | null\n}) {\n\treturn (\n\t\t<span className=\"flex items-center gap-1 text-base\">\n\t\t\t{duration ? (\n\t\t\t\t<span className=\"opacity-70\">{formatDuration(duration)}</span>\n\t\t\t) : durationEstimate ? (\n\t\t\t\t<span className=\"opacity-70\">~{formatDuration(durationEstimate)}</span>\n\t\t\t) : null}\n\t\t\t<a\n\t\t\t\thref={url}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\tclassName=\"flex items-center gap-1 no-underline opacity-70 transition hover:underline hover:opacity-100\"\n\t\t\t\trel=\"noreferrer\"\n\t\t\t>\n\t\t\t\t<Icon className=\"shrink-0\" name=\"Video\" size=\"lg\" />\n\t\t\t\t{title} <span aria-hidden>↗︎</span>\n\t\t\t</a>\n\t\t</span>\n\t)\n}\nexport function DeferredEpicVideo({\n\turl,\n\ttitle: providedTitle,\n}: {\n\turl: string\n\ttitle?: string\n}) {\n\t// we need to distinguish between the provided title and the fallback because the priority is:\n\t// 1. provided title\n\t// 2. title from the api\n\t// 3. fallback title\n\tconst title = providedTitle ?? extractEpicTitle(url)\n\tconst {\n\t\tproduct: { host, displayName },\n\t} = useWorkshopConfig()\n\tconst user = useOptionalUser()\n\tconst epicVideoInfosPromise = React.useContext(EpicVideoInfoContext)\n\tconst linkUI = <VideoLink url={url} title={title} />\n\treturn (\n\t\t<div>\n\t\t\t<React.Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"flex aspect-video w-full items-center justify-center\">\n\t\t\t\t\t\t\t<Loading>{title}</Loading>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t<div className=\"h-[32px]\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await\n\t\t\t\t\terrorElement={\n\t\t\t\t\t\t<div>Sorry, failed loading videos. Check the terminal output?</div>\n\t\t\t\t\t}\n\t\t\t\t\tresolve={epicVideoInfosPromise}\n\t\t\t\t>\n\t\t\t\t\t{(epicVideoInfos) => {\n\t\t\t\t\t\tconst epicVideoInfo = epicVideoInfos?.[url]\n\t\t\t\t\t\tconst transcriptUI = ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<Link to={ENV.EPICSHOP_GITHUB_REPO} className=\"underline\">\n\t\t\t\t\t\t\t\t\tRun locally\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t{' for transcripts'}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<Link to=\"/login\" className=\"underline\">\n\t\t\t\t\t\t\t\t\t{user ? 'Upgrade' : 'Login'}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t{' for transcripts'}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif (!epicVideoInfo) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t{transcriptUI}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst info = epicVideoInfo\n\t\t\t\t\t\tif (info.status === 'success') {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<EpicVideo\n\t\t\t\t\t\t\t\t\turl={url}\n\t\t\t\t\t\t\t\t\ttitle={providedTitle ?? info.title ?? title}\n\t\t\t\t\t\t\t\t\tmuxPlaybackId={info.muxPlaybackId}\n\t\t\t\t\t\t\t\t\ttranscript={info.transcript}\n\t\t\t\t\t\t\t\t\tduration={info.duration}\n\t\t\t\t\t\t\t\t\tdurationEstimate={info.durationEstimate}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else if (info.type === 'region-restricted') {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<div className=\"flex aspect-video min-h-full min-w-full flex-col items-center justify-start gap-2 overflow-y-scroll border-2 p-4 lg:justify-center lg:gap-4 lg:text-xl\">\n\t\t\t\t\t\t\t\t\t\t<div className=\"!text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\tError: Region Restricted\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t\t\tWe've detected you're connecting from{' '}\n\t\t\t\t\t\t\t\t\t\t\t{info.requestCountry} but your license has restricted\n\t\t\t\t\t\t\t\t\t\t\taccess to {info.restrictedCountry}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t\t\tTo continue watching uninterrupted, please{' '}\n\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\thref={`https://${host}/products`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\tupgrade your {displayName} license\n\t\t\t\t\t\t\t\t\t\t\t</a>{' '}\n\t\t\t\t\t\t\t\t\t\t\tto a full Pro license.\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={`https://${host}/products`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\tUpgrade\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{' for transcripts'}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else if (info.statusCode === 401) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t{transcriptUI}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else if (info.statusCode === 403) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={`https://${host}/products`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\tUpgrade\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{' for transcripts'}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else if (info.statusCode === 404) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t<div>Transcripts not found</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.error(info)\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<EpicVideoEmbed url={url} title={title} />\n\t\t\t\t\t\t\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t\t\t{linkUI}\n\t\t\t\t\t\t\t\t\t\t<div className=\"!text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\tUnknown error (check console)\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t</Await>\n\t\t\t</React.Suspense>\n\t\t</div>\n\t)\n}\n\nfunction EpicVideo({\n\turl: urlString,\n\ttitle = extractEpicTitle(urlString),\n\tmuxPlaybackId,\n\ttranscript,\n\tduration,\n\tdurationEstimate,\n}: {\n\turl: string\n\ttitle?: string\n\tmuxPlaybackId: string\n\ttranscript: string\n\tduration?: number | null\n\tdurationEstimate?: number | null\n}) {\n\tconst muxPlayerRef = React.useRef<MuxPlayerRefAttributes>(null)\n\tconst timestampRegex = /(\\d+:\\d+)/g\n\t// turn the transcript into an array of React elements\n\tconst transcriptElements: Array<React.ReactNode> = []\n\tlet match\n\tlet prevIndex = 0\n\twhile ((match = timestampRegex.exec(transcript))) {\n\t\tconst timestamp = match[1]\n\t\tif (!timestampRegex.lastIndex || !timestamp) break\n\n\t\tconst timestampIndexStart = match.index\n\t\tconst timestampIndexEnd = timestampRegex.lastIndex\n\t\tconst textBeforeTimestamp = transcript.slice(\n\t\t\tprevIndex + 1,\n\t\t\ttimestampIndexStart - 1,\n\t\t)\n\t\ttranscriptElements.push(\n\t\t\t<span key={`span-${timestampIndexStart}`}>{textBeforeTimestamp}</span>,\n\t\t)\n\t\ttranscriptElements.push(\n\t\t\t<button\n\t\t\t\tkey={`button-${timestampIndexStart}`}\n\t\t\t\tclassName=\"underline\"\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\tif (muxPlayerRef.current) {\n\t\t\t\t\t\tmuxPlayerRef.current.currentTime = hmsToSeconds(timestamp)\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tvoid muxPlayerRef.current.play().catch(() => {})\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmuxPlayerRef.current.scrollIntoView({\n\t\t\t\t\t\t\tbehavior: 'smooth',\n\t\t\t\t\t\t\tinline: 'center',\n\t\t\t\t\t\t\tblock: 'start',\n\t\t\t\t\t\t})\n\t\t\t\t\t\tevent.currentTarget.blur()\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{timestamp}\n\t\t\t</button>,\n\t\t)\n\t\tprevIndex = timestampIndexEnd\n\t}\n\ttranscriptElements.push(\n\t\t<span key={transcript.length}>\n\t\t\t{transcript.slice(prevIndex + 1, transcript.length)}\n\t\t</span>,\n\t)\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"shadow-lg\">\n\t\t\t\t<MuxPlayer\n\t\t\t\t\tplaybackId={muxPlaybackId}\n\t\t\t\t\tmuxPlayerRef={muxPlayerRef}\n\t\t\t\t\ttitle={title}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"mt-4 flex flex-col gap-2\">\n\t\t\t\t<VideoLink\n\t\t\t\t\turl={urlString}\n\t\t\t\t\ttitle={title}\n\t\t\t\t\tduration={duration}\n\t\t\t\t\tdurationEstimate={durationEstimate}\n\t\t\t\t/>\n\t\t\t\t<details>\n\t\t\t\t\t<summary>Transcript</summary>\n\t\t\t\t\t<div className=\"bg-accent text-accent-foreground rounded-md p-2 whitespace-pre-line\">\n\t\t\t\t\t\t{transcriptElements}\n\t\t\t\t\t</div>\n\t\t\t\t</details>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction hmsToSeconds(str: string) {\n\tconst p = str.split(':')\n\tlet s = 0\n\tlet m = 1\n\n\twhile (p.length > 0) {\n\t\ts += m * parseInt(p.pop() ?? '0', 10)\n\t\tm *= 60\n\t}\n\treturn s\n}\n\nfunction formatDuration(seconds: number): string {\n\tconst hours = Math.floor(seconds / 3600)\n\tconst minutes = Math.floor((seconds % 3600) / 60)\n\tconst secs = Math.floor(seconds % 60)\n\n\tif (hours > 0) {\n\t\treturn `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`\n\t}\n\treturn `${minutes}:${secs.toString().padStart(2, '0')}`\n}\n\nfunction EpicVideoEmbed({\n\turl: urlString,\n\ttitle,\n}: {\n\turl: string\n\ttitle: string\n}) {\n\tconst theme = useTheme()\n\tlet url: URL = new URL('https://epicweb.dev')\n\ttry {\n\t\turl = new URL(urlString)\n\t} catch (error) {\n\t\tconsole.error(error)\n\t\treturn <div>Invalid URL: \"{urlString}\"</div>\n\t}\n\turl.pathname = url.pathname.endsWith('/')\n\t\t? `${url.pathname}embed`\n\t\t: `${url.pathname}/embed`\n\turl.searchParams.set('theme', theme)\n\t// special case for epicai.pro videos\n\tif (\n\t\turl.host === 'www.epicai.pro' &&\n\t\t!url.pathname.startsWith('/workshops/')\n\t) {\n\t\turl.pathname = `/posts/${url.pathname}`\n\t}\n\treturn (\n\t\t<VideoEmbed\n\t\t\turl={url.toString()}\n\t\t\ttitle={title}\n\t\t\tloadingContent={\n\t\t\t\t<Loading>\n\t\t\t\t\t<span>\n\t\t\t\t\t\t{'Loading \"'}\n\t\t\t\t\t\t<a className=\"underline\" href={urlString}>\n\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t{'\"'}\n\t\t\t\t\t</span>\n\t\t\t\t</Loading>\n\t\t\t}\n\t\t/>\n\t)\n}\n","import path from 'path'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport { launchEditor } from '@epic-web/workshop-utils/launch-editor.server'\nimport fsExtra from 'fs-extra'\nimport { useEffect } from 'react'\nimport { Link, useFetcher, type ActionFunctionArgs } from 'react-router'\nimport { z, type ZodTypeAny } from 'zod'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { cn, ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { useApps, useRequestInfo } from '#app/utils/root-loader.ts'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nfunction getFileDescriptorSchema<AppFile extends ZodTypeAny>(appFile: AppFile) {\n\treturn z.union([\n\t\tz.object({\n\t\t\ttype: z.literal('file'),\n\t\t\tfile: z.string(),\n\t\t}),\n\t\tz.object({\n\t\t\ttype: z.literal('appFile'),\n\t\t\tappFile,\n\t\t\tappName: z.string(),\n\t\t}),\n\t])\n}\n\nconst LaunchSchema = z.intersection(\n\tz.object({\n\t\tline: z.coerce.number().optional(),\n\t\tcolumn: z.coerce.number().optional(),\n\t\tsyncTo: getFileDescriptorSchema(z.string()).optional(),\n\t}),\n\tgetFileDescriptorSchema(z.array(z.string())),\n)\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst syncTo = {\n\t\ttype: formData.get('syncTo.type') ?? undefined,\n\t\tfile: formData.get('syncTo.file') ?? undefined,\n\t\tworkshopFile: formData.get('syncTo.workshopFile') ?? undefined,\n\t\tappFile: formData.getAll('syncTo.appFile'),\n\t\tappName: formData.get('syncTo.appName') ?? undefined,\n\t}\n\tconst syncToIsProvided = Object.values(syncTo).some((v) =>\n\t\tArray.isArray(v) ? v.length : v,\n\t)\n\tconst rawData = {\n\t\ttype: formData.get('type'),\n\t\tfile: formData.get('file'),\n\t\tworkshopFile: formData.get('workshopFile'),\n\t\tappFile: formData.getAll('appFile'),\n\t\tappName: formData.get('appName'),\n\t\tline: formData.get('line') ?? undefined,\n\t\tcolumn: formData.get('column') ?? undefined,\n\t\tsyncTo: syncToIsProvided\n\t\t\t? {\n\t\t\t\t\ttype: formData.get('syncTo.type'),\n\t\t\t\t\tfile: formData.get('syncTo.file'),\n\t\t\t\t\tworkshopFile: formData.get('syncTo.workshopFile'),\n\t\t\t\t\tappFile: formData.getAll('syncTo.appFile'),\n\t\t\t\t\tappName: formData.get('syncTo.appName'),\n\t\t\t\t}\n\t\t\t: undefined,\n\t}\n\tconst form = LaunchSchema.parse(rawData)\n\n\tasync function getFiles(\n\t\tfileDescriptor:\n\t\t\t| ({ line?: number; colum?: number } & {\n\t\t\t\t\ttype: 'file'\n\t\t\t\t\tfile: string\n\t\t\t\t\tappName?: never\n\t\t\t\t\tappFile?: never\n\t\t\t })\n\t\t\t| {\n\t\t\t\t\ttype: 'appFile'\n\t\t\t\t\tfile?: never\n\t\t\t\t\tappName: string\n\t\t\t\t\tappFile: string | Array<string>\n\t\t\t },\n\t): Promise<Array<{ filepath: string; line?: number; column?: number }>> {\n\t\tif (fileDescriptor.type === 'file') {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tfilepath: fileDescriptor.file,\n\t\t\t\t\tline: fileDescriptor.line,\n\t\t\t\t\tcolumn: fileDescriptor.colum,\n\t\t\t\t},\n\t\t\t]\n\t\t} else {\n\t\t\tconst fileDescriptorApp = await getAppByName(fileDescriptor.appName)\n\t\t\tif (!fileDescriptorApp) {\n\t\t\t\tthrow new Response(`App \"${fileDescriptor.appName}\" Not found`, {\n\t\t\t\t\tstatus: 404,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst appFile = Array.isArray(fileDescriptor.appFile)\n\t\t\t\t? fileDescriptor.appFile\n\t\t\t\t: [fileDescriptor.appFile]\n\t\t\treturn appFile.map((file) => {\n\t\t\t\tconst [filePath, line = '1', column = '1'] = file.split(',')\n\t\t\t\tif (!filePath) {\n\t\t\t\t\tthrow new Response(\n\t\t\t\t\t\t`appFile missing file path: ${fileDescriptor.appFile}`,\n\t\t\t\t\t\t{ status: 400 },\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tfilepath: path.join(fileDescriptorApp.fullPath, filePath),\n\t\t\t\t\tline: Number(line),\n\t\t\t\t\tcolumn: Number(column),\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\n\tconst filesToOpen = await getFiles(form)\n\tif ('syncTo' in form && form.syncTo) {\n\t\tconst originFiles = await getFiles(form.syncTo)\n\t\tfor (let index = 0; index < originFiles.length; index++) {\n\t\t\tconst originFile = originFiles[index]\n\t\t\tif (!originFile) continue\n\t\t\tconst destFile = filesToOpen[index]\n\t\t\tif (!destFile) {\n\t\t\t\tthrow new Response(\n\t\t\t\t\t`Trying to sync to a file that does not appear at index ${index}`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tawait fsExtra.ensureDir(path.dirname(destFile.filepath))\n\t\t\tawait fsExtra.promises.copyFile(originFile.filepath, destFile.filepath)\n\t\t}\n\t}\n\tconst results: Array<\n\t\t{ status: 'success' } | { status: 'error'; message: string }\n\t> = []\n\tfor (const file of filesToOpen) {\n\t\tresults.push(await launchEditor(file.filepath, file.line, file.column))\n\t}\n\n\tif (results.every((r) => r.status === 'success')) {\n\t\treturn dataWithPE(request, formData, { status: 'success' } as const)\n\t} else {\n\t\tconst messages = results\n\t\t\t.map((r, index, array) =>\n\t\t\t\tr.status === 'error'\n\t\t\t\t\t? array.length > 1\n\t\t\t\t\t\t? `${index}. ${r.message}`\n\t\t\t\t\t\t: r.message\n\t\t\t\t\t: null,\n\t\t\t)\n\t\t\t.filter(Boolean)\n\t\t\t.join('\\n')\n\t\tconsole.error('Launch editor error:', messages)\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ status: 'error', message: messages } as const,\n\t\t\t{\n\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\ttitle: 'Launch Editor Error',\n\t\t\t\t\tdescription: messages,\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t}\n}\n\ntype FileDescriptorProps<AppFile> =\n\t| {\n\t\t\tfile: string\n\t\t\tappFile?: never\n\t\t\tappName?: never\n\t }\n\t| {\n\t\t\tfile?: never\n\t\t\tappFile: AppFile\n\t\t\tappName: string\n\t }\n\ntype LaunchEditorProps = {\n\tclassName?: string\n\tline?: number\n\tcolumn?: number\n\tsyncTo?: FileDescriptorProps<string>\n\tchildren: React.ReactNode\n\tonUpdate?: (state: string) => void\n} & FileDescriptorProps<string | string[]>\n\nfunction useLaunchFetcher(onUpdate?: ((state: string) => void) | undefined) {\n\tconst fetcher = useFetcher<typeof action>()\n\n\tuseEffect(() => {\n\t\tif (fetcher.state === 'idle' && fetcher.data != null) {\n\t\t\tonUpdate?.('fetcher-done')\n\t\t}\n\t}, [fetcher, onUpdate])\n\n\treturn fetcher\n}\n\nfunction LaunchEditorImpl({\n\tclassName,\n\tfile,\n\tappFile,\n\tappName,\n\tsyncTo,\n\tline,\n\tcolumn,\n\tchildren,\n\tonUpdate,\n}: LaunchEditorProps) {\n\tconst fetcher = useLaunchFetcher(onUpdate)\n\tconst peRedirectInput = usePERedirectInput()\n\n\tif (!file && !appFile) {\n\t\tconsole.error('LaunchEditor: requires either \"file\" or \"appFile\" prop.')\n\t\treturn null\n\t}\n\tconst fileList = typeof appFile === 'string' ? [appFile] : appFile\n\tconst type = file ? 'file' : 'appFile'\n\tconst syncToType = syncTo?.file ? 'file' : syncTo?.appFile ? 'appFile' : ''\n\n\treturn (\n\t\t<fetcher.Form\n\t\t\taction=\"/launch-editor\"\n\t\t\tmethod=\"POST\"\n\t\t\tclassName=\"flex items-center\"\n\t\t>\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input\n\t\t\t\ttype=\"hidden\"\n\t\t\t\tname=\"line\"\n\t\t\t\tvalue={typeof line === 'number' ? line : undefined}\n\t\t\t/>\n\t\t\t<input type=\"hidden\" name=\"column\" value={column} />\n\t\t\t<input type=\"hidden\" name=\"type\" value={type} />\n\t\t\t<input type=\"hidden\" name=\"file\" value={file} />\n\t\t\t<input type=\"hidden\" name=\"appName\" value={appName} />\n\t\t\t{fileList?.map((file) => (\n\t\t\t\t<input type=\"hidden\" name=\"appFile\" key={file} value={file} />\n\t\t\t))}\n\t\t\t{syncTo ? (\n\t\t\t\t<>\n\t\t\t\t\t<input type=\"hidden\" name=\"syncTo.type\" value={syncToType} />\n\t\t\t\t\t<input type=\"hidden\" name=\"syncTo.file\" value={syncTo.file} />\n\t\t\t\t\t<input type=\"hidden\" name=\"syncTo.appName\" value={syncTo.appName} />\n\t\t\t\t\t<input type=\"hidden\" name=\"syncTo.appFile\" value={syncTo.appFile} />\n\t\t\t\t</>\n\t\t\t) : null}\n\t\t\t<button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'launch_button',\n\t\t\t\t\tfetcher.state === 'idle' ? null : 'cursor-progress',\n\t\t\t\t\tfetcher.data?.status === 'error' ? 'cursor-not-allowed' : null,\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</button>\n\t\t</fetcher.Form>\n\t)\n}\n\nfunction LaunchGitHub({\n\tclassName,\n\tfile,\n\tappFile,\n\tappName,\n\tline,\n\tchildren,\n}: LaunchEditorProps) {\n\tconst apps = useApps()\n\tconst requestInfo = useRequestInfo()\n\tif (Array.isArray(appFile)) {\n\t\treturn <div>Cannot open more than one file</div>\n\t}\n\tif (file) {\n\t\tconst safePath = (s: string) => s.replace(/\\\\/g, '/')\n\t\t// Convert tree to blob for individual files\n\t\tconst githubFileRoot = ENV.EPICSHOP_GITHUB_ROOT.replace('/tree/', '/blob/')\n\t\treturn (\n\t\t\t<a\n\t\t\t\tclassName=\"launch_button !no-underline\"\n\t\t\t\thref={\n\t\t\t\t\tsafePath(file).replace(\n\t\t\t\t\t\tsafePath(ENV.EPICSHOP_CONTEXT_CWD),\n\t\t\t\t\t\tgithubFileRoot,\n\t\t\t\t\t) + (line ? `#L${line}` : '')\n\t\t\t\t}\n\t\t\t\trel=\"noreferrer\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</a>\n\t\t)\n\t}\n\tconst app = apps.find((a) => a.name === appName)\n\t// Convert tree to blob for individual files\n\tconst githubFileRoot = ENV.EPICSHOP_GITHUB_ROOT.replace('/tree/', '/blob/')\n\n\t// Parse appFile to extract filename and line number (format: \"filename,line,column\")\n\tconst [filename, appFileLine] = appFile ? appFile.split(',') : ['', '']\n\tconst lineNumber = line || (appFileLine ? Number(appFileLine) : undefined)\n\n\tconst path = [\n\t\t...(app?.relativePath.split(requestInfo.separator) ?? []),\n\t\tfilename,\n\t].join('/')\n\treturn (\n\t\t<a\n\t\t\tclassName={cn('launch_button !no-underline', className)}\n\t\t\thref={`${githubFileRoot}/${path}${lineNumber ? `#L${lineNumber}` : ''}`}\n\t\t\trel=\"noreferrer\"\n\t\t\ttarget=\"_blank\"\n\t\t>\n\t\t\t{children}\n\t\t</a>\n\t)\n}\n\nexport function EditFileOnGitHub({\n\tappFile = 'README.mdx',\n\tappName,\n\tfile,\n\trelativePath,\n\tcompact = false,\n}: {\n\tappFile?: string\n\trelativePath: string\n\tcompact?: boolean\n} & (\n\t| {\n\t\t\tfile: string\n\t\t\tappName?: never\n\t }\n\t| {\n\t\t\tfile?: never\n\t\t\tappName: string\n\t }\n)) {\n\tconst fetcher = useLaunchFetcher()\n\n\tconst handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {\n\t\tif (!e.altKey || ENV.EPICSHOP_DEPLOYED) return\n\t\te.preventDefault()\n\t\tconst formData = new FormData()\n\t\tconst type = file ? 'file' : 'appFile'\n\t\tformData.append(type, file ?? appFile)\n\t\tformData.append('type', type)\n\t\tif (appName) {\n\t\t\tformData.append('appName', appName)\n\t\t}\n\t\tvoid fetcher.submit(formData, { method: 'POST', action: '/launch-editor' })\n\t}\n\n\tconst githubPath = ENV.EPICSHOP_GITHUB_ROOT.replace(\n\t\t/\\/tree\\/|\\/blob\\//,\n\t\t'/edit/',\n\t)\n\n\treturn (\n\t\t<Link\n\t\t\tclassName=\"self-center font-mono text-sm\"\n\t\t\tonClick={handleClick}\n\t\t\ttarget=\"_blank\"\n\t\t\tto={`${githubPath}/${relativePath}`.replace(/\\\\/g, '/')}\n\t\t>\n\t\t\t{compact ? (\n\t\t\t\t<span>Edit</span>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<span className=\"block md:hidden\">Edit on GitHub</span>\n\t\t\t\t\t<span className=\"hidden md:block\">Edit this page on GitHub</span>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</Link>\n\t)\n}\n\nexport const LaunchEditor = ENV.EPICSHOP_DEPLOYED\n\t? LaunchGitHub\n\t: LaunchEditorImpl\n","import { useEffect, useId, useRef } from 'react'\n\nexport function Mermaid({\n\tcode,\n\tonSvg,\n}: {\n\tcode: string\n\tonSvg?: (svg: string) => void\n}) {\n\tconst id = `mermaid-svg-${useId()}`\n\tconst ref = useRef<HTMLDivElement>(null)\n\tconst latestOnSvg = useRef(onSvg)\n\tuseEffect(() => {\n\t\tlatestOnSvg.current = onSvg\n\t}, [onSvg])\n\n\tuseEffect(() => {\n\t\tif (!ref.current) return\n\t\tlet cancelled = false\n\t\tvoid import('mermaid').then((mermaid) => {\n\t\t\tmermaid.default.initialize({ startOnLoad: false })\n\t\t\tmermaid.default\n\t\t\t\t.render(id, code)\n\t\t\t\t.then(({ svg }) => {\n\t\t\t\t\tif (!cancelled && ref.current) {\n\t\t\t\t\t\tref.current.innerHTML = svg\n\t\t\t\t\t\tlatestOnSvg.current?.(svg)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tif (!cancelled && ref.current) {\n\t\t\t\t\t\tref.current.innerHTML = `<pre style='color:red'>${String(err)}</pre>`\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t})\n\t\treturn () => {\n\t\t\tcancelled = true\n\t\t}\n\t}, [code, id])\n\treturn (\n\t\t<div className=\"mermaid not-prose\">\n\t\t\t<div ref={ref} />\n\t\t</div>\n\t)\n}\n","import { clsx } from 'clsx'\nimport { LRUCache } from 'lru-cache'\nimport { type MDXContentProps } from 'mdx-bundler/client'\nimport * as mdxBundler from 'mdx-bundler/client'\nimport { useEffect, useMemo, useState } from 'react'\nimport { Link, useLoaderData } from 'react-router'\nimport { toast } from 'sonner'\nimport { DeferredEpicVideo, VideoEmbed } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Mermaid } from '#app/components/mermaid.tsx'\nimport { type loader } from '#app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/_layout.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { AnchorOrLink, Heading, cn } from './misc.tsx'\n\nconst safePath = (s: string) => s.replace(/\\\\/g, '/')\n\nfunction getRelativePath(file: string, separator: string, type?: string) {\n\tconst [, relativePath] = file\n\t\t.replace(/\\\\|\\//g, separator)\n\t\t.split(`${type === 'playground' ? 'example' : 'exercises'}${separator}`)\n\treturn relativePath\n}\n\nconst buttonClassName =\n\t'border-border bg-[var(--shiki-background)] hover:bg-foreground/20 active:bg-foreground/30 box-content block rounded border-2 px-2 py-0.5 font-mono text-xs font-semibold outline-none transition duration-300 ease-in-out'\n\ntype DataProps = {\n\t'data-buttons'?: string\n\t'data-filename'?: string\n\t'data-fullpath'?: string\n\t'data-nocopy'?: string\n\t'data-sep'?: string\n\t'data-start'?: string\n\t'data-type'?: string\n}\n\nfunction OpenInEditor({\n\t'data-buttons': buttons,\n\t'data-filename': filename,\n\t'data-fullpath': fullPath,\n\t'data-sep': separator = '/',\n\t'data-start': start,\n\t'data-type': type,\n}: DataProps) {\n\tconst data = useLoaderData<typeof loader>()\n\n\tif (type === 'other' || !buttons || !filename || !fullPath) return null\n\n\tconst currentAppFullPath = safePath(data[data.type]?.fullPath ?? '')\n\tconst isFileFromDifferentApp = !fullPath.startsWith(currentAppFullPath)\n\tconst validButtons = ENV.EPICSHOP_DEPLOYED\n\t\t? (['problem', 'solution'] as const)\n\t\t: (['problem', 'solution', 'playground'] as const)\n\tconst buttonList = buttons.split(',')\n\tconst apps = validButtons.filter((button) => buttonList.includes(button))\n\n\treturn (\n\t\t<>\n\t\t\t{apps.map((type) => {\n\t\t\t\tconst app = data[type]\n\t\t\t\tif (type === 'playground') {\n\t\t\t\t\tconst isDifferentApp =\n\t\t\t\t\t\tdata.playground && data.playground.appName !== data.problem?.name\n\t\t\t\t\tif (!app || isDifferentApp || isFileFromDifferentApp) {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tkey={type}\n\t\t\t\t\t\t\t\tclassName={clsx(buttonClassName, 'cursor-not-allowed')}\n\t\t\t\t\t\t\t\ttitle={\n\t\t\t\t\t\t\t\t\tisDifferentApp\n\t\t\t\t\t\t\t\t\t\t? 'Playground is not set to the right app'\n\t\t\t\t\t\t\t\t\t\t: isFileFromDifferentApp\n\t\t\t\t\t\t\t\t\t\t\t? 'This file is from different app'\n\t\t\t\t\t\t\t\t\t\t\t: \"You must 'Set to Playground' before opening a file\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"uppercase\">Open</span> in {type}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!app || !app.fullPath) {\n\t\t\t\t\t// unexpected\n\t\t\t\t\treturn null\n\t\t\t\t}\n\n\t\t\t\tconst file = [safePath(app.fullPath), safePath(filename)].join(\n\t\t\t\t\tseparator,\n\t\t\t\t)\n\t\t\t\tconst fixedTitle = getRelativePath(file, separator, type)\n\t\t\t\treturn (\n\t\t\t\t\t<LaunchEditor key={type} file={file} line={Number(start ?? 1)}>\n\t\t\t\t\t\t<span title={fixedTitle} className={buttonClassName}>\n\t\t\t\t\t\t\t<span className=\"uppercase\">Open</span> in {type}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</LaunchEditor>\n\t\t\t\t)\n\t\t\t})}\n\t\t</>\n\t)\n}\n\nfunction CopyButton(): React.ReactNode {\n\tconst [copied, setCopied] = useState(false)\n\n\tuseEffect(() => {\n\t\tif (copied) {\n\t\t\tconst timeoutId = setTimeout(() => setCopied(false), 1500)\n\t\t\treturn () => clearTimeout(timeoutId)\n\t\t}\n\t}, [copied])\n\n\treturn (\n\t\t<button\n\t\t\tclassName={cn(buttonClassName, 'w-12 uppercase')}\n\t\t\tonClick={async (event) => {\n\t\t\t\tif (navigator.clipboard) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst button = event.currentTarget\n\t\t\t\t\t\tconst code =\n\t\t\t\t\t\t\tbutton.parentElement?.parentElement?.querySelector('pre')\n\t\t\t\t\t\t\t\t?.textContent || ''\n\t\t\t\t\t\tawait navigator.clipboard.writeText(code)\n\t\t\t\t\t\tsetCopied(true)\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconsole.error('Failed to copy to clipboard:', error)\n\t\t\t\t\t\ttoast.error('Failed to copy to clipboard', {\n\t\t\t\t\t\t\tdescription: 'Please try again or copy the code manually.',\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttoast.error(\n\t\t\t\t\t\t'Copying is only available in secure contexts (HTTPS or localhost).',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t'Please access the workshop via localhost instead of an IP address to enable this feature.',\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}}\n\t\t>\n\t\t\t{copied ? 'copied' : 'copy'}\n\t\t</button>\n\t)\n}\n\nexport function PreWithButtons({ children, ...props }: any) {\n\tconst {\n\t\t'data-buttons': buttons,\n\t\t'data-filename': filename,\n\t\t'data-fullpath': fullPath,\n\t\t'data-nocopy': hideCopyButton,\n\t\t'data-sep': separator,\n\t} = props as DataProps\n\tconst showCopyButton = hideCopyButton === undefined\n\n\tfunction updateFilename() {\n\t\tif (fullPath && separator) {\n\t\t\tif (!filename || filename.includes('..')) {\n\t\t\t\treturn { 'data-filename': getRelativePath(fullPath, separator) }\n\t\t\t} else {\n\t\t\t\treturn { 'data-filename': filename.replace(/\\//g, separator) }\n\t\t\t}\n\t\t}\n\t}\n\n\treturn (\n\t\t<div className=\"group relative\">\n\t\t\t<div className=\"absolute top-0 right-0 z-50 m-2 flex items-baseline justify-end gap-4 opacity-0 transition duration-300 ease-in-out group-hover:opacity-100 focus-within:opacity-100\">\n\t\t\t\t{buttons ? <OpenInEditor {...props} /> : null}\n\t\t\t\t{showCopyButton ? <CopyButton /> : null}\n\t\t\t</div>\n\t\t\t<pre\n\t\t\t\t{...props}\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'scrollbar-thin scrollbar-thumb-scrollbar',\n\n\t\t\t\t\tprops.className ?? '',\n\t\t\t\t)}\n\t\t\t\t{...updateFilename()}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</pre>\n\t\t</div>\n\t)\n}\n\nexport const mdxComponents = {\n\th1: (props: any) => <Heading {...props} as=\"h1\" />,\n\th2: (props: any) => <Heading {...props} as=\"h2\" />,\n\th3: (props: any) => <Heading {...props} as=\"h3\" />,\n\th4: (props: any) => <Heading {...props} as=\"h4\" />,\n\th5: (props: any) => <Heading {...props} as=\"h5\" />,\n\th6: (props: any) => <Heading {...props} as=\"h6\" />,\n\ta: AnchorOrLink,\n\t// you can't put a <form> inside a <p> so we'll just use a div\n\t// if this is a problem, then render the form outside of the MDX and update <LaunchEditor /> to reference that one instead or something.\n\tp: (props: any) => <div {...props} />,\n\tpre: (props: any) => (\n\t\t<pre\n\t\t\t{...props}\n\t\t\tclassName={clsx(\n\t\t\t\t'scrollbar-thin scrollbar-thumb-scrollbar',\n\n\t\t\t\tprops.className ?? '',\n\t\t\t)}\n\t\t/>\n\t),\n\tLaunchEditor,\n\tVideoEmbed,\n\tEpicVideo: DeferredEpicVideo,\n\tMermaid,\n}\n\n/**\n * This should be rendered within a useMemo\n * @param code the code to get the component from\n * @returns the component\n */\nfunction getMdxComponent(code: string) {\n\tconst Component = mdxBundler.getMDXComponent(code)\n\tfunction EpicMdxComponent({\n\t\tcomponents: externalComponents,\n\t\t...rest\n\t}: Parameters<typeof Component>['0']) {\n\t\tconst components = useMemo(\n\t\t\t() => ({ ...mdxComponents, ...externalComponents }),\n\t\t\t[externalComponents],\n\t\t)\n\t\treturn <Component components={components} {...rest} />\n\t}\n\treturn EpicMdxComponent\n}\n\n// This exists so we don't have to call new Function for the given code\n// for every request for a given blog post/mdx file.\nconst mdxComponentCache = new LRUCache<\n\tstring,\n\tReturnType<typeof getMdxComponent>\n>({ max: 1000 })\n\nexport function useMdxComponent(code: string) {\n\treturn useMemo(() => {\n\t\tif (mdxComponentCache.has(code)) {\n\t\t\treturn mdxComponentCache.get(code)!\n\t\t}\n\t\tconst component = getMdxComponent(code)\n\t\tmdxComponentCache.set(code, component)\n\t\treturn component\n\t}, [code])\n}\n\nexport function Mdx({\n\tcode,\n\tcomponents: externalComponents,\n}: {\n\tcode: string\n\tcomponents?: MDXContentProps['components']\n}) {\n\tconst Component = useMdxComponent(code)\n\tconst components = useMemo(\n\t\t() => ({ Icon, pre: PreWithButtons, Link, ...externalComponents }),\n\t\t[externalComponents],\n\t)\n\treturn <Component components={components} />\n}\n","import { getExercises } from '@epic-web/workshop-utils/apps.server'\nimport type z from 'zod'\nimport { type error404Schema } from './error-boundary.tsx'\n\nexport async function getStep404Data({\n\texerciseNumber: exerciseNumberString,\n}: {\n\texerciseNumber: string\n}) {\n\t// Get exercise info for the 404 error\n\tconst exerciseNumber = Number(exerciseNumberString)\n\tlet exerciseTitle = 'Untitled Exercise'\n\tconst availableSteps: Array<{\n\t\tstepNumber: number\n\t\ttitle: string\n\t\thasProblem: boolean\n\t\thasSolution: boolean\n\t}> = []\n\n\ttry {\n\t\tconst exercises = await getExercises()\n\t\tconst exercise = exercises.find((e) => e.exerciseNumber === exerciseNumber)\n\t\tif (!exercise) {\n\t\t\treturn getExercise404Data({ exercises })\n\t\t}\n\t\texerciseTitle = exercise.title\n\t\tfor (const step of exercise.steps) {\n\t\t\tif (!step.problem && !step.solution) continue\n\n\t\t\tavailableSteps.push({\n\t\t\t\tstepNumber: step.stepNumber,\n\t\t\t\ttitle: step.problem?.title ?? step.solution?.title ?? 'Untitled Step',\n\t\t\t\thasProblem: Boolean(step.problem),\n\t\t\t\thasSolution: Boolean(step.solution),\n\t\t\t})\n\t\t}\n\t} catch {}\n\n\treturn {\n\t\ttype: 'step-not-found',\n\t\tsteps: availableSteps.sort((a, b) => a.stepNumber - b.stepNumber),\n\t\texerciseNumber,\n\t\texerciseTitle,\n\t} satisfies z.infer<typeof error404Schema>\n}\n\nexport function getExercise404Data({\n\texercises,\n}: {\n\texercises: Array<\n\t\tPick<\n\t\t\tAwaited<ReturnType<typeof getExercises>>[number],\n\t\t\t'title' | 'exerciseNumber'\n\t\t>\n\t>\n}) {\n\treturn {\n\t\ttype: 'exercise-not-found',\n\t\texercises: exercises.map((e) => ({\n\t\t\ttitle: e.title,\n\t\t\tnumber: e.exerciseNumber,\n\t\t})),\n\t} satisfies z.infer<typeof error404Schema>\n}\n","import { href, Link, type ErrorResponse } from 'react-router'\nimport z from 'zod'\n\nexport const error404Schema = z.discriminatedUnion('type', [\n\tz.object({\n\t\ttype: z.literal('step-not-found'),\n\t\tsteps: z.array(\n\t\t\tz.object({\n\t\t\t\tstepNumber: z.number(),\n\t\t\t\ttitle: z.string(),\n\t\t\t\thasProblem: z.boolean(),\n\t\t\t\thasSolution: z.boolean(),\n\t\t\t}),\n\t\t),\n\t\texerciseNumber: z.number(),\n\t\texerciseTitle: z.string(),\n\t}),\n\tz.object({\n\t\ttype: z.literal('exercise-not-found'),\n\t\texercises: z.array(\n\t\t\tz.object({\n\t\t\t\ttitle: z.string(),\n\t\t\t\tnumber: z.number(),\n\t\t\t}),\n\t\t),\n\t}),\n])\n\nexport function Exercise404ErrorBoundary({\n\terror,\n\tparams,\n}: {\n\terror: ErrorResponse\n\tparams: Record<string, string | undefined>\n}) {\n\tconsole.log(error)\n\tconst validationResult = error404Schema.safeParse(error.data)\n\tconst label = [params.exerciseNumber, params.stepNumber, params.type]\n\t\t.filter(Boolean)\n\t\t.join('.')\n\n\tif (!validationResult.success) {\n\t\tconsole.error(\n\t\t\t'Invalid 404 error response data',\n\t\t\tvalidationResult.error,\n\t\t\terror,\n\t\t)\n\t\treturn <p className=\"text-2xl font-bold\">\"{label}\" not found</p>\n\t}\n\tconst { data } = validationResult\n\tif (data.type === 'step-not-found') {\n\t\tconst { steps, exerciseNumber } = data\n\n\t\treturn (\n\t\t\t<div className=\"prose\">\n\t\t\t\t<p className=\"text-2xl font-bold\">Step not found for \"{label}\"</p>\n\t\t\t\t{steps.length > 0 ? (\n\t\t\t\t\t<div className=\"text-lg\">\n\t\t\t\t\t\t<p id=\"available-steps-heading\">Available Steps:</p>\n\t\t\t\t\t\t<ul\n\t\t\t\t\t\t\tclassName=\"m-0 list-inside list-none pl-4\"\n\t\t\t\t\t\t\taria-labelledby=\"available-steps-heading\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{steps.map((step) => (\n\t\t\t\t\t\t\t\t<li key={step.stepNumber} className=\"mb-2\">\n\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">\n\t\t\t\t\t\t\t\t\t\t{step.stepNumber}. {step.title}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t<div className=\"ml-4 flex gap-4\">\n\t\t\t\t\t\t\t\t\t\t{step.hasProblem ? (\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={href(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'/exercise/:exerciseNumber/:stepNumber/:type',\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber: String(exerciseNumber).padStart(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber: String(step.stepNumber).padStart(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t💪 Problem\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t{step.hasSolution ? (\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={href(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'/exercise/:exerciseNumber/:stepNumber/:type',\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber: String(exerciseNumber).padStart(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber: String(step.stepNumber).padStart(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t🏁 Solution\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t) : (\n\t\t\t\t\t<p>\n\t\t\t\t\t\tNo steps are available for this exercise.{' '}\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tto={href('/exercise/:exerciseNumber', {\n\t\t\t\t\t\t\t\texerciseNumber: String(exerciseNumber).padStart(2, '0'),\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tView Exercise\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t)\n\t} else if (data.type === 'exercise-not-found') {\n\t\tconst { exercises } = data\n\t\treturn (\n\t\t\t<div className=\"prose\">\n\t\t\t\t<p className=\"text-2xl font-bold\">Exercise not found for \"{label}\"</p>\n\t\t\t\t<div className=\"text-lg\">\n\t\t\t\t\t<p id=\"available-exercises-heading\">Available Exercises:</p>\n\t\t\t\t\t<ul\n\t\t\t\t\t\tclassName=\"m-0 list-inside list-none pl-4\"\n\t\t\t\t\t\taria-labelledby=\"available-exercises-heading\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{exercises.map((exercise) => (\n\t\t\t\t\t\t\t<li key={exercise.number}>\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={href('/exercise/:exerciseNumber', {\n\t\t\t\t\t\t\t\t\t\texerciseNumber: String(exercise.number).padStart(2, '0'),\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{exercise.number}. {exercise.title}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\tthrow new Error(`Unknown error type: ${(data as any).type}`)\n\t}\n}\n","import path from 'path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopRoot,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { type Route } from './+types/$exerciseNumber.tsx'\nimport { getExercise404Data } from './__shared/error-boundary.server.ts'\nimport { Exercise404ErrorBoundary } from './__shared/error-boundary.tsx'\n\nexport const meta: Route.MetaFunction = ({ loaderData, matches }) => {\n\tconst number = loaderData?.exercise.exerciseNumber.toString().padStart(2, '0')\n\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!loaderData || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `📝 | ${number}. ${loaderData.exercise.title} | ${rootData?.workshopTitle}`,\n\t\tdescription: `Introduction for ${number}. ${loaderData.exercise.title}`,\n\t\togTitle: loaderData.exercise.title,\n\t\togDescription: `Introduction for exercise ${Number(number)}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('exerciseNumberLoader')\n\tinvariantResponse(params.exerciseNumber, 'exerciseNumber is required')\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst exercises = await time(() => getExercises({ request, timings }), {\n\t\ttimings,\n\t\ttype: 'getExercises',\n\t\tdesc: 'getExercises in $exerciseNumber.tsx',\n\t})\n\tconst exercise = exercises.find(\n\t\t(e) => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tif (!exercise) {\n\t\tthrow Response.json(getExercise404Data({ exercises }), { status: 404 })\n\t}\n\n\tconst readmeFilepath = path.join(\n\t\tgetWorkshopRoot(),\n\t\t'exercises',\n\t\texercise.dirName,\n\t\t'README.mdx',\n\t)\n\n\tconst firstStep = exercise.steps.find(Boolean)\n\n\tconst articleId = `workshop-${slugify(workshopTitle)}-${\n\t\texercise.exerciseNumber\n\t}-instructions`\n\n\treturn data(\n\t\t{\n\t\t\tarticleId,\n\t\t\texercise,\n\t\t\texerciseNumber: exercise.exerciseNumber,\n\t\t\texerciseReadme: {\n\t\t\t\tfile: readmeFilepath,\n\t\t\t\trelativePath: `exercises/${exercise.dirName}/README.mdx`,\n\t\t\t},\n\t\t\texerciseTitle: exercise.title,\n\t\t\tfirstStep,\n\t\t\tfirstType: firstStep?.problem ? 'problem' : 'solution',\n\t\t\ttitle: workshopTitle,\n\t\t\tepicVideoInfosPromise: getEpicVideoInfos(\n\t\t\t\texercise.instructionsEpicVideoEmbeds,\n\t\t\t\t{ request },\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\n// we'll render the title ourselves thank you\nconst mdxComponents = { h1: () => null }\n\nexport default function ExerciseNumberRoute({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tuseRevalidationWS({\n\t\twatchPaths: [data.exerciseReadme.file],\n\t})\n\n\tconst firstStepNumber = String(data.firstStep?.stepNumber ?? '01').padStart(\n\t\t2,\n\t\t'0',\n\t)\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tkey={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold\">\n\t\t\t\t\t\t{data.exercise.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t{data.exercise.instructionsCode ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.exercise.instructionsCode}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No instructions yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration\n\t\t\t\telementQuery={`#${data.articleId}`}\n\t\t\t\tkey={`scroll-${data.articleId}`}\n\t\t\t/>\n\t\t\t<ProgressToggle\n\t\t\t\ttype=\"instructions\"\n\t\t\t\texerciseNumber={data.exerciseNumber}\n\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t/>\n\t\t\t<div className=\"flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t<div />\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.exerciseReadme.file}\n\t\t\t\t\trelativePath={data.exerciseReadme.relativePath}\n\t\t\t\t/>\n\t\t\t\t<Link\n\t\t\t\t\tto={`${firstStepNumber}/${data.firstType}`}\n\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\tclassName=\"bg-foreground text-background flex h-full items-center justify-center px-7\"\n\t\t\t\t\tdata-keyboard-action=\"g+n\"\n\t\t\t\t>\n\t\t\t\t\tStart Learning\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tclassName=\"container flex items-center justify-center\"\n\t\t\tstatusHandlers={{\n\t\t\t\t404: Exercise404ErrorBoundary,\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import { Link, type LinkProps } from 'react-router'\nimport { Icon } from './icons.tsx'\n\nexport function NavChevrons({\n\tprev,\n\tnext,\n}: {\n\tprev?: LinkProps | null\n\tnext?: LinkProps | null\n}) {\n\treturn (\n\t\t<div className=\"relative flex h-full overflow-hidden\">\n\t\t\t{prev ? (\n\t\t\t\t<Link\n\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t{...prev}\n\t\t\t\t\tdata-keyboard-action=\"g+p\"\n\t\t\t\t\tclassName=\"group flex h-full items-center justify-center border-l px-7\"\n\t\t\t\t\tchildren={\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"ChevronLeft\"\n\t\t\t\t\t\t\t\tclassName=\"absolute opacity-100 transition duration-300 ease-in-out group-hover:translate-y-10 group-hover:opacity-0\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"ChevronLeft\"\n\t\t\t\t\t\t\t\tclassName=\"absolute -translate-y-10 opacity-0 transition duration-300 ease-in-out group-hover:translate-y-0 group-hover:opacity-100\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t{next ? (\n\t\t\t\t<Link\n\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t{...next}\n\t\t\t\t\tdata-keyboard-action=\"g+n\"\n\t\t\t\t\tclassName=\"group flex h-full items-center justify-center border-l px-7\"\n\t\t\t\t\tchildren={\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"ChevronRight\"\n\t\t\t\t\t\t\t\tclassName=\"absolute opacity-100 transition duration-300 ease-in-out group-hover:translate-y-10 group-hover:opacity-0\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tname=\"ChevronRight\"\n\t\t\t\t\t\t\t\tclassName=\"absolute -translate-y-10 opacity-0 transition duration-300 ease-in-out group-hover:translate-y-0 group-hover:opacity-100\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t</div>\n\t)\n}\n","import {\n\tgetAppByName,\n\tgetApps,\n\tisPlaygroundApp,\n\tisProblemApp,\n\tisSolutionApp,\n\tsetPlayground,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport * as Select from '@radix-ui/react-select'\nimport { clsx } from 'clsx'\nimport { type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { z } from 'zod'\nimport { Icon } from '#app/components/icons.tsx'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { ensureUndeployed, getErrorMessage } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nconst SetPlaygroundSchema = z.object({\n\tappName: z.string(),\n\treset: z\n\t\t.string()\n\t\t.nullable()\n\t\t.optional()\n\t\t.transform((v) => v === 'true'),\n})\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst rawData = {\n\t\tappName: formData.get('appName'),\n\t\tredirectTo: formData.get('redirectTo'),\n\t}\n\tconst result = SetPlaygroundSchema.safeParse(rawData)\n\tif (!result.success) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ status: 'error', error: result.error.message } as const,\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\tconst form = result.data\n\tconst app = await getAppByName(form.appName)\n\tif (!app) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ status: 'error', error: `App ${form.appName} not found` } as const,\n\t\t\t{ status: 404 },\n\t\t)\n\t}\n\tconst converseApp =\n\t\tisProblemApp(app) && app.solutionName\n\t\t\t? await getAppByName(app.solutionName)\n\t\t\t: isSolutionApp(app) && app.problemName\n\t\t\t\t? await getAppByName(app.problemName)\n\t\t\t\t: undefined\n\ttry {\n\t\tawait setPlayground(app.fullPath, { reset: form.reset })\n\t} catch (error: unknown) {\n\t\tconst message = getErrorMessage(error)\n\t\tconsole.error('Error setting playground', message)\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ status: 'error', error: message } as const,\n\t\t\t{\n\t\t\t\tstatus: 500,\n\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\ttitle: 'Error',\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'There was an error setting the playground. Check the terminal for details.',\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t}\n\tconst apps = await getApps({ forceFresh: true })\n\tconst playground = apps.find(isPlaygroundApp)\n\tif (playground && converseApp) {\n\t\tvoid getDiffCode(playground, converseApp, { forceFresh: true })\n\t}\n\treturn dataWithPE(request, formData, { status: 'success' } as const)\n}\n\nexport function SetPlayground({\n\tappName,\n\treset = false,\n\ttooltipText,\n\t...buttonProps\n}: {\n\tappName: string\n\ttooltipText?: string\n\treset?: boolean\n} & React.ComponentProps<'button'>) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\n\tconst submitButton = (\n\t\t<button\n\t\t\ttype=\"submit\"\n\t\t\t{...buttonProps}\n\t\t\tclassName={clsx(\n\t\t\t\tbuttonProps.className,\n\t\t\t\tfetcher.state !== 'idle' ? 'cursor-progress' : null,\n\t\t\t\tfetcher.data?.status === 'error' ? 'cursor-not-allowed' : null,\n\t\t\t)}\n\t\t/>\n\t)\n\treturn (\n\t\t<fetcher.Form\n\t\t\taction=\"/set-playground\"\n\t\t\tmethod=\"POST\"\n\t\t\tclassName=\"inline-flex items-center justify-center\"\n\t\t>\n\t\t\t{peRedirectInput}\n\t\t\t<input type=\"hidden\" name=\"appName\" value={appName} />\n\t\t\t{reset ? <input type=\"hidden\" name=\"reset\" value=\"true\" /> : null}\n\t\t\t{showProgressBarField}\n\t\t\t{tooltipText ? (\n\t\t\t\t<SimpleTooltip content={tooltipText}>{submitButton}</SimpleTooltip>\n\t\t\t) : (\n\t\t\t\tsubmitButton\n\t\t\t)}\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function PlaygroundChooser({\n\tplaygroundAppName,\n\tallApps,\n}: {\n\tplaygroundAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\treturn (\n\t\t<Select.Root\n\t\t\tname=\"appName\"\n\t\t\tvalue={playgroundAppName}\n\t\t\tonValueChange={(appName) => {\n\t\t\t\tvoid fetcher.submit(\n\t\t\t\t\t{ appName },\n\t\t\t\t\t{ method: 'POST', action: '/set-playground' },\n\t\t\t\t)\n\t\t\t}}\n\t\t>\n\t\t\t<Select.Trigger\n\t\t\t\taria-label=\"Select app for playground\"\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'radix-placeholder:text-gray-500 flex h-full w-full items-center justify-between text-left focus-visible:outline-none',\n\t\t\t\t\tfetcher.state !== 'idle' ? 'cursor-progress' : null,\n\t\t\t\t\tfetcher.data?.status === 'error' ? 'cursor-not-allowed' : null,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<span className=\"scrollbar-thin scrollbar-thumb-scrollbar w-80 flex-1 overflow-hidden text-ellipsis whitespace-nowrap\">\n\t\t\t\t\t<Select.Value\n\t\t\t\t\t\tplaceholder=\"Select current app\"\n\t\t\t\t\t\tclassName=\"inline-block w-40 text-ellipsis\"\n\t\t\t\t\t/>\n\t\t\t\t</span>\n\t\t\t\t<Select.Icon>\n\t\t\t\t\t<Icon name=\"TriangleDownSmall\" />\n\t\t\t\t</Select.Icon>\n\t\t\t</Select.Trigger>\n\t\t\t<Select.Portal>\n\t\t\t\t<Select.Content\n\t\t\t\t\tposition=\"popper\"\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]\"\n\t\t\t\t>\n\t\t\t\t\t<Select.ScrollUpButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronUp\" />\n\t\t\t\t\t</Select.ScrollUpButton>\n\t\t\t\t\t<Select.Viewport className=\"p-3\">\n\t\t\t\t\t\t<Select.Group>\n\t\t\t\t\t\t\t<Select.Label className=\"px-5 pb-3 font-mono uppercase\">\n\t\t\t\t\t\t\t\tApp\n\t\t\t\t\t\t\t</Select.Label>\n\t\t\t\t\t\t\t{allApps\n\t\t\t\t\t\t\t\t.filter((app) => app.name !== 'playground')\n\t\t\t\t\t\t\t\t.map((app) => {\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<SelectItem key={app.name} value={app.name}>\n\t\t\t\t\t\t\t\t\t\t\t{app.displayName}\n\t\t\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</Select.Group>\n\t\t\t\t\t</Select.Viewport>\n\t\t\t\t\t<Select.ScrollDownButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronDown\" />\n\t\t\t\t\t</Select.ScrollDownButton>\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Portal>\n\t\t</Select.Root>\n\t)\n}\n\nfunction SelectItem({\n\tvalue,\n\tchildren,\n}: {\n\tvalue: string\n\tchildren: React.ReactNode\n}) {\n\treturn (\n\t\t<Select.Item\n\t\t\tvalue={value}\n\t\t\tclassName=\"radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100 relative flex cursor-pointer items-center rounded px-10 py-2 leading-none opacity-80 select-none\"\n\t\t>\n\t\t\t<Select.ItemText>{children}</Select.ItemText>\n\t\t\t<Select.ItemIndicator className=\"absolute left-0 inline-flex w-[25px] items-center justify-center\">\n\t\t\t\t<Icon name=\"CheckSmall\" />\n\t\t\t</Select.ItemIndicator>\n\t\t</Select.Item>\n\t)\n}\n\nexport function SetAppToPlayground({\n\tappName,\n\tisOutdated,\n}: {\n\tappName: string\n\tisOutdated?: boolean\n}) {\n\tif (ENV.EPICSHOP_DEPLOYED) return null\n\treturn (\n\t\t<SetPlayground\n\t\t\tappName={appName}\n\t\t\ttooltipText={\n\t\t\t\tisOutdated\n\t\t\t\t\t? 'The app the playground was set to has been updated. Click to update to the latest version.'\n\t\t\t\t\t: 'Playground is not set to the right app. Click to set Playground.'\n\t\t\t}\n\t\t>\n\t\t\t<span className=\"text-foreground-destructive flex items-center justify-center gap-1 hover:underline\">\n\t\t\t\t<Icon name=\"Unlinked\" className=\"animate-ping\" />{' '}\n\t\t\t\t<span className=\"uppercase\">\n\t\t\t\t\t{isOutdated ? 'Playground Outdated' : 'Set to Playground'}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</SetPlayground>\n\t)\n}\n","import * as React from 'react'\nimport { type PropsWithChildren } from 'react'\nimport {\n\tLink,\n\tuseLoaderData,\n\tuseSearchParams,\n\ttype LinkProps,\n} from 'react-router'\nimport iconsSvg from '#app/assets/icons.svg'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { type loader } from '../_layout.tsx'\n\ntype StepContextType = {\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}\nconst StepContext = React.createContext<StepContextType | null>(null)\n\nfunction useStepContext() {\n\tconst context = React.useContext(StepContext)\n\tif (!context) {\n\t\tthrow new Error('useStepContext must be used within a StepContextProvider')\n\t}\n\treturn context\n}\n\nfunction StepContextProvider({\n\tchildren,\n\tinBrowserBrowserRef,\n}: {\n\tchildren: React.ReactNode\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\treturn <StepContext value={{ inBrowserBrowserRef }}>{children}</StepContext>\n}\n\nconst stepMdxComponents = {\n\tDiffLink,\n\tPrevDiffLink,\n\tNextDiffLink,\n\tInlineFile,\n\tLinkToApp,\n}\n\nexport function StepMdx({\n\tinBrowserBrowserRef,\n}: {\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tif (!data.exerciseStepApp.instructionsCode) return null\n\treturn (\n\t\t<StepContextProvider inBrowserBrowserRef={inBrowserBrowserRef}>\n\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={data.epicVideoInfosPromise}>\n\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t<Mdx\n\t\t\t\t\t\tcode={data.exerciseStepApp.instructionsCode}\n\t\t\t\t\t\tcomponents={stepMdxComponents}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</EpicVideoInfoProvider>\n\t\t</StepContextProvider>\n\t)\n}\n\nfunction withParam(\n\tsearchParams: URLSearchParams,\n\tkey: string,\n\tvalue: string | null,\n) {\n\tconst newSearchParams = new URLSearchParams(searchParams)\n\tif (value === null) {\n\t\tnewSearchParams.delete(key)\n\t} else {\n\t\tnewSearchParams.set(key, value)\n\t}\n\treturn newSearchParams\n}\n\nfunction NextDiffLink({\n\tapp = 0,\n\tfullPage = false,\n\tchildren,\n}: {\n\tapp: number\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\treturn (\n\t\t<DiffLink app1={app} app2={app + 1} fullPage={fullPage}>\n\t\t\t{children}\n\t\t</DiffLink>\n\t)\n}\n\nfunction PrevDiffLink({\n\tapp = -1,\n\tfullPage = false,\n\tchildren,\n}: {\n\tapp: number\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\treturn (\n\t\t<DiffLink app1={app} app2={app + 1} fullPage={fullPage}>\n\t\t\t{children}\n\t\t</DiffLink>\n\t)\n}\n\nfunction DiffLink({\n\tapp1 = 0,\n\tapp2 = 1,\n\tchildren,\n\tfullPage = false,\n\tto,\n}: {\n\tapp1?: string | number | null\n\tapp2?: string | number | null\n\tto?: string\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tif (!to && !app1 && !app2) {\n\t\treturn (\n\t\t\t<callout-danger className=\"notification\">\n\t\t\t\t<div className=\"title\">DiffLink Error: invalid input</div>\n\t\t\t</callout-danger>\n\t\t)\n\t}\n\n\tfunction getAppName(input: typeof app1) {\n\t\tif (typeof input === 'number') {\n\t\t\tconst stepIndex = data.exerciseIndex + input\n\t\t\treturn data.allApps[stepIndex]?.name\n\t\t}\n\t\tif (!input) return null\n\t\tfor (const { name, stepName } of data.allApps) {\n\t\t\tif (input === name || input === stepName) {\n\t\t\t\treturn name\n\t\t\t}\n\t\t}\n\t\treturn null\n\t}\n\n\tif (to) {\n\t\tconst params = new URLSearchParams(to)\n\t\tapp1 = params.get('app1')\n\t\tapp2 = params.get('app2')\n\t}\n\tconst app1Name = getAppName(app1)\n\tconst app2Name = getAppName(app2)\n\tif (!app1Name || !app2Name) {\n\t\treturn (\n\t\t\t<callout-danger className=\"notification\">\n\t\t\t\t<div className=\"title\">DiffLink Error: invalid input</div>\n\t\t\t\t{!app1Name && <div>app1: \"{app1}\" is not a valid app name</div>}\n\t\t\t\t{!app2Name && <div>app2: \"{app2}\" is not a valid app name</div>}\n\t\t\t</callout-danger>\n\t\t)\n\t}\n\n\tif (!to) {\n\t\tto = `app1=${app1Name}&app2=${app2Name}`\n\t}\n\tconst pathToDiff = fullPage\n\t\t? `/diff?${to}`\n\t\t: `?${decodeURIComponent(\n\t\t\t\twithParam(new URLSearchParams(), 'preview', `diff&${to}`).toString(),\n\t\t\t)}`\n\n\tif (!children) {\n\t\tchildren = (\n\t\t\t<span>\n\t\t\t\tGo to Diff {fullPage ? '' : 'Preview'} from: <code>{app1Name}</code> to:{' '}\n\t\t\t\t<code>{app2Name}</code>\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn <Link to={pathToDiff}>{children}</Link>\n}\n\nfunction InlineFile({\n\tfile,\n\ttype = 'playground',\n\tchildren = <code>{file}</code>,\n\t...props\n}: Omit<PropsWithChildren<typeof LaunchEditor>, 'appName'> & {\n\tfile: string\n\ttype?: 'playground' | 'solution' | 'problem'\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst app = data[type] || data[data.type]\n\n\tconst info = (\n\t\t<div className=\"launch-editor-button-wrapper flex underline underline-offset-4\">\n\t\t\t{children}{' '}\n\t\t\t<svg height={24} width={24}>\n\t\t\t\t<use href={`${iconsSvg}#Keyboard`} />\n\t\t\t</svg>\n\t\t</div>\n\t)\n\n\treturn ENV.EPICSHOP_DEPLOYED && app ? (\n\t\t<div className=\"inline-block grow\">\n\t\t\t<LaunchEditor appFile={file} appName={app.name} {...props}>\n\t\t\t\t{info}\n\t\t\t</LaunchEditor>\n\t\t</div>\n\t) : app ? (\n\t\t<div className=\"inline-block grow\">\n\t\t\t<LaunchEditor appFile={file} appName={app.name} {...props}>\n\t\t\t\t{info}\n\t\t\t</LaunchEditor>\n\t\t</div>\n\t) : type === 'playground' ? (\n\t\t// playground does not exist yet\n\t\t<SimpleTooltip content=\"You must 'Set to Playground' before opening a file\">\n\t\t\t<div className=\"inline-block grow cursor-not-allowed\">{info}</div>\n\t\t</SimpleTooltip>\n\t) : (\n\t\t<>children</>\n\t)\n}\n\nfunction getPreviewType(\n\tpreview: string | null,\n): 'playground' | 'problem' | 'solution' {\n\tif (preview === 'problem') return 'problem'\n\tif (preview === 'solution') return 'solution'\n\treturn 'playground'\n}\n\nfunction LinkToApp({\n\tto: appTo,\n\tchildren = <code>{appTo.toString()}</code>,\n\t...props\n}: LinkProps) {\n\tconst [searchParams] = useSearchParams()\n\tconst to = `?${withParam(\n\t\tsearchParams,\n\t\t'pathname',\n\t\tappTo.toString(),\n\t).toString()}`\n\tconst data = useLoaderData<typeof loader>()\n\tconst type = getPreviewType(searchParams.get('preview'))\n\tconst requestInfo = useRequestInfo()\n\tconst app = data[type]\n\tconst previewAppUrl =\n\t\tapp?.dev.type === 'script'\n\t\t\t? getBaseUrl({\n\t\t\t\t\tdomain: requestInfo.domain,\n\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t})\n\t\t\t: data.playground?.dev.type === 'browser' ||\n\t\t\t\t data.playground?.dev.type === 'export'\n\t\t\t\t? data.playground.dev.pathname\n\t\t\t\t: null\n\tconst { inBrowserBrowserRef } = useStepContext()\n\tconst href = previewAppUrl\n\t\t? previewAppUrl.slice(0, -1) + appTo.toString()\n\t\t: null\n\treturn (\n\t\t<div className=\"inline-flex items-center justify-between gap-1\">\n\t\t\t<Link\n\t\t\t\tto={to}\n\t\t\t\t{...props}\n\t\t\t\tclassName={cn(props.className, {\n\t\t\t\t\t'cursor-not-allowed': ENV.EPICSHOP_DEPLOYED,\n\t\t\t\t})}\n\t\t\t\ttitle={\n\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t? 'Cannot link to app in deployed version'\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\tif (ENV.EPICSHOP_DEPLOYED) event.preventDefault()\n\n\t\t\t\t\tprops.onClick?.(event)\n\t\t\t\t\tinBrowserBrowserRef.current?.handleExtrnalNavigation(appTo.toString())\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Link>\n\t\t\t{href ? (\n\t\t\t\t<SimpleTooltip content=\"Open in new tab\">\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={href}\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\tclassName={cn('flex aspect-square items-center justify-center', {\n\t\t\t\t\t\t\t'cursor-not-allowed': ENV.EPICSHOP_DEPLOYED,\n\t\t\t\t\t\t})}\n\t\t\t\t\t\ttitle={\n\t\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t\t? 'Cannot link to app in deployed version'\n\t\t\t\t\t\t\t\t: 'Open in new tab'\n\t\t\t\t\t\t}\n\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\tif (ENV.EPICSHOP_DEPLOYED) event.preventDefault()\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t</a>\n\t\t\t\t</SimpleTooltip>\n\t\t\t) : null}\n\t\t</div>\n\t)\n}\n","import * as Popover from '@radix-ui/react-popover'\nimport * as React from 'react'\nimport { Await, useLoaderData } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { SetAppToPlayground } from '#app/routes/set-playground.tsx'\nimport { type Route as LayoutRoute } from '../+types/_layout.tsx'\n\nfunction TouchedFiles({\n\tdiffFilesPromise,\n\tcompact = false,\n}: {\n\tdiffFilesPromise: LayoutRoute.ComponentProps['loaderData']['diffFiles']\n\tcompact?: boolean\n}) {\n\tconst data = useLoaderData<LayoutRoute.ComponentProps['loaderData']>()\n\n\tconst [open, setOpen] = React.useState(false)\n\tconst contentRef = React.useRef<HTMLDivElement>(null)\n\n\tfunction handleLaunchUpdate() {\n\t\tsetOpen(false)\n\t}\n\n\tconst appName = data.playground?.appName\n\n\treturn (\n\t\t<>\n\t\t\t<Popover.Root open={open} onOpenChange={setOpen}>\n\t\t\t\t<Popover.Trigger asChild>\n\t\t\t\t\t<button\n\t\t\t\t\t\tclassName=\"flex h-full items-center gap-1 border-r px-6 py-3 font-mono text-sm uppercase\"\n\t\t\t\t\t\taria-label=\"Relevant Files\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Files\" />\n\t\t\t\t\t\t{compact ? null : <span className=\"hidden xl:inline\">Files</span>}\n\t\t\t\t\t</button>\n\t\t\t\t</Popover.Trigger>\n\t\t\t\t<Popover.Portal>\n\t\t\t\t\t<Popover.Content\n\t\t\t\t\t\tref={contentRef}\n\t\t\t\t\t\tclassName=\"slideRightContent lg:slideUpContent invert-theme bg-background text-foreground z-10 rounded px-9 py-8 select-none\"\n\t\t\t\t\t\talign=\"start\"\n\t\t\t\t\t\tsideOffset={5}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"launch-editor-wrapper\">\n\t\t\t\t\t\t\t<strong className=\"inline-block px-2 pb-4 font-semibold uppercase\">\n\t\t\t\t\t\t\t\tRelevant Files\n\t\t\t\t\t\t\t</strong>\n\t\t\t\t\t\t\t{data.problem &&\n\t\t\t\t\t\t\tdata.playground?.appName !== data.problem.name ? (\n\t\t\t\t\t\t\t\t<div className=\"mb-2 rounded p-1 font-mono font-medium\">\n\t\t\t\t\t\t\t\t\t<SetAppToPlayground appName={data.problem.name} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<div id=\"files\">\n\t\t\t\t\t\t\t\t<React.Suspense\n\t\t\t\t\t\t\t\t\tfallback={\n\t\t\t\t\t\t\t\t\t\t<SimpleTooltip content=\"Loading diff\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex justify-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"h-8 w-8 animate-spin\" />\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Await\n\t\t\t\t\t\t\t\t\t\tresolve={diffFilesPromise}\n\t\t\t\t\t\t\t\t\t\terrorElement={\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\tSomething went wrong.\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{(diffFiles) => {\n\t\t\t\t\t\t\t\t\t\t\tif (!diffFiles) {\n\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tUnable to determine diff\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tif (typeof diffFiles === 'string') {\n\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tif (!diffFiles.length) {\n\t\t\t\t\t\t\t\t\t\t\t\treturn <p>No files changed</p>\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tconst props =\n\t\t\t\t\t\t\t\t\t\t\t\tappName || ENV.EPICSHOP_GITHUB_ROOT\n\t\t\t\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"You must 'Set to Playground' before opening a file\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName: 'not-allowed',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<ul {...props}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles.length > 1 && !ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"border-opacity-50 mb-2 border-b border-b-gray-50 pb-2 font-sans\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappFile={diffFiles.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(file) => `${file.path},${file.line},1`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappName=\"playground\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonUpdate={handleLaunchUpdate}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<p>Open All Files</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles.map((file) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li key={file.path} data-state={file.status}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappFile={`${file.path},${file.line},1`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappName={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? (data.problem?.name ?? 'playground')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'playground'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonUpdate={handleLaunchUpdate}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<code>{file.path}</code>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t</Await>\n\t\t\t\t\t\t\t\t</React.Suspense>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</Popover.Content>\n\t\t\t\t</Popover.Portal>\n\t\t\t</Popover.Root>\n\t\t</>\n\t)\n}\n\nexport default TouchedFiles\n","import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetAppDisplayName,\n\tgetAppPageRoute,\n\tgetApps,\n\tgetExerciseApp,\n\tgetNextExerciseApp,\n\tgetPrevExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExercise,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getDiffFiles } from '@epic-web/workshop-utils/diff.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport * as cookie from 'cookie'\nimport { useEffect, useRef, useState } from 'react'\nimport {\n\tLink,\n\tOutlet,\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n} from 'react-router'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { SetAppToPlayground } from '#app/routes/set-playground.tsx'\nimport { getExercisePath } from '#app/utils/misc.tsx'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { getStep404Data } from '../__shared/error-boundary.server.ts'\nimport { Exercise404ErrorBoundary } from '../__shared/error-boundary.tsx'\nimport { type Route } from './+types/_layout.tsx'\nimport { StepMdx } from './__shared/step-mdx.tsx'\nimport TouchedFiles from './__shared/touched-files.tsx'\n\n// shared split state helpers\nconst splitCookieName = 'es_split_pct'\n\nfunction computeSplitPercent(input: unknown, defaultValue = 50): number {\n\tconst value = typeof input === 'number' ? input : Number(input)\n\tif (Number.isFinite(value)) {\n\t\treturn Math.min(80, Math.max(20, Math.round(value * 100) / 100))\n\t}\n\treturn defaultValue\n}\n\nfunction pageTitle(\n\tdata: Awaited<Route.ComponentProps['loaderData']> | undefined,\n\tworkshopTitle?: string,\n) {\n\tconst exerciseNumber =\n\t\tdata?.exerciseStepApp.exerciseNumber.toString().padStart(2, '0') ?? '00'\n\tconst stepNumber =\n\t\tdata?.exerciseStepApp.stepNumber.toString().padStart(2, '0') ?? '00'\n\tconst emoji = (\n\t\t{\n\t\t\tproblem: '💪',\n\t\t\tsolution: '🏁',\n\t\t} as const\n\t)[data?.type ?? 'problem']\n\tconst title = data?.[data.type]?.title ?? 'N/A'\n\treturn {\n\t\temoji,\n\t\tstepNumber,\n\t\ttitle,\n\t\texerciseNumber,\n\t\texerciseTitle: data?.exerciseTitle ?? 'Unknown exercise',\n\t\tworkshopTitle,\n\t\ttype: data?.type ?? 'problem',\n\t}\n}\n\nexport const meta: Route.MetaFunction = ({ loaderData, matches, params }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!loaderData || !rootData) return [{ title: '🦉 | Error' }]\n\tconst { emoji, stepNumber, title, exerciseNumber, exerciseTitle } =\n\t\tpageTitle(loaderData)\n\n\treturn getSeoMetaTags({\n\t\ttitle: `${emoji} | ${stepNumber}. ${title} | ${exerciseNumber}. ${exerciseTitle} | ${rootData.workshopTitle}`,\n\t\tdescription: `${params.type} step for exercise ${exerciseNumber}. ${exerciseTitle}`,\n\t\togTitle: title,\n\t\togDescription: `${exerciseTitle} step ${Number(stepNumber)} ${params.type}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('exerciseStepTypeLayoutLoader')\n\tconst url = new URL(request.url)\n\tconst { type } = params\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\n\tconst cacheOptions = { request, timings }\n\n\tconst [allAppsFull, problemApp, solutionApp] = await Promise.all([\n\t\tgetApps(cacheOptions),\n\t\tgetExerciseApp({ ...params, type: 'problem' }, cacheOptions),\n\t\tgetExerciseApp({ ...params, type: 'solution' }, cacheOptions),\n\t])\n\n\tconst reqUrl = new URL(request.url)\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tif (\n\t\t(type === 'problem' && !problemApp) ||\n\t\t(type === 'solution' && !solutionApp)\n\t) {\n\t\tconst errorData = await getStep404Data({\n\t\t\texerciseNumber: params.exerciseNumber,\n\t\t})\n\t\tthrow Response.json(errorData, { status: 404 })\n\t}\n\n\tconst exerciseStepApp = await requireExerciseApp(params, cacheOptions)\n\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\tconst exerciseId = getStepId(exerciseStepApp)\n\tconst exerciseIndex = allApps.findIndex((step) => step.stepId === exerciseId)\n\n\t// These depend on exerciseStepApp\n\tconst [exercise, nextApp, prevApp] = await Promise.all([\n\t\trequireExercise(exerciseStepApp.exerciseNumber, cacheOptions),\n\t\tgetNextExerciseApp(exerciseStepApp, cacheOptions),\n\t\tgetPrevExerciseApp(exerciseStepApp, cacheOptions),\n\t])\n\n\tconst exerciseApps = allAppsFull\n\t\t.filter(isExerciseStepApp)\n\t\t.filter((app) => app.exerciseNumber === exerciseStepApp.exerciseNumber)\n\tconst isLastStep =\n\t\texerciseApps[exerciseApps.length - 1]?.name === exerciseStepApp.name\n\tconst isFirstStep = exerciseApps[0]?.name === exerciseStepApp.name\n\n\tconst articleId = `workshop-${slugify(workshopTitle)}-${\n\t\texercise.exerciseNumber\n\t}-${exerciseStepApp.stepNumber}-${exerciseStepApp.type}`\n\n\tconst subroute = url.pathname.split(\n\t\t`/exercise/${params.exerciseNumber}/${params.stepNumber}/${params.type}/`,\n\t)[1]\n\n\t// read persisted split percentage from cookie (10-90, default 50)\n\tconst cookieHeader = request.headers.get('cookie')\n\tconst rawSplit = cookieHeader\n\t\t? cookie.parse(cookieHeader)[splitCookieName]\n\t\t: null\n\tconst splitPercent = computeSplitPercent(rawSplit, 50)\n\n\treturn data(\n\t\t{\n\t\t\tarticleId,\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\texerciseTitle: exercise.title,\n\t\t\tepicVideoInfosPromise: getEpicVideoInfos(exerciseStepApp.epicVideoEmbeds),\n\t\t\texerciseIndex,\n\t\t\tallApps,\n\t\t\tsplitPercent,\n\t\t\tprevStepLink: isFirstStep\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${exerciseStepApp.exerciseNumber\n\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t.padStart(2, '0')}`,\n\t\t\t\t\t}\n\t\t\t\t: prevApp\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: getAppPageRoute(prevApp, {\n\t\t\t\t\t\t\t\tsubroute,\n\t\t\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t\tnextStepLink: isLastStep\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${exerciseStepApp.exerciseNumber\n\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t.padStart(2, '0')}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: nextApp\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: getAppPageRoute(nextApp, {\n\t\t\t\t\t\t\t\tsubroute,\n\t\t\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t\tisUpToDate: playgroundApp.isUpToDate,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiffFiles:\n\t\t\t\tproblemApp && solutionApp\n\t\t\t\t\t? getDiffFiles(problemApp, solutionApp, {\n\t\t\t\t\t\t\t...cacheOptions,\n\t\t\t\t\t\t\tforceFresh: url.searchParams.get('forceFresh') === 'diff',\n\t\t\t\t\t\t}).catch((e) => {\n\t\t\t\t\t\t\tconsole.error(e)\n\t\t\t\t\t\t\treturn 'There was a problem generating the diff (check the terminal output)'\n\t\t\t\t\t\t})\n\t\t\t\t\t: 'No diff available',\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nexport default function ExercisePartRoute({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tconst inBrowserBrowserRef = useRef<InBrowserBrowserRef>(null)\n\tconst containerRef = useRef<HTMLDivElement>(null)\n\tconst leftPaneRef = useRef<HTMLDivElement>(null)\n\tconst [splitPercent, setSplitPercent] = useState<number>(data.splitPercent)\n\tconst [leftWidthPx, setLeftWidthPx] = useState<number>(0)\n\n\tuseEffect(() => {\n\t\tconst left = leftPaneRef.current\n\t\tif (!left) return\n\t\tconst ro = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tsetLeftWidthPx(entry.contentRect.width)\n\t\t\t}\n\t\t})\n\t\tro.observe(left)\n\t\tsetLeftWidthPx(left.getBoundingClientRect().width)\n\t\treturn () => ro.disconnect()\n\t}, [])\n\n\tfunction setCookie(percent: number) {\n\t\tconst clamped = computeSplitPercent(percent)\n\t\tdocument.cookie = `${splitCookieName}=${clamped}; path=/; SameSite=Lax;`\n\t}\n\n\tfunction startDrag(initialClientX: number) {\n\t\tconst container = containerRef.current\n\t\tif (!container) return\n\t\tconst rect = container.getBoundingClientRect()\n\t\tlet dragging = true\n\n\t\t// Disable pointer events on iframes so the drag keeps receiving events\n\t\tconst iframes = Array.from(\n\t\t\tdocument.querySelectorAll('iframe'),\n\t\t) as HTMLIFrameElement[]\n\t\tconst originalPointerEvents = iframes.map((el) => el.style.pointerEvents)\n\t\tiframes.forEach((el) => (el.style.pointerEvents = 'none'))\n\n\t\tfunction handleMove(clientX: number) {\n\t\t\t// Safety check: ensure user is still dragging\n\t\t\tif (!dragging) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst relativeX = clientX - rect.left\n\t\t\tconst percent = (relativeX / rect.width) * 100\n\t\t\tconst clamped = computeSplitPercent(percent)\n\t\t\tsetSplitPercent(clamped)\n\t\t\tsetCookie(clamped)\n\t\t}\n\n\t\tfunction onMouseMove(e: MouseEvent) {\n\t\t\tif (!dragging || e.buttons === 0) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandleMove(e.clientX)\n\t\t}\n\t\tfunction onTouchMove(e: TouchEvent) {\n\t\t\tconst firstTouch = e.touches?.[0]\n\t\t\tif (!dragging || !firstTouch) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandleMove(firstTouch.clientX)\n\t\t}\n\t\tfunction cleanup() {\n\t\t\tif (!dragging) return\n\t\t\tdragging = false\n\t\t\tiframes.forEach(\n\t\t\t\t(el, i) => (el.style.pointerEvents = originalPointerEvents[i] ?? ''),\n\t\t\t)\n\t\t\twindow.removeEventListener('mousemove', onMouseMove)\n\t\t\twindow.removeEventListener('mouseup', cleanup)\n\t\t\twindow.removeEventListener('touchmove', onTouchMove)\n\t\t\twindow.removeEventListener('touchend', cleanup)\n\t\t\tdocument.body.style.cursor = ''\n\t\t\tdocument.body.style.userSelect = ''\n\t\t}\n\n\t\twindow.addEventListener('mousemove', onMouseMove)\n\t\twindow.addEventListener('mouseup', cleanup)\n\t\twindow.addEventListener('touchmove', onTouchMove)\n\t\twindow.addEventListener('touchend', cleanup)\n\t\tdocument.body.style.cursor = 'col-resize'\n\t\tdocument.body.style.userSelect = 'none'\n\t\thandleMove(initialClientX)\n\t}\n\n\tconst titleBits = pageTitle(data)\n\n\tuseRevalidationWS({\n\t\twatchPaths: [`${data.exerciseStepApp.relativePath}/README.mdx`],\n\t})\n\n\treturn (\n\t\t<div className=\"flex max-w-full grow flex-col\">\n\t\t\t<main\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName=\"flex grow flex-col sm:h-full sm:min-h-[800px] md:min-h-[unset] lg:flex-row\"\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"relative flex min-w-0 flex-none basis-full flex-col sm:col-span-1 sm:row-span-1 sm:h-full lg:basis-(--split-pct)\"\n\t\t\t\t\tstyle={{ ['--split-pct' as any]: `${splitPercent}%` }}\n\t\t\t\t\tref={leftPaneRef}\n\t\t\t\t>\n\t\t\t\t\t<h1 className=\"h-14 border-b pr-5 pl-10 text-sm leading-tight font-medium\">\n\t\t\t\t\t\t<div className=\"flex h-14 items-center justify-between gap-x-2 overflow-x-auto py-2 whitespace-nowrap\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2 uppercase\">\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={getExercisePath(data.exerciseStepApp.exerciseNumber)}\n\t\t\t\t\t\t\t\t\tclassName=\"hover:underline\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{titleBits.exerciseNumber}. {titleBits.exerciseTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t{'/'}\n\t\t\t\t\t\t\t\t<Link to=\".\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{titleBits.stepNumber}. {titleBits.title}\n\t\t\t\t\t\t\t\t\t{' ('}\n\t\t\t\t\t\t\t\t\t{titleBits.emoji} {titleBits.type}\n\t\t\t\t\t\t\t\t\t{')'}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{data.problem &&\n\t\t\t\t\t\t\t(data.playground?.appName !== data.problem.name ||\n\t\t\t\t\t\t\t\t!data.playground?.isUpToDate) ? (\n\t\t\t\t\t\t\t\t<div className=\"hidden md:block\">\n\t\t\t\t\t\t\t\t\t<SetAppToPlayground\n\t\t\t\t\t\t\t\t\t\tappName={data.problem.name}\n\t\t\t\t\t\t\t\t\t\tisOutdated={data.playground?.isUpToDate === false}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t\tkey={data.articleId}\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex h-full w-full max-w-none flex-1 scroll-pt-6 flex-col justify-between space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.exerciseStepApp.instructionsCode ? (\n\t\t\t\t\t\t\t<StepMdx inBrowserBrowserRef={inBrowserBrowserRef} />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t\t\t\t\t<p>No instructions yet...</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<div className=\"mt-auto flex justify-between\">\n\t\t\t\t\t\t\t{data.prevStepLink ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={data.prevStepLink.to}\n\t\t\t\t\t\t\t\t\taria-label=\"Previous Step\"\n\t\t\t\t\t\t\t\t\tdata-keyboard-action=\"g+p\"\n\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span aria-hidden>←</span>\n\t\t\t\t\t\t\t\t\t<span className=\"hidden xl:inline\"> Previous</span>\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<span />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{data.nextStepLink ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={data.nextStepLink.to}\n\t\t\t\t\t\t\t\t\taria-label=\"Next Step\"\n\t\t\t\t\t\t\t\t\tdata-keyboard-action=\"g+n\"\n\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"hidden xl:inline\">Next </span>\n\t\t\t\t\t\t\t\t\t<span aria-hidden>→</span>\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<span />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration\n\t\t\t\t\t\telementQuery={`#${data.articleId}`}\n\t\t\t\t\t\tkey={`scroll-${data.articleId}`}\n\t\t\t\t\t/>\n\t\t\t\t\t{data.type === 'solution' ? (\n\t\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\texerciseNumber={data.exerciseStepApp.exerciseNumber}\n\t\t\t\t\t\t\tstepNumber={data.exerciseStepApp.stepNumber}\n\t\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<div className=\"h-full\">\n\t\t\t\t\t\t\t\t<TouchedFiles\n\t\t\t\t\t\t\t\t\tdiffFilesPromise={data.diffFiles}\n\t\t\t\t\t\t\t\t\tcompact={leftWidthPx < 640}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\tappName={data.exerciseStepApp.name}\n\t\t\t\t\t\t\trelativePath={`${data.exerciseStepApp.relativePath}/README.mdx`}\n\t\t\t\t\t\t\tcompact={leftWidthPx < 720}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<NavChevrons\n\t\t\t\t\t\t\tprev={\n\t\t\t\t\t\t\t\tdata.prevStepLink\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tto: data.prevStepLink.to,\n\t\t\t\t\t\t\t\t\t\t\t'aria-label': 'Previous Step',\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnext={\n\t\t\t\t\t\t\t\tdata.nextStepLink\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tto: data.nextStepLink.to,\n\t\t\t\t\t\t\t\t\t\t\t'aria-label': 'Next Step',\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div\n\t\t\t\t\trole=\"separator\"\n\t\t\t\t\taria-orientation=\"vertical\"\n\t\t\t\t\ttitle=\"Drag to resize\"\n\t\t\t\t\tclassName=\"bg-border hover:bg-accent hidden w-1 cursor-col-resize lg:block\"\n\t\t\t\t\tonMouseDown={(e) => startDrag(e.clientX)}\n\t\t\t\t\tonDoubleClick={() => {\n\t\t\t\t\t\tsetSplitPercent(50)\n\t\t\t\t\t\tsetCookie(50)\n\t\t\t\t\t}}\n\t\t\t\t\tonTouchStart={(e) => {\n\t\t\t\t\t\tconst firstTouch = e.touches?.[0]\n\t\t\t\t\t\tif (firstTouch) startDrag(firstTouch.clientX)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<div className=\"flex min-w-0 flex-1\">\n\t\t\t\t\t<Outlet context={{ inBrowserBrowserRef }} />\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tclassName=\"container flex items-center justify-center\"\n\t\t\tstatusHandlers={{\n\t\t\t\t404: Exercise404ErrorBoundary,\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import { invariant, invariantResponse } from '@epic-web/invariant'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcloseProcess,\n\trunAppDev,\n\tstopPort,\n\twaitOnApp,\n} from '@epic-web/workshop-utils/process-manager.server'\nimport { data, type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { ensureUndeployed, useAltDown } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server'\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tinvariantResponse(typeof intent === 'string', 'intent is required')\n\n\tif (intent === 'start' || intent === 'stop' || intent === 'restart') {\n\t\tconst name = formData.get('name')\n\t\tinvariantResponse(typeof name === 'string', 'name is required')\n\t\tconst app = await getAppByName(name)\n\t\tif (!app) {\n\t\t\tthrow new Response('Not found', { status: 404 })\n\t\t}\n\t\tif (app.dev.type !== 'script') {\n\t\t\tthrow new Response(`App \"${name}\" does not have a server`, {\n\t\t\t\tstatus: 400,\n\t\t\t})\n\t\t}\n\n\t\tasync function startApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tconst result = await runAppDev(app)\n\t\t\tif (result.running) {\n\t\t\t\tconst appRunningResult = await waitOnApp(app)\n\t\t\t\tif (appRunningResult?.status === 'success') {\n\t\t\t\t\t// wait another 200ms just in case the build output for assets isn't finished\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 200))\n\t\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\t\tstatus: 'app-started',\n\t\t\t\t\t} as const)\n\t\t\t\t} else if (app.dev.type === 'script') {\n\t\t\t\t\tconst errorMessage = appRunningResult\n\t\t\t\t\t\t? appRunningResult.error\n\t\t\t\t\t\t: 'Unknown error'\n\t\t\t\t\treturn data(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t\t\t} as const,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tstatusText: 'App did not start',\n\t\t\t\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\t\t\t\tdescription: errorMessage,\n\t\t\t\t\t\t\t\ttitle: 'App did not start',\n\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else if (result.portNumber) {\n\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\terror: result.status,\n\t\t\t\t\tport: result.portNumber,\n\t\t\t\t} as const)\n\t\t\t} else {\n\t\t\t\tthrow new Response(\n\t\t\t\t\t'Tried starting a server for an app that does not have one',\n\t\t\t\t\t{ status: 400 },\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tasync function stopApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tawait closeProcess(app.name)\n\t\t\treturn dataWithPE(request, formData, { status: 'app-stopped' } as const)\n\t\t}\n\n\t\tswitch (intent) {\n\t\t\tcase 'start': {\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t\tcase 'stop': {\n\t\t\t\treturn stopApp()\n\t\t\t}\n\t\t\tcase 'restart': {\n\t\t\t\tawait stopApp()\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intent === 'stop-port') {\n\t\tconst port = formData.get('port')\n\t\tinvariantResponse(typeof port === 'string', 'port is required')\n\t\tawait stopPort(port)\n\t\treturn dataWithPE(request, formData, { status: 'port-stopped' } as const)\n\t}\n\tthrow new Error(`Unknown intent: ${intent}`)\n}\n\nexport function AppStopper({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst inFlightIntent = fetcher.formData?.get('intent')\n\tconst inFlightState =\n\t\tinFlightIntent === 'stop'\n\t\t\t? 'Stopping App'\n\t\t\t: inFlightIntent === 'restart'\n\t\t\t\t? 'Restarting App'\n\t\t\t\t: null\n\tconst altDown = useAltDown()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tname=\"intent\"\n\t\t\t\tvalue={altDown ? 'restart' : 'stop'}\n\t\t\t\tclassName=\"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase\"\n\t\t\t>\n\t\t\t\t{inFlightState ? inFlightState : altDown ? 'Restart App' : 'Stop App'}\n\t\t\t</button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function PortStopper({ port }: { port: number | string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"port\" value={port} />\n\t\t\t<Button varient=\"mono\" type=\"submit\" name=\"intent\" value=\"stop-port\">\n\t\t\t\t{fetcher.state === 'idle' ? 'Stop Port' : 'Stopping Port'}\n\t\t\t</Button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function AppStarter({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tif (fetcher.data?.status === 'app-not-started') {\n\t\tif (fetcher.data.error === 'port-unavailable') {\n\t\t\treturn (\n\t\t\t\t<div>\n\t\t\t\t\tThe port is unavailable. Would you like to stop whatever is running on\n\t\t\t\t\tthat port and try again?\n\t\t\t\t\t<PortStopper port={fetcher.data.port} />\n\t\t\t\t</div>\n\t\t\t)\n\t\t} else {\n\t\t\treturn <div>An unknown error has happened.</div>\n\t\t}\n\t}\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t<Button type=\"submit\" name=\"intent\" value=\"start\" varient=\"mono\">\n\t\t\t\t\tStart App\n\t\t\t\t</Button>\n\t\t\t) : (\n\t\t\t\t<div>\n\t\t\t\t\t<Loading>Starting App</Loading>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</fetcher.Form>\n\t)\n}\n","import { clsx } from 'clsx'\nimport * as React from 'react'\nimport { useImperativeHandle, useRef, useState } from 'react'\nimport { Icon } from '#app/components/icons.tsx'\nimport { AppStarter, AppStopper, PortStopper } from '#app/routes/start.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { LinkButton } from './button.tsx'\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from './ui/tooltip.tsx'\n\nexport type InBrowserBrowserRef = {\n\thandleExtrnalNavigation: (pathname?: string) => void\n}\n\ntype Props = {\n\tid: string\n\tname: string\n\tport: number\n\tportIsAvailable: boolean | null\n\tisRunning: boolean\n\tbaseUrl: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nexport function InBrowserBrowser({\n\tname,\n\tport,\n\tportIsAvailable,\n\tisRunning,\n\tbaseUrl,\n\tid,\n\tinitialRoute,\n\tref,\n}: Props) {\n\tconst requestInfo = useRequestInfo()\n\tconst [showUnmanaged, setShowUnmanaged] = useState(false)\n\tif (isRunning || showUnmanaged) {\n\t\treturn (\n\t\t\t<InBrowserBrowserForRealz\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tid={id}\n\t\t\t\tname={name}\n\t\t\t\tref={ref}\n\t\t\t\tinitialRoute={initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (portIsAvailable === false) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center justify-center\">\n\t\t\t\t<p className=\"max-w-xs pb-5 text-center\" role=\"status\">\n\t\t\t\t\t{`The port for this app is unavailable. It could be that you're running it `}\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={getBaseUrl({ domain: requestInfo.domain, port })}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t>\n\t\t\t\t\t\telsewhere\n\t\t\t\t\t</a>\n\t\t\t\t\t{'. '}\n\t\t\t\t\t<LinkButton onClick={() => setShowUnmanaged(true)}>\n\t\t\t\t\t\tShow here anyway\n\t\t\t\t\t</LinkButton>\n\t\t\t\t</p>\n\t\t\t\t<PortStopper port={port} />\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-center\">\n\t\t\t\t<AppStarter name={name} />\n\t\t\t</div>\n\t\t)\n\t}\n}\ntype RealBrowserProps = {\n\tbaseUrl: string\n\tid: string\n\tname: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nfunction InBrowserBrowserForRealz({\n\tbaseUrl,\n\tid,\n\tname,\n\tinitialRoute,\n\tref,\n}: RealBrowserProps) {\n\tconst theme = useTheme()\n\tconst [iframeKeyNumber, setIframeKeyNumber] = useState(0)\n\tconst iframeKey = id + iframeKeyNumber\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\n\tconst appUrl = new URL(initialRoute, baseUrl)\n\tconst [iframeSrcUrl, setIframeSrcUrl] = useState(appUrl)\n\n\tconst currentId = useRef(id)\n\tif (currentId.current !== id) {\n\t\tcurrentId.current = id\n\t\tsetIframeSrcUrl(appUrl)\n\t}\n\n\tfunction handleExtrnalNavigation(pathname?: string) {\n\t\tif (pathname) {\n\t\t\tconst newUrl = new URL(pathname, baseUrl)\n\t\t\tsetIframeSrcUrl(newUrl)\n\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t}\n\t}\n\n\tuseImperativeHandle(ref, () => ({ handleExtrnalNavigation }))\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t\t<div className=\"flex items-center justify-between border-b pl-1.5\">\n\t\t\t\t\t<div className=\"mr-2 flex items-center justify-center gap-2 px-1\">\n\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>Refresh</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none\">\n\t\t\t\t\t\t<a href={iframeSrcUrl.toString()} target=\"_blank\" rel=\"noreferrer\">\n\t\t\t\t\t\t\t{iframeSrcUrl.toString()}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t\t<AppStopper name={name} />\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={iframeSrcUrl.toString()}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex aspect-square items-center justify-center px-3.5',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>Open in new tab</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex h-full w-full grow dark:bg-white\">\n\t\t\t\t\t<iframe\n\t\t\t\t\t\ttitle={name}\n\t\t\t\t\t\tkey={iframeKey}\n\t\t\t\t\t\tref={iframeRef}\n\t\t\t\t\t\tsrc={iframeSrcUrl.toString()}\n\t\t\t\t\t\tclassName=\"h-full w-full grow bg-white\"\n\t\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t)\n}\n","import { type BaseExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport { useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Icon } from '#app/components/icons'\nimport {\n\tInBrowserBrowser,\n\ttype InBrowserBrowserRef,\n} from '#app/components/in-browser-browser.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\n\nexport function Preview({\n\tid,\n\tappInfo,\n\tinBrowserBrowserRef,\n}: {\n\tid?: string\n\tappInfo: {\n\t\tisRunning: boolean\n\t\tappName?: string\n\t\tname: string\n\t\ttitle: string\n\t\tportIsAvailable: boolean | null\n\t\ttype: string\n\t\tfullPath: string\n\t\tdev: BaseExerciseStepApp['dev']\n\t\ttest: BaseExerciseStepApp['test']\n\t\tstackBlitzUrl: BaseExerciseStepApp['stackBlitzUrl']\n\t} | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst requestInfo = useRequestInfo()\n\tconst [searchParams] = useSearchParams()\n\tconst theme = useTheme()\n\tif (!appInfo) return <p>No app here. Sorry.</p>\n\tconst { isRunning, dev, name, portIsAvailable, title } = appInfo\n\n\tif (ENV.EPICSHOP_DEPLOYED && appInfo.stackBlitzUrl) {\n\t\tconst url = new URL(appInfo.stackBlitzUrl)\n\t\turl.searchParams.set('embed', '1')\n\t\turl.searchParams.set('theme', theme)\n\n\t\treturn (\n\t\t\t<StackBlitzEmbed\n\t\t\t\ttitle={title}\n\t\t\t\turl={url.toString()}\n\t\t\t\tloadingContent={\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tLoading{' '}\n\t\t\t\t\t\t\t<a className=\"underline\" href={appInfo.stackBlitzUrl}>\n\t\t\t\t\t\t\t\t\"{title}\"\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t}\n\t\t\t/>\n\t\t)\n\t}\n\n\tif (dev.type === 'script') {\n\t\tconst baseUrl = getBaseUrl({\n\t\t\tdomain: requestInfo.domain,\n\t\t\tport: dev.portNumber,\n\t\t})\n\t\treturn (\n\t\t\t<InBrowserBrowser\n\t\t\t\tref={inBrowserBrowserRef}\n\t\t\t\tisRunning={isRunning}\n\t\t\t\tid={id ?? name}\n\t\t\t\tname={name}\n\t\t\t\tportIsAvailable={portIsAvailable}\n\t\t\t\tport={dev.portNumber}\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tinitialRoute={searchParams.get('pathname') ?? dev.initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (dev.type === 'browser' || dev.type === 'export') {\n\t\treturn (\n\t\t\t<div className=\"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto\">\n\t\t\t\t<a\n\t\t\t\t\thref={dev.pathname}\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'absolute right-5 bottom-5 flex items-center justify-center rounded-full bg-gray-100 p-2.5 transition hover:bg-gray-200 dark:bg-gray-800 hover:dark:bg-gray-600',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"ExternalLink\" aria-hidden=\"true\" />\n\t\t\t\t\t<span className=\"sr-only\">Open in New Window</span>\n\t\t\t\t</a>\n\t\t\t\t<iframe\n\t\t\t\t\ttitle={title}\n\t\t\t\t\tsrc={dev.pathname}\n\t\t\t\t\tclassName=\"yo yo h-full w-full grow bg-white\"\n\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>\n\t\t\t\t\tPreview for dev type of <code>{dev.type}</code> not supported.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t)\n\t}\n}\n\nexport function StackBlitzEmbed({\n\turl,\n\ttitle,\n\tloadingContent,\n}: {\n\turl: string\n\ttitle?: string\n\tloadingContent: React.ReactNode\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = useState(false)\n\n\treturn (\n\t\t<div className=\"h-full w-full grow\">\n\t\t\t{iframeLoaded ? null : (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t{loadingContent}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\tsrc={url}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'h-full w-full grow transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\ttitle={title}\n\t\t\t\tsandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n","import { type App } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tgetTestProcessEntry,\n\tisAppRunning,\n\tisPortAvailable,\n\tisTestRunning,\n} from '@epic-web/workshop-utils/process-manager.server'\n\nexport async function getAppRunningState(a: App) {\n\tif (a.dev.type !== 'script') {\n\t\treturn { isRunning: false, portIsAvailable: null }\n\t}\n\tconst isRunning = await isAppRunning(a)\n\tconst portIsAvailable = isRunning\n\t\t? null\n\t\t: await isPortAvailable(a.dev.portNumber)\n\treturn { isRunning, portIsAvailable }\n}\n\nexport function getTestState(a: App) {\n\tconst testProcess = getTestProcessEntry(a)\n\tif (!testProcess) {\n\t\treturn { isTestRunning: false, testExitCode: null }\n\t}\n\treturn {\n\t\tisTestRunning: isTestRunning(a),\n\t\ttestExitCode: testProcess.exitCode ?? null,\n\t}\n}\n","import { requireExerciseApp } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcombineServerTimings,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { useRef } from 'react'\nimport {\n\tdata,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tuseLoaderData,\n} from 'react-router'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.ts'\nimport { Preview } from './__shared/preview.tsx'\nimport { getAppRunningState } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exercise-step-test')\n\tconst exerciseStepApp = await requireExerciseApp(params, { request, timings })\n\tconst { isRunning, portIsAvailable } =\n\t\tawait getAppRunningState(exerciseStepApp)\n\n\treturn data(\n\t\t{\n\t\t\tappInfo: {\n\t\t\t\tisRunning,\n\t\t\t\tname: exerciseStepApp.name,\n\t\t\t\ttitle: exerciseStepApp.title,\n\t\t\t\tportIsAvailable,\n\t\t\t\ttype: exerciseStepApp.type,\n\t\t\t\tfullPath: exerciseStepApp.fullPath,\n\t\t\t\tdev: exerciseStepApp.dev,\n\t\t\t\ttest: exerciseStepApp.test,\n\t\t\t\tstackBlitzUrl: exerciseStepApp.stackBlitzUrl,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nexport default function TestsList() {\n\tconst { appInfo } = useLoaderData<typeof loader>()\n\tconst ref = useRef<InBrowserBrowserRef>(null)\n\n\treturn <Preview appInfo={appInfo} inBrowserBrowserRef={ref} />\n}\n","import * as Accordion from '@radix-ui/react-accordion'\nimport { clsx } from 'clsx'\nimport * as React from 'react'\nimport { Icon } from './icons.tsx'\n\ntype AccordionProps = {\n\ttitle: string\n\tchildren: React.ReactElement\n\tvariant?: 'changed' | 'added' | 'deleted' | 'renamed'\n\ticon?: React.ReactElement\n\tforceMount?: boolean\n}\n\nconst AccordionComponent: React.FC<AccordionProps> = ({\n\ttitle,\n\tchildren,\n\tvariant,\n\ticon,\n\tforceMount = false,\n}) => {\n\tconst getVariantIcon = () => {\n\t\tswitch (variant) {\n\t\t\tcase 'changed':\n\t\t\t\treturn (\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"Modified\"\n\t\t\t\t\t\taria-label=\"Modified\"\n\t\t\t\t\t\tclassName=\"text-[#fb923c]\"\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\tcase 'renamed':\n\t\t\t\treturn (\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"Renamed\"\n\t\t\t\t\t\taria-label=\"Renamed\"\n\t\t\t\t\t\tclassName=\"text-[#fb923c]\"\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\tcase 'added':\n\t\t\t\treturn (\n\t\t\t\t\t<Icon name=\"Added\" aria-label=\"Added\" className=\"text-[#10b981]\" />\n\t\t\t\t)\n\t\t\tcase 'deleted':\n\t\t\t\treturn (\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"Deleted\"\n\t\t\t\t\t\taria-label=\"Deleted\"\n\t\t\t\t\t\tclassName=\"text-[#ef4444]\"\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\treturn (\n\t\t\t\t\t<Icon\n\t\t\t\t\t\tname=\"Modified\"\n\t\t\t\t\t\taria-label=\"Modified\"\n\t\t\t\t\t\tclassName=\"text-[#fb923c]\"\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t}\n\t}\n\tconst getVariantLabel = () => {\n\t\tswitch (variant) {\n\t\t\tcase 'changed':\n\t\t\t\treturn 'modified'\n\t\t\tdefault:\n\t\t\t\treturn variant\n\t\t}\n\t}\n\n\t// Somehow on windows we get double backslashes in the title\n\t// so we'll just remove those 🤷‍♂️\n\tconst fixedTitle = title.replace(/\\\\\\\\/g, '\\\\')\n\treturn (\n\t\t<Accordion.Item value={title}>\n\t\t\t<AccordionTrigger variant={getVariantLabel()}>\n\t\t\t\t{icon ? icon : getVariantIcon()} {fixedTitle}\n\t\t\t</AccordionTrigger>\n\t\t\t<AccordionContent\n\t\t\t\tforceMount={forceMount}\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'prose dark:prose-invert prose-pre:m-0 prose-pre:mb-1 prose-pre:rounded-none max-w-none whitespace-pre-wrap',\n\t\t\t\t\t{\n\t\t\t\t\t\t'radix-state-closed:hidden': forceMount,\n\t\t\t\t\t},\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</AccordionContent>\n\t\t</Accordion.Item>\n\t)\n}\n\nexport default AccordionComponent\n\nconst AccordionTrigger: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\tvariant,\n\t...props\n}) => (\n\t<Accordion.Header className=\"flex\" asChild>\n\t\t<Accordion.Trigger\n\t\t\tclassName={clsx(\n\t\t\t\t'group hover:bg-foreground/20 flex w-full items-center justify-between border-b p-4 pr-3 font-mono text-sm leading-none font-medium',\n\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t\tref={forwardedRef}\n\t\t>\n\t\t\t<div className=\"flex items-center gap-1.5\">{children}</div>\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<span className=\"text-muted-foreground font-mono text-xs font-normal uppercase\">\n\t\t\t\t\t{variant}\n\t\t\t\t</span>\n\t\t\t\t<Icon\n\t\t\t\t\tname=\"TriangleDownSmall\"\n\t\t\t\t\tclassName=\"group-radix-state-open:rotate-180 transition\"\n\t\t\t\t\taria-hidden\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</Accordion.Trigger>\n\t</Accordion.Header>\n)\n\nconst AccordionContent: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => (\n\t<Accordion.Content\n\t\tclassName={clsx('', className)}\n\t\t{...props}\n\t\tref={forwardedRef}\n\t>\n\t\t<div>{children}</div>\n\t</Accordion.Content>\n)\n","import * as Accordion from '@radix-ui/react-accordion'\nimport * as Select from '@radix-ui/react-select'\nimport { clsx } from 'clsx'\nimport React, { Suspense } from 'react'\nimport { ErrorBoundary } from 'react-error-boundary'\nimport {\n\tAwait,\n\tForm,\n\tLink,\n\tuseNavigation,\n\tuseSearchParams,\n\tuseSubmit,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport AccordionComponent from '#app/components/accordion.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useApps } from '#app/utils/root-loader.ts'\nimport { DeferredEpicVideo } from './epic-video.tsx'\nimport { Icon } from './icons.tsx'\nimport { useRevalidationWS } from './revalidation-ws.tsx'\nimport { SimpleTooltip } from './ui/tooltip.tsx'\n\ntype diffProp = {\n\tapp1?: string\n\tapp2?: string\n\tdiffCode?: string | null\n}\n\nconst pre = (props: any) => <pre {...props} />\n\nconst mdxComponents = {\n\tAccordion: AccordionComponent,\n\t// override the pre-with-buttons\n\tpre,\n}\n\nfunction RevalidateApps({\n\tapp1: app1Name,\n\tapp2: app2Name,\n}: {\n\tapp1?: string\n\tapp2?: string\n}) {\n\tconst apps = useApps()\n\tconst app1 = apps.find((app) => app.name === app1Name)\n\tconst app2 = apps.find((app) => app.name === app2Name)\n\n\tuseRevalidationWS({\n\t\twatchPaths: [app1?.fullPath, app2?.fullPath].filter(Boolean),\n\t})\n\treturn null\n}\n\nexport function UserHasAccessDiff({\n\tuserHasAccessPromise,\n\tdiff,\n\tallApps,\n}: {\n\tuserHasAccessPromise: Promise<boolean>\n\tdiff: Promise<diffProp> | diffProp\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\treturn (\n\t\t<ErrorBoundary\n\t\t\tfallbackRender={() => (\n\t\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t\t<p className=\"text-2xl font-bold\">Error</p>\n\t\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\t\tThere was an error loading the user access.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t>\n\t\t\t<Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div className=\"flex items-center justify-center p-8\">\n\t\t\t\t\t\t<SimpleTooltip content=\"Loading user access\">\n\t\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"animate-spin\" />\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await resolve={userHasAccessPromise}>\n\t\t\t\t\t{(userHasAccess) =>\n\t\t\t\t\t\tuserHasAccess ? (\n\t\t\t\t\t\t\t<DiffImplementation diff={diff} allApps={allApps} />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t\t\t\t\t<p className=\"text-2xl font-bold\">Access Denied</p>\n\t\t\t\t\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\t\t\t\t\tYou must login or register for the workshop to view the\n\t\t\t\t\t\t\t\t\t\tdiff.\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"h-16\" />\n\t\t\t\t\t\t\t\t<p className=\"pb-4\">\n\t\t\t\t\t\t\t\t\tCheck out this video to see how the diff tab works.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t<DeferredEpicVideo url=\"https://www.epicweb.dev/tips/epic-workshop-diff-tab-demo\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t</Await>\n\t\t\t</Suspense>\n\t\t</ErrorBoundary>\n\t)\n}\n\nexport { UserHasAccessDiff as Diff }\n\nexport function DiffImplementation({\n\tdiff,\n\tallApps,\n}: {\n\tdiff: Promise<diffProp> | diffProp\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\tconst submit = useSubmit()\n\tconst [params] = useSearchParams()\n\tconst paramsWithForcedRefresh = new URLSearchParams(params)\n\tparamsWithForcedRefresh.set('forceFresh', 'diff')\n\tconst navigation = useNavigation()\n\tconst spinnerNavigating = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 0,\n\t\tminDuration: 1000,\n\t})\n\n\tconst hiddenInputs: Array<React.ReactNode> = []\n\tfor (const [key, value] of params.entries()) {\n\t\tif (key === 'app1' || key === 'app2') continue\n\t\thiddenInputs.push(\n\t\t\t<input key={key} type=\"hidden\" name={key} value={value} />,\n\t\t)\n\t}\n\n\treturn (\n\t\t<Suspense\n\t\t\tfallback={\n\t\t\t\t<div className=\"flex items-center justify-center p-8\">\n\t\t\t\t\t<SimpleTooltip content=\"Loading diff\">\n\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"animate-spin\" />\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t</div>\n\t\t\t}\n\t\t>\n\t\t\t<Await\n\t\t\t\tresolve={diff}\n\t\t\t\terrorElement={\n\t\t\t\t\t<p className=\"text-foreground-destructive p-6\">\n\t\t\t\t\t\tThere was an error calculating the diff. Sorry.\n\t\t\t\t\t</p>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t{(diff) => (\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col\">\n\t\t\t\t\t\t<div className=\"flex h-14 min-h-14 w-full overflow-x-hidden border-b\">\n\t\t\t\t\t\t\t<div className=\"border-r\">\n\t\t\t\t\t\t\t\t<SimpleTooltip content=\"Reload diff\">\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={`.?${paramsWithForcedRefresh}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex h-full w-14 items-center justify-center\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\tname=\"Refresh\"\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn({ 'animate-spin': spinnerNavigating })}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<Form\n\t\t\t\t\t\t\t\tonChange={(e) => submit(e.currentTarget)}\n\t\t\t\t\t\t\t\tclassName=\"scrollbar-thin scrollbar-thumb-scrollbar flex h-full flex-1 items-center overflow-x-auto\"\n\t\t\t\t\t\t\t\tkey={`${diff.app1}${diff.app2}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{hiddenInputs}\n\t\t\t\t\t\t\t\t<SelectFileToDiff\n\t\t\t\t\t\t\t\t\tname=\"app1\"\n\t\t\t\t\t\t\t\t\tlabel=\"App 1\"\n\t\t\t\t\t\t\t\t\tclassName=\"border-r\"\n\t\t\t\t\t\t\t\t\tallApps={allApps}\n\t\t\t\t\t\t\t\t\tdefaultValue={diff.app1}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<SelectFileToDiff\n\t\t\t\t\t\t\t\t\tname=\"app2\"\n\t\t\t\t\t\t\t\t\tlabel=\"App 2\"\n\t\t\t\t\t\t\t\t\tallApps={allApps}\n\t\t\t\t\t\t\t\t\tdefaultValue={diff.app2}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"scrollbar-thin scrollbar-thumb-scrollbar grow overflow-y-scroll\">\n\t\t\t\t\t\t\t{diff.diffCode ? (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<Accordion.Root className=\"w-full\" type=\"multiple\">\n\t\t\t\t\t\t\t\t\t\t<Mdx code={diff.diffCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t\t</Accordion.Root>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : diff.app1 && diff.app2 ? (\n\t\t\t\t\t\t\t\t<p className=\"bg-foreground text-background m-5 inline-flex items-center justify-center px-1 py-0.5 font-mono text-sm uppercase\">\n\t\t\t\t\t\t\t\t\tThere was a problem generating the diff\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"bg-foreground text-background m-5 inline-flex items-center justify-center px-1 py-0.5 font-mono text-sm uppercase\">\n\t\t\t\t\t\t\t\t\tSelect two apps to compare\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<RevalidateApps app1={diff.app1} app2={diff.app2} />\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</Await>\n\t\t</Suspense>\n\t)\n}\n\nfunction SelectFileToDiff({\n\tname,\n\tlabel,\n\tclassName,\n\tallApps,\n\tdefaultValue,\n}: {\n\tname: string\n\tlabel: string\n\tclassName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tdefaultValue?: string\n}) {\n\treturn (\n\t\t<Select.Root name={name} defaultValue={defaultValue}>\n\t\t\t<Select.Trigger\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'radix-placeholder:text-gray-500 flex h-full w-full max-w-[50%] items-center justify-between px-3 text-left focus-visible:outline-none',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\taria-label={`Select ${label} for git Diff`}\n\t\t\t>\n\t\t\t\t<span className=\"overflow-hidden text-ellipsis whitespace-nowrap\">\n\t\t\t\t\t{label}:{' '}\n\t\t\t\t\t<Select.Value\n\t\t\t\t\t\tplaceholder={`Select ${label}`}\n\t\t\t\t\t\tclassName=\"inline-block w-40 text-ellipsis\"\n\t\t\t\t\t/>\n\t\t\t\t</span>\n\t\t\t\t<Select.Icon className=\"\">\n\t\t\t\t\t<Icon name=\"TriangleDownSmall\" />\n\t\t\t\t</Select.Icon>\n\t\t\t</Select.Trigger>\n\t\t\t<Select.Portal>\n\t\t\t\t<Select.Content\n\t\t\t\t\tposition=\"popper\"\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]\"\n\t\t\t\t>\n\t\t\t\t\t<Select.ScrollUpButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronUp\" />\n\t\t\t\t\t</Select.ScrollUpButton>\n\t\t\t\t\t<Select.Viewport className=\"p-3\">\n\t\t\t\t\t\t<Select.Group>\n\t\t\t\t\t\t\t<Select.Label className=\"px-5 pb-3 font-mono uppercase\">\n\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t</Select.Label>\n\t\t\t\t\t\t\t{allApps.map((app) => {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<SelectItem key={app.name} value={app.name}>\n\t\t\t\t\t\t\t\t\t\t{app.displayName}\n\t\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</Select.Group>\n\t\t\t\t\t</Select.Viewport>\n\t\t\t\t\t<Select.ScrollDownButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronDown\" />\n\t\t\t\t\t</Select.ScrollDownButton>\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Portal>\n\t\t</Select.Root>\n\t)\n}\n\nconst SelectItem: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => {\n\treturn (\n\t\t<Select.Item\n\t\t\tclassName={clsx(\n\t\t\t\t'radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100 relative flex cursor-pointer items-center rounded px-10 py-2 leading-none opacity-80 select-none',\n\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t\tref={forwardedRef}\n\t\t>\n\t\t\t<Select.ItemText>{children}</Select.ItemText>\n\t\t\t<Select.ItemIndicator className=\"absolute left-0 inline-flex w-[25px] items-center justify-center\">\n\t\t\t\t<Icon name=\"CheckSmall\" />\n\t\t\t</Select.ItemIndicator>\n\t\t</Select.Item>\n\t)\n}\n","export function StatusIndicator({\n\tstatus,\n}: {\n\tstatus: 'running' | 'passed' | 'failed' | 'stopped'\n}) {\n\tconst colors = {\n\t\trunning: {\n\t\t\tpinger: 'bg-green-400',\n\t\t\tcircle: 'bg-green-500',\n\t\t},\n\t\tpassed: {\n\t\t\tcircle: 'bg-green-500',\n\t\t},\n\t\tfailed: {\n\t\t\tcircle: 'bg-red-500',\n\t\t},\n\t\tstopped: {\n\t\t\tcircle: 'bg-gray-500',\n\t\t},\n\t}[status]\n\treturn (\n\t\t<span className=\"relative flex h-3 w-3\">\n\t\t\t{colors.pinger ? (\n\t\t\t\t<span\n\t\t\t\t\tclassName={`absolute inline-flex h-full w-full animate-ping rounded-full ${colors.pinger} opacity-75`}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<span\n\t\t\t\tclassName={`relative inline-flex h-3 w-3 rounded-full ${colors.circle}`}\n\t\t\t/>\n\t\t</span>\n\t)\n}\n","import {\n\tcachified,\n\tdiscordCache,\n\tshouldForceFresh,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { dayjs } from '@epic-web/workshop-utils/utils.server'\nimport { z } from 'zod'\nimport { getHints } from '#app/utils/client-hints.tsx'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\n\nconst EmojiDataSchema = z.union([\n\tz.object({\n\t\temojiName: z.never().optional(),\n\t\temojiUrl: z.string(),\n\t}),\n\tz.object({\n\t\temojiName: z.string(),\n\t\temojiUrl: z.never().optional(),\n\t}),\n\tz.object({\n\t\temojiName: z.never().optional(),\n\t\temojiUrl: z.never().optional(),\n\t}),\n])\n\nexport const ThreadItemSchema = z.object({\n\tid: z.string(),\n\ttags: z.array(\n\t\tz\n\t\t\t.object({\n\t\t\t\tname: z.string(),\n\t\t\t})\n\t\t\t.and(EmojiDataSchema),\n\t),\n\tname: z.string(),\n\tlink: z.string(),\n\tauthorDisplayName: z.string(),\n\tauthorHexAccentColor: z.string().nullable().optional(),\n\tauthorAvatarUrl: z.string().nullable(),\n\tmessagePreview: z.string(),\n\tmessageCount: z.number(),\n\tlastUpdated: z.string(),\n\tpreviewImageUrl: z.string().nullable(),\n\treactions: z.array(\n\t\tz\n\t\t\t.object({\n\t\t\t\tcount: z.number(),\n\t\t\t})\n\t\t\t.and(EmojiDataSchema),\n\t),\n})\n\nconst ThreadDataSchema = z.array(ThreadItemSchema)\n\nconst EpicForumResponseSchema = z\n\t.object({\n\t\tstatus: z.literal('error'),\n\t\terror: z.string(),\n\t})\n\t.or(\n\t\tz.object({\n\t\t\tstatus: z.literal('success'),\n\t\t\tthreadData: ThreadDataSchema,\n\t\t}),\n\t)\n\nexport async function fetchDiscordPosts({ request }: { request: Request }) {\n\tconst config = getWorkshopConfig()\n\tif (!config.product.discordChannelId) return []\n\n\tconst forceFresh = await shouldForceFresh({ request })\n\tconst searchParams = new URLSearchParams({\n\t\tchannelId: config.product.discordChannelId,\n\t})\n\tif (config.product.discordTags?.length) {\n\t\tfor (const tag of config.product.discordTags) {\n\t\t\tsearchParams.append('tagId', tag)\n\t\t}\n\t}\n\tif (forceFresh) searchParams.set('fresh', 'true')\n\t// const url = `http://localhost:3000/resources/forum-feed?${searchParams}`\n\tconst url = `https://kcd-discord-bot-v2.fly.dev/resources/forum-feed?${searchParams}`\n\n\tconst threadData = await cachified({\n\t\tkey: url,\n\t\trequest,\n\t\tforceFresh,\n\t\tcache: discordCache,\n\t\tttl: 1000 * 60 * 2,\n\t\tswr: 1000 * 60 * 60 * 24 * 365 * 100,\n\t\tofflineFallbackValue: [],\n\t\tcheckValue: ThreadDataSchema,\n\t\tasync getFreshValue(): Promise<z.infer<typeof ThreadDataSchema>> {\n\t\t\tconst result = await fetch(url, {\n\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t}).catch((error) => {\n\t\t\t\treturn new Response(getErrorMessage(error), { status: 500 })\n\t\t\t})\n\n\t\t\tif (!result.ok) {\n\t\t\t\tconsole.error(`There was an error communicating with discord`)\n\t\t\t\ttry {\n\t\t\t\t\tconsole.error(await result.text())\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore\n\t\t\t\t}\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\tconst jsonResult = await result.json()\n\t\t\tconst epicForumResponseResult =\n\t\t\t\tEpicForumResponseSchema.safeParse(jsonResult)\n\t\t\tif (epicForumResponseResult.success) {\n\t\t\t\tif (epicForumResponseResult.data.status === 'error') {\n\t\t\t\t\tconsole.error(`There was an error communicating with discord`)\n\t\t\t\t\tconsole.error(epicForumResponseResult.data.error)\n\t\t\t\t\treturn []\n\t\t\t\t} else {\n\t\t\t\t\treturn epicForumResponseResult.data.threadData\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconsole.error(`There was an error parsing the discord response`)\n\t\t\t\tconsole.error(epicForumResponseResult.error.flatten())\n\t\t\t\treturn []\n\t\t\t}\n\t\t},\n\t})\n\n\tconst hints = getHints(request)\n\n\treturn threadData.map((thread) => ({\n\t\t...thread,\n\t\tlastUpdatedDisplay: dayjs(thread.lastUpdated).tz(hints.timeZone).fromNow(),\n\t}))\n}\n","import * as React from 'react'\nimport { Await, Link, useLoaderData } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { DiscordCTA, useDiscordCTALink } from '#app/routes/_app+/discord.tsx'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { type Route } from '../+types/index.tsx'\n\nexport function DiscordChat() {\n\treturn (\n\t\t<div className=\"flex h-full w-full flex-col gap-4 pt-4\">\n\t\t\t<div className=\"text-center\">\n\t\t\t\t<DiscordCTA />\n\t\t\t</div>\n\t\t\t<div className=\"bg-accent scrollbar-thin scrollbar-thumb-scrollbar flex-1 overflow-y-scroll pb-4\">\n\t\t\t\t<DiscordPosts />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPosts() {\n\tconst data = useLoaderData<Route.ComponentProps['loaderData']>()\n\tconst ctaLink = useDiscordCTALink()\n\tconst altDown = useAltDown()\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t<div className=\"text-foreground-destructive flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\tUnable to load discord messages when offline\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\treturn (\n\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t<React.Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t\t<Loading>Loading Discord Posts</Loading>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await\n\t\t\t\t\tresolve={data.discordPostsPromise}\n\t\t\t\t\terrorElement={\n\t\t\t\t\t\t<div className=\"text-red-500\">\n\t\t\t\t\t\t\tThere was a problem loading the discord posts\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{(posts) => (\n\t\t\t\t\t\t<ul className=\"flex w-full flex-col gap-4 p-3 xl:p-12\">\n\t\t\t\t\t\t\t{posts.map((post) => (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={post.id}\n\t\t\t\t\t\t\t\t\tclassName=\"bg-background rounded-xl border transition-all duration-200 focus-within:-translate-y-1 focus-within:shadow-lg hover:-translate-y-1 hover:shadow-lg\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<DiscordPost thread={post} />\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t)}\n\t\t\t\t</Await>\n\t\t\t</React.Suspense>\n\t\t\t<div>\n\t\t\t\t<Link\n\t\t\t\t\tto={\n\t\t\t\t\t\taltDown && !ctaLink.includes('oauth')\n\t\t\t\t\t\t\t? ctaLink.replace(/^https/, 'discord')\n\t\t\t\t\t\t\t: ctaLink\n\t\t\t\t\t}\n\t\t\t\t\ttarget={ctaLink.includes('oauth') ? undefined : '_blank'}\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\tonClick={\n\t\t\t\t\t\taltDown\n\t\t\t\t\t\t\t? (e) => {\n\t\t\t\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t\t\t\t\twindow.open(\n\t\t\t\t\t\t\t\t\t\te.currentTarget.href,\n\t\t\t\t\t\t\t\t\t\t'_blank',\n\t\t\t\t\t\t\t\t\t\t'noreferrer noopener',\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"flex items-center gap-2 p-2 text-xl hover:underline\"\n\t\t\t\t>\n\t\t\t\t\tCreate Post <Icon name=\"ExternalLink\" />\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPost({\n\tthread,\n}: {\n\tthread: Awaited<\n\t\tRoute.ComponentProps['loaderData']['discordPostsPromise']\n\t>[number]\n}) {\n\tconst reactionsWithCounts = thread.reactions.filter((r) => r.count)\n\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"flex flex-col gap-2 p-4\">\n\t\t\t\t<div className=\"flex gap-4\">\n\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t{thread.tags.length ? (\n\t\t\t\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t\t\t\t{thread.tags.map((t) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={t.name}\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-accent flex items-center justify-center gap-1 rounded-full px-2 py-1 text-sm\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t<Emoji name={t.emojiName} url={t.emojiUrl} />\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span>{t.name}</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<strong className=\"text-xl font-bold\">{thread.name}</strong>\n\t\t\t\t\t\t<div className=\"flex items-start gap-1\">\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t{thread.authorAvatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tsrc={thread.authorAvatarUrl}\n\t\t\t\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-6 w-6 rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclassName=\"font-bold\"\n\t\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\t\tthread.authorHexAccentColor\n\t\t\t\t\t\t\t\t\t\t\t\t? { color: thread.authorHexAccentColor }\n\t\t\t\t\t\t\t\t\t\t\t\t: {}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{thread.authorDisplayName}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t:{' '}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<span className=\"text-muted-foreground flex-1 overflow-ellipsis\">\n\t\t\t\t\t\t\t\t{thread.messagePreview}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{thread.previewImageUrl ? (\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tsrc={thread.previewImageUrl}\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tclassName=\"h-28 w-28 rounded-lg object-cover\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"flex justify-between\">\n\t\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{reactionsWithCounts.length ? (\n\t\t\t\t\t\t\t\t<ul className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t{reactionsWithCounts.map((r, i) => (\n\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-1 rounded-md border border-blue-600 bg-blue-500/20 px-[5px] py-[0.5px] text-sm\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Emoji name={r.emojiName} url={r.emojiUrl} />\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>{r.count}</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t<span className=\"inline-flex items-center gap-1\">\n\t\t\t\t\t\t\t\t<Icon name=\"Chat\" /> {thread.messageCount}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{` · ${thread.lastUpdatedDisplay}`}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span className=\"flex items-center gap-4\">\n\t\t\t\t\t\t<a href={thread.link.replace(/^https/, 'discord')}>\n\t\t\t\t\t\t\t<Icon name=\"Discord\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<a href={thread.link} target=\"_blank\" rel=\"noreferrer noopener\">\n\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction Emoji({ name, url }: { name?: string; url?: string }) {\n\treturn url ? (\n\t\t<img src={url} alt={name} className=\"h-full w-full\" />\n\t) : name ? (\n\t\tname\n\t) : null\n}\n","import { Icon } from '#app/components/icons'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { PlaygroundChooser, SetPlayground } from '#app/routes/set-playground'\n\nexport function PlaygroundWindow({\n\tplaygroundAppName,\n\tproblemAppName,\n\tisUpToDate,\n\tallApps,\n\tchildren,\n}: {\n\tplaygroundAppName?: string\n\tproblemAppName?: string\n\tisUpToDate: boolean\n\tallApps: Array<{ name: string; displayName: string }>\n\tchildren: React.ReactNode\n}) {\n\tconst isCorrectApp = playgroundAppName === problemAppName\n\tconst playgroundLinkedUI =\n\t\tisCorrectApp && isUpToDate ? (\n\t\t\t<Icon size=\"xl\" name=\"Linked\" />\n\t\t) : (\n\t\t\t<Icon\n\t\t\t\tsize=\"xl\"\n\t\t\t\tname=\"Unlinked\"\n\t\t\t\tclassName=\"text-foreground-destructive animate-pulse\"\n\t\t\t/>\n\t\t)\n\tlet setPlaygroundTooltipText = 'Click to reset Playground.'\n\tif (!isUpToDate) {\n\t\tsetPlaygroundTooltipText =\n\t\t\t'Playground is out of date. Click to reset Playground.'\n\t}\n\tif (!isCorrectApp) {\n\t\tsetPlaygroundTooltipText =\n\t\t\t'Playground is not set to the right app. Click to set Playground.'\n\t}\n\treturn (\n\t\t<div className=\"flex h-full w-full flex-col justify-between\">\n\t\t\t<div className=\"flex h-14 shrink-0 items-center justify-start gap-2 border-b px-3\">\n\t\t\t\t<div className=\"display-alt-up\">\n\t\t\t\t\t{problemAppName ? (\n\t\t\t\t\t\t<SetPlayground\n\t\t\t\t\t\t\tappName={problemAppName}\n\t\t\t\t\t\t\ttooltipText={setPlaygroundTooltipText}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{playgroundLinkedUI}\n\t\t\t\t\t\t</SetPlayground>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<SimpleTooltip content=\"No problem app available for this step\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"display-alt-down\">\n\t\t\t\t\t{playgroundAppName ? (\n\t\t\t\t\t\t<SetPlayground\n\t\t\t\t\t\t\tappName={playgroundAppName}\n\t\t\t\t\t\t\treset\n\t\t\t\t\t\t\ttooltipText=\"Reset Playground\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"flex h-7 w-7 items-center justify-center\">\n\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SetPlayground>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"h-7 w-7\" />\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<PlaygroundChooser\n\t\t\t\t\tallApps={allApps}\n\t\t\t\t\tplaygroundAppName={playgroundAppName}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"flex min-h-0 flex-1 grow items-stretch justify-center overflow-hidden\">\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n","import { toast as showToast } from 'sonner'\nimport { Icon } from '#app/components/icons.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser'\nimport { SimpleTooltip } from '#app/components/ui/tooltip'\nimport { SetAppToPlayground } from '#app/routes/set-playground'\nimport { PlaygroundWindow } from './playground-window'\nimport { Preview } from './preview'\n\nexport function Playground({\n\tappInfo: playgroundAppInfo,\n\tinBrowserBrowserRef,\n\tproblemAppName,\n\tallApps,\n\tisUpToDate,\n}: {\n\tappInfo: Parameters<typeof Preview>['0']['appInfo'] | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\tproblemAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tisUpToDate: boolean\n}) {\n\treturn (\n\t\t<PlaygroundWindow\n\t\t\tplaygroundAppName={playgroundAppInfo?.appName}\n\t\t\tproblemAppName={problemAppName}\n\t\t\tallApps={allApps}\n\t\t\tisUpToDate={isUpToDate}\n\t\t>\n\t\t\t{playgroundAppInfo?.dev.type === 'none' ? (\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-center gap-4\">\n\t\t\t\t\t<div className=\"text-secondary-foreground text-2xl\">\n\t\t\t\t\t\tNon-UI exercise\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"text-secondary-foreground max-w-md text-center text-balance\">\n\t\t\t\t\t\tThis exercise has no application or other UI associated with it.{' '}\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\tNavigate to{' '}\n\t\t\t\t\t\t<SimpleTooltip content={playgroundAppInfo.fullPath}>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"inline-flex cursor-pointer items-center gap-1.5 underline\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tvoid navigator.clipboard.writeText(playgroundAppInfo.fullPath)\n\t\t\t\t\t\t\t\t\tshowToast.success('Copied playground path to clipboard')\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tthe playground directory\n\t\t\t\t\t\t\t\t<Icon name=\"Copy\" size=\"sm\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</SimpleTooltip>{' '}\n\t\t\t\t\t\tin your editor and follow the exercise instructions to complete it.\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) : playgroundAppInfo ? (\n\t\t\t\t<Preview\n\t\t\t\t\tid={playgroundAppInfo.appName}\n\t\t\t\t\tappInfo={playgroundAppInfo}\n\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex flex-col justify-center gap-2\">\n\t\t\t\t\t<p>Please set the playground first</p>\n\t\t\t\t\t{problemAppName ? (\n\t\t\t\t\t\t<SetAppToPlayground appName={problemAppName} />\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</PlaygroundWindow>\n\t)\n}\n","import AnsiToHTML from 'ansi-to-html'\nimport { useMemo } from 'react'\nimport { useTheme } from '#app/routes/theme/index.tsx'\n\nexport function useAnsiToHtml() {\n\tconst theme = useTheme()\n\tconst ansi = useMemo(\n\t\t() =>\n\t\t\tnew AnsiToHTML(\n\t\t\t\ttheme === 'dark'\n\t\t\t\t\t? { fg: '#d6deeb', bg: '#121318', escapeXML: true }\n\t\t\t\t\t: { fg: '#000000', bg: '#f3f3f3', escapeXML: true },\n\t\t\t),\n\t\t[theme],\n\t)\n\treturn ansi\n}\n\n// remove this when this is fixed: https://github.com/rburns/ansi-to-html/issues/112\nexport function stripCursorMovements(data: string) {\n\treturn data.replace(/\\u001b\\[\\d+A/g, '').replace(/\\u001b\\[\\d+K/g, '')\n}\n","import * as Accordion from '@radix-ui/react-accordion'\nimport { useEffect, useRef, useState } from 'react'\nimport { z } from 'zod'\nimport AccordionComponent from '#app/components/accordion.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { stripCursorMovements, useAnsiToHtml } from '#app/utils/ansi-text.ts'\nimport { AnimatedBars, Icon } from './icons.tsx'\n\nconst testRunnerStatusDataSchema = z.intersection(\n\tz.object({\n\t\ttype: z.literal('epicshop:test-status-update'),\n\t\ttimestamp: z.number(),\n\t}),\n\tz.union([\n\t\tz.object({ status: z.literal('pending') }),\n\t\tz.object({ status: z.literal('pass') }),\n\t\tz.object({ status: z.literal('fail'), error: z.string() }),\n\t]),\n)\n\nconst testRunnerTestStepDataSchema = z.object({\n\ttype: z.literal('epicshop:test-step-update'),\n\tstatus: z.literal('pass'),\n\ttitle: z.string(),\n\ttimestamp: z.number(),\n})\n\nconst testRunnerDataSchema = z.union([\n\ttestRunnerTestStepDataSchema,\n\ttestRunnerStatusDataSchema,\n])\n\ntype TestRunnerStatusData = z.infer<typeof testRunnerStatusDataSchema>\ntype TestRunnerTestStepData = z.infer<typeof testRunnerTestStepDataSchema>\n\nexport function InBrowserTestRunner({\n\tpathname,\n\ttestFile,\n}: {\n\tpathname: string\n\ttestFile: string\n}) {\n\tconst theme = useTheme()\n\tconst ansi = useAnsiToHtml()\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\tconst [message, setMessage] = useState<TestRunnerStatusData | null>(null)\n\tconst [testSteps, setTestSteps] = useState<Array<TestRunnerTestStepData>>([])\n\n\tuseEffect(() => {\n\t\tfunction handleMessage(messageEvent: MessageEvent) {\n\t\t\tif (messageEvent.source !== iframeRef.current?.contentWindow) return\n\t\t\tif ('request' in messageEvent.data) return\n\n\t\t\tconst result = testRunnerDataSchema.safeParse(messageEvent.data, {\n\t\t\t\tpath: ['messageEvent', 'data'],\n\t\t\t})\n\t\t\tif (!result.success) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Invalid message from test iframe`,\n\t\t\t\t\tmessageEvent.data,\n\t\t\t\t\tresult.error,\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst { data } = result\n\t\t\tif (data.type === 'epicshop:test-status-update') {\n\t\t\t\tif (data.status === 'pending') {\n\t\t\t\t\tsetTestSteps([])\n\t\t\t\t}\n\t\t\t\tsetMessage(data)\n\t\t\t}\n\t\t\tif (data.type === 'epicshop:test-step-update') {\n\t\t\t\tsetTestSteps((steps) => [...steps, data])\n\t\t\t}\n\t\t}\n\t\twindow.addEventListener('message', handleMessage)\n\t\treturn () => {\n\t\t\twindow.removeEventListener('message', handleMessage)\n\t\t}\n\t}, [])\n\n\tconst statusEmoji = {\n\t\tpending: <AnimatedBars size={14} aria-label=\"Pending\" />,\n\t\tpass: (\n\t\t\t<Icon\n\t\t\t\tname=\"CheckSmall\"\n\t\t\t\taria-label=\"Passed\"\n\t\t\t\tclassName=\"text-emerald-700\"\n\t\t\t/>\n\t\t),\n\t\tfail: (\n\t\t\t<Icon\n\t\t\t\tname=\"Remove\"\n\t\t\t\taria-label=\"Failed\"\n\t\t\t\tclassName=\"text-foreground-destructive\"\n\t\t\t/>\n\t\t),\n\t\tunknown: (\n\t\t\t<Icon name=\"Question\" aria-label=\"Unknown\" className=\"animate-pulse\" />\n\t\t),\n\t}[message?.status ?? 'unknown']\n\n\tconst sortedTestSteps = testSteps.sort((a, b) => a.timestamp - b.timestamp)\n\tconst testStepStatusEmojis = {\n\t\tpass: <Icon name=\"CheckSmall\" aria-label=\"Passed\" />,\n\t\tfail: <Icon name=\"Remove\" aria-label=\"Failed\" />,\n\t\tunknown: (\n\t\t\t<Icon name=\"Question\" aria-label=\"Unknown\" className=\"animate-pulse\" />\n\t\t),\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<Accordion.Root className=\"w-full\" type=\"multiple\">\n\t\t\t\t<AccordionComponent\n\t\t\t\t\ticon={statusEmoji}\n\t\t\t\t\ttitle={testFile}\n\t\t\t\t\tforceMount={true}\n\t\t\t\t>\n\t\t\t\t\t<div className=\"not-prose\">\n\t\t\t\t\t\t<div className=\"flex flex-col gap-2 p-5 pt-3\">\n\t\t\t\t\t\t\t<ul className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t\t{sortedTestSteps.map((testStep, index) => (\n\t\t\t\t\t\t\t\t\t// sometimes the steps come in so fast that the timestamp is the same\n\t\t\t\t\t\t\t\t\t<li key={testStep.timestamp + testStep.title}>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-baseline gap-2 text-emerald-700\">\n\t\t\t\t\t\t\t\t\t\t\t<span>{index + 1}.</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>{testStepStatusEmojis[testStep.status]}</span>\n\t\t\t\t\t\t\t\t\t\t\t<pre className=\"scrollbar-thin scrollbar-thumb-scrollbar max-h-48 overflow-y-auto p-4\">\n\t\t\t\t\t\t\t\t\t\t\t\t{testStep.title}\n\t\t\t\t\t\t\t\t\t\t\t</pre>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t{message?.status === 'fail' ? (\n\t\t\t\t\t\t\t\t<div className=\"text-foreground-destructive flex items-baseline gap-2\">\n\t\t\t\t\t\t\t\t\t<span>{sortedTestSteps.length + 1}.</span>\n\t\t\t\t\t\t\t\t\t<span>{testStepStatusEmojis.fail}</span>\n\t\t\t\t\t\t\t\t\t<pre\n\t\t\t\t\t\t\t\t\t\tclassName=\"scrollbar-thin scrollbar-thumb-scrollbar max-h-48 overflow-y-auto p-4\"\n\t\t\t\t\t\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t\t\t\t\t\t__html: ansi.toHtml(stripCursorMovements(message.error)),\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<iframe\n\t\t\t\t\t\t\t\tref={iframeRef}\n\t\t\t\t\t\t\t\ttitle={testFile}\n\t\t\t\t\t\t\t\tsrc={pathname + testFile}\n\t\t\t\t\t\t\t\tclassName=\"mt-5 min-h-[420px] w-full border bg-white\"\n\t\t\t\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex border-y\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\t\t\t\tiframeRef.current?.contentWindow?.location.reload()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tclassName=\"border-r p-3\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" aria-label=\"Rerun Tests\" />\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={pathname + testFile}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName=\"border-r p-3\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" aria-label=\"Open in New Window\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</AccordionComponent>\n\t\t\t</Accordion.Root>\n\t\t</>\n\t)\n}\n","import { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport { userHasAccessToWorkshop } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tclearTestProcessEntry,\n\tgetTestProcessEntry,\n\tisTestRunning,\n\trunAppTests,\n} from '@epic-web/workshop-utils/process-manager.server'\nimport { useEffect, useReducer, useRef } from 'react'\nimport {\n\tdata,\n\ttype ActionFunctionArgs,\n\ttype LoaderFunctionArgs,\n\tuseFetcher,\n\tuseRevalidator,\n} from 'react-router'\nimport { useEventSource } from 'remix-utils/sse/react'\nimport { eventStream } from 'remix-utils/sse/server'\nimport { z } from 'zod'\nimport { AnimatedBars, Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { stripCursorMovements, useAnsiToHtml } from '#app/utils/ansi-text.ts'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nconst testActionSchema = z.union([\n\tz.object({\n\t\tintent: z.literal('run'),\n\t\tname: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('stop'),\n\t\tname: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('clear'),\n\t\tname: z.string(),\n\t}),\n])\n\nconst testEventSchema = z.union([\n\tz.object({\n\t\ttype: z.literal('init'),\n\t\texitCode: z.number().nullable().optional(),\n\t\tisRunning: z.boolean(),\n\t\toutput: z.array(\n\t\t\tz.object({\n\t\t\t\ttype: z.union([z.literal('stdout'), z.literal('stderr')]),\n\t\t\t\tcontent: z.string(),\n\t\t\t\ttimestamp: z.number(),\n\t\t\t}),\n\t\t),\n\t}),\n\tz.object({\n\t\ttype: z.union([z.literal('stdout'), z.literal('stderr')]),\n\t\tdata: z.string(),\n\t\ttimestamp: z.number(),\n\t}),\n\tz.object({\n\t\ttype: z.literal('exit'),\n\t\tisRunning: z.literal(false),\n\t\tcode: z.number().nullable(),\n\t}),\n])\nconst testEventQueueSchema = z.array(testEventSchema)\n\ntype TestEvent = z.infer<typeof testEventSchema>\ntype TestEventQueue = z.infer<typeof testEventQueueSchema>\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst url = new URL(request.url)\n\tconst name = url.searchParams.get('name')\n\tif (!name) {\n\t\treturn data({ error: 'Missing name' }, { status: 400 })\n\t}\n\tconst app = await getAppByName(name)\n\tif (!app) {\n\t\treturn data({ error: 'App not found' }, { status: 404 })\n\t}\n\tconst processEntry = getTestProcessEntry(app)\n\tif (!processEntry) {\n\t\treturn data({ error: 'App is not running tests' }, { status: 404 })\n\t}\n\treturn eventStream(request.signal, function setup(send) {\n\t\t// have to batch because the client may miss events if we send too many\n\t\t// too rapidly\n\t\tlet queue: TestEventQueue = []\n\t\tfunction sendEvent(event: TestEvent) {\n\t\t\tqueue.push(event)\n\t\t}\n\t\tconst interval = setInterval(() => {\n\t\t\tif (queue.length) {\n\t\t\t\tsend({ data: JSON.stringify(queue) })\n\t\t\t\tqueue = []\n\t\t\t}\n\t\t}, 10)\n\n\t\tconst isRunning = isTestRunning(app)\n\n\t\tsendEvent({\n\t\t\ttype: 'init',\n\t\t\texitCode: processEntry.exitCode,\n\t\t\tisRunning,\n\t\t\toutput: processEntry.output.map((line) => ({\n\t\t\t\ttype: line.type,\n\t\t\t\tcontent: line.content,\n\t\t\t\ttimestamp: line.timestamp,\n\t\t\t})),\n\t\t})\n\n\t\tconst testProcess = processEntry.process\n\t\tif (!testProcess) {\n\t\t\treturn () => {}\n\t\t}\n\n\t\tfunction handleStdOutData(data: Buffer) {\n\t\t\tsendEvent({\n\t\t\t\ttype: 'stdout',\n\t\t\t\tdata: data.toString('utf-8'),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t})\n\t\t}\n\t\tfunction handleStdErrData(data: Buffer) {\n\t\t\tsendEvent({\n\t\t\t\ttype: 'stderr',\n\t\t\t\tdata: data.toString('utf-8'),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t})\n\t\t}\n\t\tfunction handleExit(code: number) {\n\t\t\ttestProcess?.stdout?.off('data', handleStdOutData)\n\t\t\ttestProcess?.stderr?.off('data', handleStdErrData)\n\t\t\ttestProcess?.off('exit', handleExit)\n\t\t\tsendEvent({ type: 'exit', isRunning: false, code })\n\t\t}\n\t\ttestProcess.stdout?.on('data', handleStdOutData)\n\t\ttestProcess.stderr?.on('data', handleStdErrData)\n\t\ttestProcess.on('exit', handleExit)\n\t\treturn function cleanup() {\n\t\t\ttestProcess.stdout?.off('data', handleStdOutData)\n\t\t\ttestProcess.stderr?.off('data', handleStdErrData)\n\t\t\ttestProcess.off('exit', handleExit)\n\t\t\tclearInterval(interval)\n\t\t}\n\t})\n}\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst userHasAccess = await userHasAccessToWorkshop({\n\t\trequest,\n\t})\n\tif (!userHasAccess) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{\n\t\t\t\tsuccess: false,\n\t\t\t\terror:\n\t\t\t\t\t'You do not have access to this workshop. Login or register for the workshop to be able to run the tests.',\n\t\t\t},\n\t\t\t{\n\t\t\t\tstatus: 403,\n\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\ttitle: 'Access denied',\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'You do not have access to this workshop. Login or register for the workshop to be able to run the tests.',\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t}\n\tconst result = testActionSchema.safeParse({\n\t\tintent: formData.get('intent'),\n\t\tname: formData.get('name'),\n\t})\n\tif (!result.success) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ success: false, error: result.error.flatten() },\n\t\t\t{ status: 400 },\n\t\t)\n\t}\n\tconst app = await getAppByName(result.data.name)\n\tif (!app) {\n\t\treturn dataWithPE(\n\t\t\trequest,\n\t\t\tformData,\n\t\t\t{ success: false, error: 'App not found' },\n\t\t\t{ status: 404 },\n\t\t)\n\t}\n\tswitch (result.data.intent) {\n\t\tcase 'run': {\n\t\t\tvoid runAppTests(app)\n\t\t\treturn dataWithPE(request, formData, { success: true })\n\t\t}\n\t\tcase 'stop': {\n\t\t\tconst processEntry = getTestProcessEntry(app)\n\t\t\tif (processEntry) {\n\t\t\t\tprocessEntry.process?.kill()\n\t\t\t}\n\t\t\treturn dataWithPE(request, formData, { success: true })\n\t\t}\n\t\tcase 'clear': {\n\t\t\tclearTestProcessEntry(app)\n\t\t\treturn dataWithPE(request, formData, { success: true })\n\t\t}\n\t}\n}\n\nfunction simpleReducer<State>(prev: State, getNext: (prev: State) => State) {\n\treturn getNext(prev)\n}\n\nexport function TestOutput({ name }: { name: string }) {\n\ttype State = {\n\t\t/** version is used to trigger an unsubscribe and resubscribe to the event source */\n\t\tversion: number\n\t\tisRunning: boolean\n\t\texitCode: number | null | undefined\n\t\tlines: Array<{\n\t\t\ttype: 'stdout' | 'stderr'\n\t\t\tcontent: string\n\t\t\ttimestamp: number\n\t\t}>\n\t}\n\tconst [state, dispatch] = useReducer(simpleReducer<State>, {\n\t\tversion: 0,\n\t\tisRunning: false,\n\t\texitCode: undefined,\n\t\tlines: [],\n\t})\n\tconst revalidator = useRevalidator()\n\tconst latestRevalidatorRef = useRef(revalidator)\n\tuseEffect(() => {\n\t\tlatestRevalidatorRef.current = revalidator\n\t}, [revalidator])\n\tconst ansi = useAnsiToHtml()\n\tconst { version, isRunning, exitCode, lines } = state\n\tconst lastMessage = useEventSource(\n\t\t`/test?${new URLSearchParams({ name })}&v=${version}`,\n\t)\n\tuseEffect(() => {\n\t\tif (!lastMessage) return\n\n\t\tconst parsed = JSON.parse(lastMessage)\n\t\tconst result = testEventQueueSchema.safeParse(parsed)\n\t\tif (!result.success) {\n\t\t\tconsole.error(result.error.flatten())\n\t\t\treturn\n\t\t}\n\t\tfor (const event of result.data) {\n\t\t\tswitch (event.type) {\n\t\t\t\tcase 'exit': {\n\t\t\t\t\tconst { isRunning, code: exitCode } = event\n\t\t\t\t\tdispatch((prev) => ({ ...prev, isRunning, exitCode }))\n\t\t\t\t\tvoid latestRevalidatorRef.current.revalidate()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'init': {\n\t\t\t\t\tconst { output, exitCode, isRunning } = event\n\t\t\t\t\tdispatch((prev) => ({ ...prev, lines: output, exitCode, isRunning }))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'stderr':\n\t\t\t\tcase 'stdout': {\n\t\t\t\t\tconst { type, data: content, timestamp } = event\n\t\t\t\t\tdispatch((prev) => ({\n\t\t\t\t\t\t...prev,\n\t\t\t\t\t\tlines: [...prev.lines, { type, content, timestamp }].sort(\n\t\t\t\t\t\t\t(a, b) => a.timestamp - b.timestamp,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tisRunning: true,\n\t\t\t\t\t}))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}, [lastMessage])\n\n\treturn (\n\t\t<div className=\"relative flex h-full w-full flex-col overflow-hidden\">\n\t\t\t<div className=\"flex h-12 w-full shrink-0 items-center justify-between border-b\">\n\t\t\t\t<div className=\"flex h-full items-center\">\n\t\t\t\t\t{!isRunning && (\n\t\t\t\t\t\t<TestRunner\n\t\t\t\t\t\t\tname={name}\n\t\t\t\t\t\t\tonRun={() => {\n\t\t\t\t\t\t\t\tdispatch((prev) => ({\n\t\t\t\t\t\t\t\t\t...prev,\n\t\t\t\t\t\t\t\t\texitCode: undefined,\n\t\t\t\t\t\t\t\t\tlines: [],\n\t\t\t\t\t\t\t\t\tversion: prev.version + 1,\n\t\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t\t{isRunning ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<div className=\"flex h-full grow items-center justify-center border-r px-3.5\">\n\t\t\t\t\t\t\t\t<AnimatedBars role=\"status\" aria-label=\"Running Tests\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<StopTest name={name} />\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\n\t\t\t\t{!isRunning && exitCode !== undefined && (\n\t\t\t\t\t<p className=\"pr-3.5 leading-none\">\n\t\t\t\t\t\t{exitCode === 0\n\t\t\t\t\t\t\t? `Tests passed`\n\t\t\t\t\t\t\t: `Test failed (exit code ${String(exitCode)})`}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t\t{!isRunning && exitCode !== undefined && (\n\t\t\t\t\t<ClearTest\n\t\t\t\t\t\tname={name}\n\t\t\t\t\t\tonClear={() => {\n\t\t\t\t\t\t\tdispatch((prev) => ({\n\t\t\t\t\t\t\t\t...prev,\n\t\t\t\t\t\t\t\texitCode: undefined,\n\t\t\t\t\t\t\t\tlines: [],\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"flex min-h-0 flex-1 flex-col gap-5 p-5\">\n\t\t\t\t<p className=\"font-mono text-sm font-medium uppercase\">Test Output</p>\n\t\t\t\t<pre className=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar min-h-0 flex-1 overflow-y-auto\">\n\t\t\t\t\t{lines.map((line) => (\n\t\t\t\t\t\t<code\n\t\t\t\t\t\t\tkey={line.timestamp}\n\t\t\t\t\t\t\tdata-type={line.type}\n\t\t\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t\t\t__html: ansi.toHtml(stripCursorMovements(line.content)),\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</pre>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nexport function TestRunner({\n\tname,\n\tonRun,\n}: {\n\tname: string\n\tonRun?: () => void\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst latestOnRun = useRef(onRun)\n\tuseEffect(() => {\n\t\tlatestOnRun.current = onRun\n\t}, [onRun])\n\tuseEffect(() => {\n\t\tif (fetcher.data?.success) {\n\t\t\tlatestOnRun.current?.()\n\t\t}\n\t}, [fetcher.data])\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/test\" className=\"h-full\">\n\t\t\t{peRedirectInput}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<SimpleTooltip\n\t\t\t\tcontent={fetcher.state === 'idle' ? 'Run Tests' : 'Running Tests...'}\n\t\t\t>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tname=\"intent\"\n\t\t\t\t\tvalue=\"run\"\n\t\t\t\t\tclassName=\"flex h-full grow items-center justify-center border-r px-3.5\"\n\t\t\t\t>\n\t\t\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t\t\t<Icon name=\"TriangleSmall\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<AnimatedBars role=\"status\" />\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t</SimpleTooltip>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function ClearTest({\n\tname,\n\tonClear,\n}: {\n\tname: string\n\tonClear?: () => void\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst latestOnClear = useRef(onClear)\n\tuseEffect(() => {\n\t\tlatestOnClear.current = onClear\n\t}, [onClear])\n\tuseEffect(() => {\n\t\tif (fetcher.data?.success) {\n\t\t\tlatestOnClear.current?.()\n\t\t}\n\t}, [fetcher.data])\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/test\" className=\"h-full\">\n\t\t\t{peRedirectInput}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<SimpleTooltip\n\t\t\t\tcontent={fetcher.state === 'idle' ? 'Clear Tests' : 'Clearing Tests...'}\n\t\t\t>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tname=\"intent\"\n\t\t\t\t\tvalue=\"clear\"\n\t\t\t\t\tclassName=\"flex h-full grow items-center justify-center border-l px-3.5\"\n\t\t\t\t>\n\t\t\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t\t\t<Icon name=\"Clear\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<Icon name=\"Clear\" className=\"animate-pulse\" role=\"status\" />\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t</SimpleTooltip>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function StopTest({\n\tname,\n\tonStop,\n}: {\n\tname: string\n\tonStop?: () => void\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst latestOnStop = useRef(onStop)\n\tuseEffect(() => {\n\t\tlatestOnStop.current = onStop\n\t}, [onStop])\n\tuseEffect(() => {\n\t\tif (fetcher.data?.success) {\n\t\t\tlatestOnStop.current?.()\n\t\t}\n\t}, [fetcher.data])\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/test\" className=\"h-full\">\n\t\t\t{peRedirectInput}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<SimpleTooltip\n\t\t\t\tcontent={fetcher.state === 'idle' ? 'Stop Tests' : 'Stopping Tests...'}\n\t\t\t>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tname=\"intent\"\n\t\t\t\t\tvalue=\"stop\"\n\t\t\t\t\tclassName=\"flex h-full grow items-center justify-center border-r px-3.5\"\n\t\t\t\t>\n\t\t\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t\t\t<Icon name=\"Stop\" />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<Icon name=\"Stop\" className=\"animate-pulse\" role=\"status\" />\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t</SimpleTooltip>\n\t\t</fetcher.Form>\n\t)\n}\n","import { type PlaygroundApp } from '@epic-web/workshop-utils/apps.server'\nimport { Suspense, useState } from 'react'\nimport { ErrorBoundary } from 'react-error-boundary'\nimport { Await } from 'react-router'\nimport { DeferredEpicVideo } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons'\nimport { InBrowserTestRunner } from '#app/components/in-browser-test-runner'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { TestOutput } from '#app/routes/test'\nimport { PlaygroundWindow } from './playground-window'\n\nexport function Tests({\n\tappInfo: playgroundAppInfo,\n\tproblemAppName,\n\tallApps,\n\tisUpToDate,\n\tuserHasAccessPromise,\n}: {\n\tappInfo: Pick<PlaygroundApp, 'appName' | 'name' | 'test'> | null\n\tproblemAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tisUpToDate: boolean\n\tuserHasAccessPromise: Promise<boolean>\n}) {\n\treturn (\n\t\t<PlaygroundWindow\n\t\t\tplaygroundAppName={playgroundAppInfo?.appName}\n\t\t\tproblemAppName={problemAppName}\n\t\t\tallApps={allApps}\n\t\t\tisUpToDate={isUpToDate}\n\t\t>\n\t\t\t<ErrorBoundary\n\t\t\t\tfallbackRender={() => (\n\t\t\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t\t\t<p className=\"text-2xl font-bold\">Error</p>\n\t\t\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\t\t\tThere was an error loading the user access.\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Suspense\n\t\t\t\t\tfallback={\n\t\t\t\t\t\t<div className=\"flex items-center justify-center p-8\">\n\t\t\t\t\t\t\t<SimpleTooltip content=\"Loading user access\">\n\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"animate-spin\" />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Await resolve={userHasAccessPromise}>\n\t\t\t\t\t\t{(userHasAccess) => (\n\t\t\t\t\t\t\t<TestUI\n\t\t\t\t\t\t\t\tplaygroundAppInfo={playgroundAppInfo}\n\t\t\t\t\t\t\t\tuserHasAccess={userHasAccess}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Await>\n\t\t\t\t</Suspense>\n\t\t\t</ErrorBoundary>\n\t\t</PlaygroundWindow>\n\t)\n}\n\nexport function TestUI({\n\tuserHasAccess,\n\tplaygroundAppInfo,\n}: {\n\tplaygroundAppInfo: Pick<PlaygroundApp, 'name' | 'test'> | null\n\tuserHasAccess: boolean\n}) {\n\tconst [inBrowserTestKey, setInBrowserTestKey] = useState(0)\n\n\tif (!userHasAccess) {\n\t\treturn (\n\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t<p className=\"text-2xl font-bold\">Access Denied</p>\n\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\tYou must login or register for the workshop to view and run the\n\t\t\t\t\t\ttests.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"h-16\" />\n\t\t\t\t<p className=\"pb-4\">\n\t\t\t\t\tCheck out this video to see how the test tab works.\n\t\t\t\t</p>\n\t\t\t\t<DeferredEpicVideo url=\"https://www.epicweb.dev/tips/epic-workshop-test-tab-demo\" />\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (!playgroundAppInfo) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>No tests here 😢 Sorry.</p>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (playgroundAppInfo.test.type === 'script') {\n\t\treturn <TestOutput name={playgroundAppInfo.name} />\n\t}\n\n\tif (playgroundAppInfo.test.type === 'browser') {\n\t\tconst { pathname } = playgroundAppInfo.test\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName=\"flex h-full min-h-0 w-full grow flex-col overflow-y-auto\"\n\t\t\t\tkey={inBrowserTestKey}\n\t\t\t>\n\t\t\t\t{playgroundAppInfo.test.testFiles.map((testFile) => (\n\t\t\t\t\t<div key={testFile}>\n\t\t\t\t\t\t<InBrowserTestRunner pathname={pathname} testFile={testFile} />\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t\t<div className=\"px-3 py-[21px]\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tonClick={() => setInBrowserTestKey((c) => c + 1)}\n\t\t\t\t\t\tclassName=\"flex items-center gap-2 font-mono text-sm leading-none uppercase\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Refresh\" aria-hidden /> Rerun All Tests\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t<p>No tests here 😢 Sorry.</p>\n\t\t</div>\n\t)\n}\n","import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tgetExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { userHasAccessToExerciseStep } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport * as Tabs from '@radix-ui/react-tabs'\nimport { clsx } from 'clsx'\nimport * as React from 'react'\nimport {\n\tLink,\n\tuseNavigate,\n\tuseSearchParams,\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tuseOutletContext,\n} from 'react-router'\nimport { Diff } from '#app/components/diff.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { StatusIndicator } from '#app/components/status-indicator.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { type Route } from './+types/index.ts'\nimport { fetchDiscordPosts } from './__shared/discord.server.ts'\nimport { DiscordChat } from './__shared/discord.tsx'\nimport { Playground } from './__shared/playground.tsx'\nimport { Preview } from './__shared/preview.tsx'\nimport { Tests } from './__shared/tests.tsx'\nimport { getAppRunningState, getTestState } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exerciseStepTypeIndexLoader')\n\tconst searchParams = new URL(request.url).searchParams\n\tconst cacheOptions = { request, timings }\n\n\tconst [exerciseStepApp, allAppsFull, problemApp, solutionApp] =\n\t\tawait Promise.all([\n\t\t\trequireExerciseApp(params, cacheOptions),\n\t\t\tgetApps(cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'problem' }, cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'solution' }, cacheOptions),\n\t\t])\n\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\tconst reqUrl = new URL(request.url)\n\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: playgroundApp || problemApp\n\tconst app2 = app2Name ? await getAppByName(app2Name) : solutionApp\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\treturn data(\n\t\t{\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\tallApps,\n\t\t\t// defer this promise so that we don't block the response from being sent\n\t\t\tdiscordPostsPromise: fetchDiscordPosts({ request }),\n\t\t\tuserHasAccessPromise: userHasAccessToExerciseStep({\n\t\t\t\texerciseNumber: Number(params.exerciseNumber),\n\t\t\t\tstepNumber: Number(params.stepNumber),\n\t\t\t\trequest,\n\t\t\t\ttimings,\n\t\t\t}),\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t\ttest: playgroundApp.test,\n\t\t\t\t\t\ttitle: playgroundApp.title,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tisUpToDate: playgroundApp.isUpToDate,\n\t\t\t\t\t\tstackBlitzUrl: playgroundApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(playgroundApp)),\n\t\t\t\t\t\t...getTestState(playgroundApp),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t\ttest: problemApp.test,\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tstackBlitzUrl: problemApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(problemApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t\ttest: solutionApp.test,\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tstackBlitzUrl: solutionApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(solutionApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiff: getDiffProp(),\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst tabs = [\n\t'playground',\n\t'problem',\n\t'solution',\n\t'tests',\n\t'diff',\n\t'chat',\n] as const\nconst isValidPreview = (s: string | null): s is (typeof tabs)[number] =>\n\tBoolean(s && tabs.includes(s as (typeof tabs)[number]))\n\nfunction withParam(\n\tsearchParams: URLSearchParams,\n\tkey: string,\n\tvalue: string | null,\n) {\n\tconst newSearchParams = new URLSearchParams(searchParams)\n\tif (value === null) {\n\t\tnewSearchParams.delete(key)\n\t} else {\n\t\tnewSearchParams.set(key, value)\n\t}\n\treturn newSearchParams\n}\n\nexport default function ExercisePartRoute({\n\tloaderData,\n}: Route.ComponentProps) {\n\tconst { inBrowserBrowserRef } = useOutletContext<{\n\t\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\t}>()\n\tconst workshopConfig = useWorkshopConfig()\n\tconst [searchParams] = useSearchParams()\n\n\tconst preview = searchParams.get('preview')\n\n\tconst altDown = useAltDown()\n\tconst navigate = useNavigate()\n\n\tfunction shouldHideTab(tab: (typeof tabs)[number]) {\n\t\tif (tab === 'tests') {\n\t\t\treturn (\n\t\t\t\tENV.EPICSHOP_DEPLOYED ||\n\t\t\t\t!loaderData.playground ||\n\t\t\t\tloaderData.playground.test.type === 'none'\n\t\t\t)\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution') {\n\t\t\tif (loaderData[tab]?.dev.type === 'none') return true\n\t\t\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\t\t\tconst devType = loaderData[tab]?.dev.type\n\t\t\t\treturn (\n\t\t\t\t\tdevType !== 'browser' &&\n\t\t\t\t\tdevType !== 'export' &&\n\t\t\t\t\t!loaderData[tab]?.stackBlitzUrl\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tif (tab === 'playground' && ENV.EPICSHOP_DEPLOYED) return true\n\n\t\tif (tab === 'chat') {\n\t\t\treturn !workshopConfig.product.discordChannelId\n\t\t}\n\t\treturn false\n\t}\n\n\tfunction getTabStatus(\n\t\ttab: (typeof tabs)[number],\n\t): 'running' | 'passed' | 'failed' | null {\n\t\tif (tab === 'tests') {\n\t\t\tif (!loaderData.playground) return null\n\t\t\tconst { isTestRunning, testExitCode } = loaderData.playground\n\t\t\tif (isTestRunning) return 'running'\n\t\t\tif (testExitCode === 0) return 'passed'\n\t\t\tif (testExitCode !== null && testExitCode !== 0) return 'failed'\n\t\t\treturn null\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution' || tab === 'playground') {\n\t\t\tconst appData =\n\t\t\t\ttab === 'playground' ? loaderData.playground : loaderData[tab]\n\t\t\tif (appData?.isRunning) return 'running'\n\t\t}\n\t\treturn null\n\t}\n\n\tconst activeTab = isValidPreview(preview)\n\t\t? preview\n\t\t: tabs.find((t) => !shouldHideTab(t))\n\n\t// when alt is held down, the diff tab should open to the full-page diff view\n\t// between the problem and solution (this is more for the instructor than the student)\n\tconst altDiffUrl = `/diff?${new URLSearchParams({\n\t\tapp1: loaderData.problem?.name ?? '',\n\t\tapp2: loaderData.solution?.name ?? '',\n\t})}`\n\n\tfunction handleDiffTabClick(event: React.MouseEvent<HTMLAnchorElement>) {\n\t\tif (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) {\n\t\t\tevent.preventDefault()\n\t\t\tvoid navigate(altDiffUrl)\n\t\t}\n\t}\n\n\treturn (\n\t\t<Tabs.Root\n\t\t\tclassName=\"relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden sm:col-span-1 sm:row-span-1\"\n\t\t\tvalue={activeTab}\n\t\t\t// intentionally no onValueChange here because the Link will trigger the\n\t\t\t// change.\n\t\t>\n\t\t\t<Tabs.List className=\"scrollbar-thin scrollbar-thumb-scrollbar h-14 min-h-14 overflow-x-auto border-b whitespace-nowrap\">\n\t\t\t\t{tabs.map((tab) => {\n\t\t\t\t\tconst hidden = shouldHideTab(tab)\n\t\t\t\t\tconst status = getTabStatus(tab)\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Tabs.Trigger key={tab} value={tab} hidden={hidden} asChild>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tid={`${tab}-tab`}\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'clip-path-button radix-state-active:z-10 radix-state-active:bg-foreground radix-state-active:text-background radix-state-active:hover:bg-foreground/80 radix-state-active:hover:text-background/80 radix-state-inactive:hover:bg-foreground/20 radix-state-inactive:hover:text-foreground/80 focus:bg-foreground/80 focus:text-background/80 relative h-full px-6 py-4 font-mono text-sm uppercase outline-none',\n\t\t\t\t\t\t\t\t\thidden ? 'hidden' : 'inline-block',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tpreventScrollReset\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tonClick={handleDiffTabClick}\n\t\t\t\t\t\t\t\tto={\n\t\t\t\t\t\t\t\t\ttab === 'diff' && altDown\n\t\t\t\t\t\t\t\t\t\t? altDiffUrl\n\t\t\t\t\t\t\t\t\t\t: `?${withParam(\n\t\t\t\t\t\t\t\t\t\t\t\tsearchParams,\n\t\t\t\t\t\t\t\t\t\t\t\t'preview',\n\t\t\t\t\t\t\t\t\t\t\t\ttab === 'playground' ? null : tab,\n\t\t\t\t\t\t\t\t\t\t\t)}`\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t{status && <StatusIndicator status={status} />}\n\t\t\t\t\t\t\t\t\t<span>{tab}</span>\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</Tabs.Trigger>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t</Tabs.List>\n\t\t\t<div className=\"relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden\">\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"playground\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Playground\n\t\t\t\t\t\tappInfo={loaderData.playground}\n\t\t\t\t\t\tproblemAppName={loaderData.problem?.name}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tisUpToDate={loaderData.playground?.isUpToDate ?? false}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"problem\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={loaderData.problem}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"solution\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={loaderData.solution}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"tests\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start overflow-hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Tests\n\t\t\t\t\t\tappInfo={loaderData.playground}\n\t\t\t\t\t\tproblemAppName={loaderData.problem?.name}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tisUpToDate={loaderData.playground?.isUpToDate ?? false}\n\t\t\t\t\t\tuserHasAccessPromise={loaderData.userHasAccessPromise}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"diff\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t>\n\t\t\t\t\t<Diff\n\t\t\t\t\t\tdiff={loaderData.diff}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tuserHasAccessPromise={loaderData.userHasAccessPromise}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"chat\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t>\n\t\t\t\t\t<DiscordChat />\n\t\t\t\t</Tabs.Content>\n\t\t\t</div>\n\t\t</Tabs.Root>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import { requireExerciseApp } from '@epic-web/workshop-utils/apps.server'\nimport { userHasAccessToExerciseStep } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport {\n\tdata,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tuseLoaderData,\n} from 'react-router'\nimport { TestUI } from './__shared/tests.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exercise-step-test')\n\tconst exerciseStepApp = await requireExerciseApp(params, { request, timings })\n\n\treturn data(\n\t\t{\n\t\t\tappInfo: {\n\t\t\t\tname: exerciseStepApp?.name,\n\t\t\t\ttest: exerciseStepApp?.test,\n\t\t\t},\n\t\t\tuserHasAccess: await userHasAccessToExerciseStep({\n\t\t\t\texerciseNumber: Number(params.exerciseNumber),\n\t\t\t\tstepNumber: Number(params.stepNumber),\n\t\t\t\trequest,\n\t\t\t\ttimings,\n\t\t\t}),\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nexport default function TestsList() {\n\tconst { appInfo, userHasAccess } = useLoaderData<typeof loader>()\n\n\treturn (\n\t\t<TestUI\n\t\t\tkey={appInfo.name}\n\t\t\tplaygroundAppInfo={appInfo}\n\t\t\tuserHasAccess={userHasAccess}\n\t\t/>\n\t)\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport {\n\tgetExerciseApp,\n\tisProblemApp,\n\tisSolutionApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { getStep404Data } from './__shared/error-boundary.server.ts'\nimport { Exercise404ErrorBoundary } from './__shared/error-boundary.tsx'\n\nexport async function loader({ params }: LoaderFunctionArgs) {\n\tinvariantResponse(params.exerciseNumber, 'exerciseNumber is required')\n\tconst problemApp = await getExerciseApp({ ...params, type: 'problem' }).then(\n\t\t(a) => (isProblemApp(a) ? a : null),\n\t)\n\tif (problemApp) {\n\t\treturn redirect(\n\t\t\t`/exercise/${params.exerciseNumber}/${params.stepNumber}/problem`,\n\t\t)\n\t}\n\tconst solutionApp = await getExerciseApp({\n\t\t...params,\n\t\ttype: 'solution',\n\t}).then((a) => (isSolutionApp(a) ? a : null))\n\tif (solutionApp) {\n\t\treturn redirect(\n\t\t\t`/exercise/${params.exerciseNumber}/${params.stepNumber}/solution`,\n\t\t)\n\t}\n\tthrow Response.json(\n\t\tawait getStep404Data({ exerciseNumber: params.exerciseNumber }),\n\t\t{ status: 404 },\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tclassName=\"container flex items-center justify-center\"\n\t\t\tstatusHandlers={{\n\t\t\t\t404: Exercise404ErrorBoundary,\n\t\t\t}}\n\t\t/>\n\t)\n}\n","import path from 'path'\nimport { invariantResponse } from '@epic-web/invariant'\nimport { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetAppPageRoute,\n\tgetApps,\n\tgetExercise,\n\tgetWorkshopRoot,\n\tisExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport * as React from 'react'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { type Route } from './+types/$exerciseNumber_.finished.tsx'\n\nexport const meta: Route.MetaFunction = ({ loaderData, matches }) => {\n\tconst number = loaderData?.exercise.exerciseNumber.toString().padStart(2, '0')\n\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!loaderData || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🦉 | ${number}. ${loaderData.exercise.title} | ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${number}. ${loaderData.exercise.title}`,\n\t\togTitle: `Finished: ${loaderData.exercise.title}`,\n\t\togDescription: `Elaboration for exercise ${Number(number)}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('exerciseFinishedLoader')\n\tinvariantResponse(params.exerciseNumber, 'exerciseNumber is required')\n\tconst exercise = await getExercise(params.exerciseNumber, {\n\t\ttimings,\n\t\trequest,\n\t})\n\tif (!exercise) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\n\tconst workshopConfig = getWorkshopConfig()\n\tconst exerciseFormTemplate = workshopConfig.forms.exercise\n\tconst exerciseFormEmbedUrl = exerciseFormTemplate\n\t\t.replace('{workshopTitle}', encodeURIComponent(workshopConfig.title))\n\t\t.replace('{exerciseTitle}', encodeURIComponent(exercise.title))\n\tconst nextExercise = await getExercise(exercise.exerciseNumber + 1, {\n\t\ttimings,\n\t\trequest,\n\t})\n\n\tconst finishedFilepath = path.join(\n\t\tgetWorkshopRoot(),\n\t\t'exercises',\n\t\texercise.dirName,\n\t\t'FINISHED.mdx',\n\t)\n\n\tconst apps = await getApps({ request, timings })\n\tconst exerciseApps = apps\n\t\t.filter(isExerciseStepApp)\n\t\t.filter((app) => app.exerciseNumber === exercise.exerciseNumber)\n\tconst prevApp = exerciseApps[exerciseApps.length - 1]\n\n\tconst articleId = `workshop-${slugify(workshopConfig.title)}-${\n\t\texercise.exerciseNumber\n\t}-finished`\n\n\treturn data(\n\t\t{\n\t\t\tarticleId,\n\t\t\tworkshopTitle: workshopConfig.title,\n\t\t\texercise,\n\t\t\texerciseFormEmbedUrl,\n\t\t\tepicVideoInfosPromise: getEpicVideoInfos(\n\t\t\t\texercise.finishedEpicVideoEmbeds,\n\t\t\t\t{ request },\n\t\t\t),\n\t\t\texerciseFinished: {\n\t\t\t\tfile: finishedFilepath,\n\t\t\t\trelativePath: `exercises/${exercise.dirName}/FINISHED.mdx`,\n\t\t\t},\n\t\t\tprevStepLink: prevApp\n\t\t\t\t? {\n\t\t\t\t\t\tto: getAppPageRoute(prevApp),\n\t\t\t\t\t\t'aria-label': `${prevApp.title} (${prevApp.type})`,\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t\tnextStepLink: nextExercise\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${nextExercise.exerciseNumber.toString().padStart(2, '0')}`,\n\t\t\t\t\t\t'aria-label': `${nextExercise.title}`,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tto: '/finished',\n\t\t\t\t\t\t'aria-label': 'Finished! 🎉',\n\t\t\t\t\t},\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst mdxComponents = { h1: () => null }\nexport default function ExerciseFinished({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tconst exerciseNumber = data.exercise.exerciseNumber\n\t\t.toString()\n\t\t.padStart(2, '0')\n\n\tuseRevalidationWS({\n\t\twatchPaths: [`./exercises/${exerciseNumber}/FINISHED.mdx`],\n\t})\n\n\treturn (\n\t\t<div className=\"flex max-w-full grow flex-col\">\n\t\t\t<main className=\"flex grow flex-col sm:grid sm:h-full sm:min-h-[800px] sm:grid-cols-1 sm:grid-rows-2 md:min-h-[unset] lg:grid-cols-2 lg:grid-rows-1\">\n\t\t\t\t<div className=\"relative flex flex-col sm:col-span-1 sm:row-span-1 sm:h-full lg:border-r\">\n\t\t\t\t\t<h1 className=\"h-14 border-b pr-5 pl-10 text-sm leading-tight font-medium\">\n\t\t\t\t\t\t<div className=\"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2\">\n\t\t\t\t\t\t\t\t<Link to={`/${exerciseNumber}`} className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{`${exerciseNumber}. ${data.exercise.title}`}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t<span>/</span>\n\t\t\t\t\t\t\t\t<span>Elaboration</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\n\t\t\t\t\t<article\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8\"\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.exercise.finishedCode ? (\n\t\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\t\tcode={data.exercise.finishedCode}\n\t\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t// TODO: render a random dad joke...\n\t\t\t\t\t\t\t'No finished instructions yet...'\n\t\t\t\t\t\t)}\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\texerciseNumber={data.exercise.exerciseNumber}\n\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\tfile={data.exerciseFinished.file}\n\t\t\t\t\t\t\trelativePath={data.exerciseFinished.relativePath}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<NavChevrons prev={data.prevStepLink} next={data.nextStepLink} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<Survey\n\t\t\t\t\texerciseFormEmbedUrl={data.exerciseFormEmbedUrl}\n\t\t\t\t\texerciseTitle={data.exercise.title}\n\t\t\t\t/>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nfunction Survey({\n\texerciseFormEmbedUrl,\n\texerciseTitle,\n}: {\n\texerciseFormEmbedUrl: string\n\texerciseTitle: string\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"relative shrink-0\">\n\t\t\t\t<div className=\"text-body-md text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{'Unable to load the '}\n\t\t\t\t\t\t\t<a href={exerciseFormEmbedUrl} className=\"underline\">\n\t\t\t\t\t\t\t\t{`${exerciseTitle} feedback form`}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{' when offline'}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\treturn (\n\t\t<div className=\"relative min-h-full sm:min-h-[unset] sm:shrink-0\">\n\t\t\t{!iframeLoaded ? (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>Loading {exerciseTitle} Elaboration form</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\ttitle=\"Elaboration\"\n\t\t\t\tsrc={exerciseFormEmbedUrl}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n","import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopFinished,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport slugify from '@sindresorhus/slugify'\nimport * as React from 'react'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { EditFileOnGitHub } from '../launch-editor.tsx'\nimport { ProgressToggle } from '../progress.tsx'\nimport { useTheme } from '../theme/index.tsx'\nimport { type Route } from './+types/finished.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => [{ route: '/finished' }],\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!rootData) return []\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🎉 ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${rootData?.workshopTitle}`,\n\t\togTitle: `Finished ${rootData?.workshopTitle}`,\n\t\togDescription: `You finished! Time to submit feedback.`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('finishedLoader')\n\tconst exercises = await getExercises({ request, timings })\n\tconst compiledFinished = await time(() => getWorkshopFinished({ request }), {\n\t\ttimings,\n\t\ttype: 'compileMdx',\n\t\tdesc: 'compileMdx in finished',\n\t})\n\n\tconst lastExercises = exercises[exercises.length - 1]\n\tconst workshopConfig = getWorkshopConfig()\n\tconst workshopTitle = workshopConfig.title\n\tconst workshopFormTemplate = workshopConfig.forms.workshop\n\tconst workshopFormEmbedUrl = workshopFormTemplate.replace(\n\t\t'{workshopTitle}',\n\t\tencodeURIComponent(workshopTitle),\n\t)\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(workshopTitle)}-finished`,\n\t\t\tworkshopTitle,\n\t\t\tworkshopFormEmbedUrl,\n\t\t\tfinishedCode:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? compiledFinished.compiled.code\n\t\t\t\t\t: null,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(compiledFinished.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t\tworkshopFinished: {\n\t\t\t\tstatus: compiledFinished.compiled.status,\n\t\t\t\tfile: compiledFinished.file,\n\t\t\t\trelativePath: compiledFinished.relativePath,\n\t\t\t},\n\t\t\tprevStepLink: lastExercises\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/${lastExercises.exerciseNumber}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function ExerciseFinished({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tuseRevalidationWS({ watchPaths: ['./exercises/FINISHED.mdx'] })\n\treturn (\n\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t<main className=\"grid h-full grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1\">\n\t\t\t\t<div className=\"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r\">\n\t\t\t\t\t<h1 className=\"h-14 border-b pr-5 pl-10 text-sm leading-none font-medium uppercase\">\n\t\t\t\t\t\t<div className=\"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2\">\n\t\t\t\t\t\t\t\t<Link to=\"/\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{data.workshopTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t<span>/</span>\n\t\t\t\t\t\t\t\t<span>Elaboration</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8\"\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.finishedCode ? (\n\t\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t\t<Mdx code={data.finishedCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t// TODO: render a random dad joke...\n\t\t\t\t\t\t\t'No finished instructions yet...'\n\t\t\t\t\t\t)}\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\ttype=\"workshop-finished\"\n\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t{data.workshopFinished.status === 'success' ? (\n\t\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\t\tfile={data.workshopFinished.file}\n\t\t\t\t\t\t\t\trelativePath={data.workshopFinished.relativePath}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<NavChevrons prev={data.prevStepLink} next={{ to: '/' }} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<Survey\n\t\t\t\t\tworkshopTitle={data.workshopTitle}\n\t\t\t\t\tworkshopFormEmbedUrl={data.workshopFormEmbedUrl}\n\t\t\t\t/>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nfunction Survey({\n\tworkshopTitle,\n\tworkshopFormEmbedUrl,\n}: {\n\tworkshopTitle: string\n\tworkshopFormEmbedUrl: string\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"relative shrink-0\">\n\t\t\t\t<div className=\"text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{'Unable to load the '}\n\t\t\t\t\t\t\t<a href={workshopFormEmbedUrl} className=\"underline\">\n\t\t\t\t\t\t\t\t{`${workshopTitle} feedback form`}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{' when offline'}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\treturn (\n\t\t<div className=\"relative shrink-0\">\n\t\t\t{!iframeLoaded ? (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>Loading {workshopTitle} Elaboration form</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\ttitle=\"Elaboration\"\n\t\t\t\tsrc={workshopFormEmbedUrl}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n","import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopInstructions,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { ProgressToggle, useExerciseProgressClassName } from '../progress.tsx'\nimport { type Route } from './+types/index.tsx'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('indexLoader')\n\tconst { title } = getWorkshopConfig()\n\tconst [exercises, workshopReadme] = await Promise.all([\n\t\ttime(() => getExercises({ request, timings }), {\n\t\t\ttimings,\n\t\t\ttype: 'getExercises',\n\t\t\tdesc: 'getExercises in index',\n\t\t}),\n\t\ttime(() => getWorkshopInstructions({ request }), {\n\t\t\ttimings,\n\t\t\ttype: 'compileMdx',\n\t\t\tdesc: 'compileMdx in index',\n\t\t}),\n\t])\n\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(title)}-instructions`,\n\t\t\ttitle:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? workshopReadme.compiled.title\n\t\t\t\t\t: title,\n\t\t\texercises: exercises.map((e) => ({\n\t\t\t\texerciseNumber: e.exerciseNumber,\n\t\t\t\ttitle: e.title,\n\t\t\t})),\n\t\t\tworkshopReadme,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(workshopReadme.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nfunction ExerciseListItem({\n\tindex,\n\texercise,\n}: {\n\tindex: number\n\texercise: Awaited<Route.ComponentProps['loaderData']>['exercises'][number]\n}) {\n\tconst progressClassName = useExerciseProgressClassName(\n\t\texercise.exerciseNumber,\n\t)\n\treturn (\n\t\t<li key={exercise.exerciseNumber}>\n\t\t\t<Link\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition after:absolute after:right-10 after:-translate-x-2 after:opacity-0 after:transition after:content-['→'] hover:bg-gray-50 hover:after:translate-x-0 hover:after:opacity-100 dark:hover:bg-white/5\",\n\t\t\t\t\tprogressClassName,\n\t\t\t\t)}\n\t\t\t\tto={`${exercise.exerciseNumber.toString().padStart(2, '0')}`}\n\t\t\t\tdata-keyboard-action={index === 0 ? 'g+n' : undefined}\n\t\t\t>\n\t\t\t\t<span className=\"text-xs font-normal tabular-nums opacity-50\">\n\t\t\t\t\t{exercise.exerciseNumber}\n\t\t\t\t</span>\n\t\t\t\t<span>{exercise.title}</span>\n\t\t\t</Link>\n\t\t</li>\n\t)\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function Index({ loaderData: data }: Route.ComponentProps) {\n\tconst exerciseLinks = (\n\t\t<ul className=\"divide-border dark:divide-border/50 flex flex-col divide-y\">\n\t\t\t<strong className=\"px-10 pb-3 font-mono text-xs uppercase\">\n\t\t\t\tExercises\n\t\t\t</strong>\n\t\t\t{data.exercises.map((exercise, index) => (\n\t\t\t\t<ExerciseListItem\n\t\t\t\t\tkey={exercise.exerciseNumber}\n\t\t\t\t\tindex={index}\n\t\t\t\t\texercise={exercise}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</ul>\n\t)\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"px-10 text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold\">\n\t\t\t\t\t\t{data.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"w-full max-w-none scroll-pt-6 border-t px-3 pt-3 md:px-10 md:pt-8\">\n\t\t\t\t\t<h2 className=\"pb-5 font-mono text-xs font-semibold uppercase\">\n\t\t\t\t\t\tIntro\n\t\t\t\t\t</h2>\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.workshopReadme.compiled.code}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t) : data.workshopReadme.compiled.status === 'error' ? (\n\t\t\t\t\t\t<div className=\"text-red-500\">\n\t\t\t\t\t\t\tThere was an error:\n\t\t\t\t\t\t\t<pre>{data.workshopReadme.compiled.error}</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No instructions yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"pt-10 pb-5\">\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code &&\n\t\t\t\t\tdata.workshopReadme.compiled.code.length > 500\n\t\t\t\t\t\t? exerciseLinks\n\t\t\t\t\t\t: null}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t<ProgressToggle\n\t\t\t\ttype=\"workshop-instructions\"\n\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t/>\n\t\t\t<div className=\"flex h-16 justify-center border-t\">\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.workshopReadme.file}\n\t\t\t\t\trelativePath={data.workshopReadme.relativePath}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn <GeneralErrorBoundary />\n}\n","import { getExercises } from '@epic-web/workshop-utils/apps.server'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst exercises = await getExercises({ request })\n\tif (!exercises.length) {\n\t\tthrow new Response('No exercises found', { status: 404 })\n\t}\n\n\tconst lastExercise = exercises[exercises.length - 1]\n\tif (!lastExercise || !lastExercise.steps || !lastExercise.steps.length) {\n\t\tthrow new Response('No steps found in last exercise', { status: 404 })\n\t}\n\n\tconst lastStep = lastExercise.steps[lastExercise.steps.length - 1]\n\tif (!lastStep || !lastStep.solution) {\n\t\tthrow new Response('No solution found for last step', { status: 404 })\n\t}\n\n\tconst exerciseNumber = lastExercise.exerciseNumber.toString().padStart(2, '0')\n\tconst stepNumber = lastStep.stepNumber.toString().padStart(2, '0')\n\treturn redirect(`/exercise/${exerciseNumber}/${stepNumber}/solution`)\n}\n\nexport default function LastExerciseRedirect() {\n\treturn null\n}\n","export const EVENTS = {\n\tUSER_CODE_RECEIVED: 'USER_CODE_RECEIVED',\n\tAUTH_RESOLVED: 'AUTH_RESOLVED',\n\tAUTH_REJECTED: 'AUTH_REJECTED',\n} as const\nexport type EventTypes = keyof typeof EVENTS\n","import { EventEmitter } from 'events'\nimport { remember } from '@epic-web/remember'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { setAuthInfo } from '@epic-web/workshop-utils/db.server'\nimport { getUserInfo } from '@epic-web/workshop-utils/epic-api.server'\nimport { logger } from '@epic-web/workshop-utils/logger'\nimport * as client from 'openid-client'\nimport { z } from 'zod'\nimport { EVENTS } from './auth-events.ts'\nimport { getErrorMessage } from './misc.tsx'\n\nconst log = logger('epic:auth')\n\nconst UserInfoSchema = z.object({\n\tid: z.string(),\n\temail: z.string(),\n\tname: z.string().nullable().optional(),\n})\n\nexport const authEmitter = remember('authEmitter', () => new EventEmitter())\n// cleanup any that may exist already\nauthEmitter.removeAllListeners()\n\nexport async function registerDevice() {\n\tlog('Starting device registration process')\n\tconst {\n\t\tproduct: { host },\n\t} = getWorkshopConfig()\n\tconst { ISSUER = `https://${host}/oauth` } = process.env\n\tlog.info(`Using OAuth issuer: ${ISSUER}`)\n\n\ttry {\n\t\tlog('Discovering OAuth configuration')\n\t\tconst config = await client.discovery(new URL(ISSUER), 'EPICSHOP_APP')\n\t\tlog.info('OAuth configuration discovered successfully')\n\n\t\tlog('Initiating device authorization')\n\t\tconst deviceResponse = await client.initiateDeviceAuthorization(config, {})\n\t\tlog.info(\n\t\t\t`Device authorization initiated - user code: ${deviceResponse.user_code}`,\n\t\t)\n\n\t\tauthEmitter.emit(EVENTS.USER_CODE_RECEIVED, {\n\t\t\tcode: deviceResponse.user_code,\n\t\t\turl: deviceResponse.verification_uri_complete,\n\t\t})\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\tlog.error('Device authorization timed out')\n\t\t\tthrow new Error('Device authorization timed out')\n\t\t}, deviceResponse.expires_in * 1000)\n\n\t\ttry {\n\t\t\tlog('Polling for device authorization grant')\n\t\t\tconst tokenSet = await client.pollDeviceAuthorizationGrant(\n\t\t\t\tconfig,\n\t\t\t\tdeviceResponse,\n\t\t\t)\n\t\t\tclearTimeout(timeout)\n\n\t\t\tif (!tokenSet) {\n\t\t\t\tlog.error('No token set received from device authorization')\n\t\t\t\tauthEmitter.emit(EVENTS.AUTH_REJECTED, {\n\t\t\t\t\terror: 'No token set',\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.info('Device authorization grant received successfully')\n\n\t\t\tlog('Fetching user info from protected resource')\n\t\t\tconst protectedResourceResponse = await client.fetchProtectedResource(\n\t\t\t\tconfig,\n\t\t\t\ttokenSet.access_token,\n\t\t\t\tnew URL(`${ISSUER}/userinfo`),\n\t\t\t\t'GET',\n\t\t\t)\n\t\t\tconst userinfoRaw = await protectedResourceResponse.json()\n\t\t\tlog.info('User info fetched from protected resource')\n\n\t\t\tconst userinfoResult = UserInfoSchema.safeParse(userinfoRaw)\n\t\t\tif (!userinfoResult.success) {\n\t\t\t\tlog.error(`Failed to parse user info: ${userinfoResult.error.message}`)\n\t\t\t\tauthEmitter.emit(EVENTS.AUTH_REJECTED, {\n\t\t\t\t\terror: `Failed to parse user info: ${userinfoResult.error.message}`,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst userinfo = userinfoResult.data\n\t\t\tlog.info(\n\t\t\t\t`User info parsed successfully - ID: ${userinfo.id}, Email: ${userinfo.email}`,\n\t\t\t)\n\n\t\t\tlog('Setting auth info in database')\n\t\t\tawait setAuthInfo({\n\t\t\t\tid: userinfo.id,\n\t\t\t\ttokenSet,\n\t\t\t\temail: userinfo.email,\n\t\t\t\tname: userinfo.name,\n\t\t\t})\n\t\t\tlog.info('Auth info saved to database successfully')\n\n\t\t\tlog('Fetching fresh user info from API')\n\t\t\tawait getUserInfo({ forceFresh: true })\n\t\t\tlog.info('Fresh user info fetched successfully')\n\n\t\t\tlog('Authentication process completed successfully')\n\t\t\tauthEmitter.emit(EVENTS.AUTH_RESOLVED)\n\t\t} catch (error) {\n\t\t\tclearTimeout(timeout)\n\t\t\tlog.error('Error during device authorization polling:', error)\n\t\t\tthrow error\n\t\t}\n\t} catch (error) {\n\t\tlog.error('Device registration failed:', error)\n\t\tauthEmitter.emit(EVENTS.AUTH_REJECTED, {\n\t\t\terror: getErrorMessage(error),\n\t\t})\n\t}\n}\n","import { type LoaderFunctionArgs } from 'react-router'\nimport { eventStream } from 'remix-utils/sse/server'\nimport { z } from 'zod'\nimport { EVENTS } from '#app/utils/auth-events.ts'\nimport { authEmitter } from '#app/utils/auth.server.ts'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\n\nconst CodeReceivedEventSchema = z.object({\n\ttype: z.literal(EVENTS.USER_CODE_RECEIVED),\n\tcode: z.string(),\n\turl: z.string(),\n})\nconst AuthResolvedEventSchema = z.object({\n\ttype: z.literal(EVENTS.AUTH_RESOLVED),\n})\nconst AuthRejectedEventSchema = z.object({\n\ttype: z.literal(EVENTS.AUTH_REJECTED),\n\terror: z.string().optional().default('Unknown error'),\n})\nexport const EventSchema = z.union([\n\tCodeReceivedEventSchema,\n\tAuthResolvedEventSchema,\n\tAuthRejectedEventSchema,\n])\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\treturn eventStream(request.signal, function setup(send) {\n\t\tfunction handleCodeReceived(data: any) {\n\t\t\tsend({\n\t\t\t\tdata: JSON.stringify(\n\t\t\t\t\tCodeReceivedEventSchema.parse({\n\t\t\t\t\t\ttype: EVENTS.USER_CODE_RECEIVED,\n\t\t\t\t\t\t...data,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t})\n\t\t}\n\t\tfunction handleAuthResolved() {\n\t\t\tsend({ data: JSON.stringify({ type: EVENTS.AUTH_RESOLVED }) })\n\t\t}\n\t\tfunction handleAuthRejected(data: any) {\n\t\t\tconst result = AuthRejectedEventSchema.safeParse({\n\t\t\t\ttype: EVENTS.AUTH_REJECTED,\n\t\t\t\t...data,\n\t\t\t})\n\t\t\tif (result.success) {\n\t\t\t\tsend({ data: JSON.stringify(result.data) })\n\t\t\t} else {\n\t\t\t\tconsole.error('Error parsing auth rejected event', result.error, data)\n\t\t\t}\n\t\t}\n\t\tauthEmitter.on(EVENTS.USER_CODE_RECEIVED, handleCodeReceived)\n\t\tauthEmitter.on(EVENTS.AUTH_RESOLVED, handleAuthResolved)\n\t\tauthEmitter.on(EVENTS.AUTH_REJECTED, handleAuthRejected)\n\t\treturn () => {\n\t\t\tauthEmitter.off(EVENTS.USER_CODE_RECEIVED, handleCodeReceived)\n\t\t\tauthEmitter.off(EVENTS.AUTH_RESOLVED, handleAuthResolved)\n\t\t\tauthEmitter.off(EVENTS.AUTH_REJECTED, handleAuthRejected)\n\t\t}\n\t})\n}\n","import { getAuthInfo } from '@epic-web/workshop-utils/db.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { useEffect, useState } from 'react'\nimport {\n\tredirect,\n\tLink,\n\tuseFetcher,\n\tuseNavigate,\n\tuseRevalidator,\n} from 'react-router'\nimport { useEventSource } from 'remix-utils/sse/react'\nimport { Button, ButtonLink } from '#app/components/button.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { Logo } from '#app/components/product.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { EVENTS } from '#app/utils/auth-events.ts'\nimport { registerDevice } from '#app/utils/auth.server.ts'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { EventSchema } from '../login-sse.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst isAuthenticated = Boolean(await getAuthInfo())\n\tif (isAuthenticated) throw redirect('/account')\n\treturn {}\n}\n\nexport async function action() {\n\tensureUndeployed()\n\tvoid registerDevice()\n\treturn { status: 'pending' } as const\n}\n\nexport default function Login() {\n\tconst {\n\t\tproduct: { displayName },\n\t} = useWorkshopConfig()\n\tconst loginFetcher = useFetcher<typeof action>()\n\tconst [clickedVerificationLink, setClickedVerificationLink] = useState(false)\n\tconst [authError, setAuthError] = useState<null | string>(null)\n\tconst [userCodeInfo, setUserCodeInfo] = useState<null | {\n\t\tcode: string\n\t\turl: string\n\t}>(null)\n\tconst navigate = useNavigate()\n\tconst revalidator = useRevalidator()\n\tconst lastMessage = useEventSource(`/login-sse`)\n\tuseEffect(() => {\n\t\tif (!lastMessage) return\n\n\t\tconst parsed = JSON.parse(lastMessage)\n\t\tconst result = EventSchema.safeParse(parsed)\n\t\tif (!result.success) {\n\t\t\tconsole.error(result.error.flatten())\n\t\t\treturn\n\t\t}\n\t\tswitch (result.data.type) {\n\t\t\tcase EVENTS.USER_CODE_RECEIVED: {\n\t\t\t\tsetUserCodeInfo(result.data)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase EVENTS.AUTH_RESOLVED: {\n\t\t\t\tvoid revalidator.revalidate().then(() => navigate('/'))\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase EVENTS.AUTH_REJECTED: {\n\t\t\t\tsetAuthError(result.data.error)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}, [lastMessage, navigate, revalidator])\n\n\treturn (\n\t\t<main className=\"flex h-full w-full grow flex-col items-center justify-center p-10\">\n\t\t\t<div className=\"flex flex-col items-center\">\n\t\t\t\t<Logo className=\"h-16 w-16\" />\n\t\t\t\t<h1 className=\"pt-5 text-2xl font-semibold md:text-3xl\">\n\t\t\t\t\tLogin to {displayName}\n\t\t\t\t</h1>\n\t\t\t\t<div className=\"flex w-full flex-col items-center pt-5\">\n\t\t\t\t\t{userCodeInfo ? (\n\t\t\t\t\t\t<div className=\"flex w-full max-w-md flex-col items-center gap-3\">\n\t\t\t\t\t\t\t<div className=\"my-2 flex w-full flex-col items-center gap-2\">\n\t\t\t\t\t\t\t\t<p className=\"text-lg\">Your verification code is: </p>\n\t\t\t\t\t\t\t\t<div className=\"mb-3 w-full bg-gray-100 px-5 py-3 text-center text-lg font-bold dark:bg-black/40\">\n\t\t\t\t\t\t\t\t\t<code>{userCodeInfo.code}</code>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<p className=\"text-base\">\n\t\t\t\t\t\t\t\t\tYou'll use this to verify your device on {displayName}. Click\n\t\t\t\t\t\t\t\t\tverify code below to open the verification page.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<ButtonLink\n\t\t\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\t\t\tto={userCodeInfo.url}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tonClick={() => setClickedVerificationLink(true)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tVerify Auth Code\n\t\t\t\t\t\t\t</ButtonLink>\n\t\t\t\t\t\t\t{clickedVerificationLink ? (\n\t\t\t\t\t\t\t\t<div className=\"justify-center pt-5 text-center opacity-60\">\n\t\t\t\t\t\t\t\t\t<Loading className=\"justify-center\">\n\t\t\t\t\t\t\t\t\t\tWaiting for confirmation\n\t\t\t\t\t\t\t\t\t</Loading>\n\t\t\t\t\t\t\t\t\t<p className=\"pt-2\">\n\t\t\t\t\t\t\t\t\t\tPlease open{' '}\n\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\thref={userCodeInfo.url}\n\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tyour auth page\n\t\t\t\t\t\t\t\t\t\t</a>{' '}\n\t\t\t\t\t\t\t\t\t\tin a new tab to continue.\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"flex flex-col items-center gap-8\">\n\t\t\t\t\t\t\t<div className=\"flex max-w-lg flex-col gap-3 pt-3 text-base text-gray-700 dark:text-gray-300\">\n\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\tIf you have access to this workshop on {displayName}, you'll\n\t\t\t\t\t\t\t\t\tbe able to watch videos, track progress, run tests, view the\n\t\t\t\t\t\t\t\t\tdiffs, and more!\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\tFirst you need to authenticate your device by requesting an\n\t\t\t\t\t\t\t\t\taccess code and verifying on {displayName}.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<loginFetcher.Form method=\"POST\">\n\t\t\t\t\t\t\t\t<Button varient=\"primary\" type=\"submit\">\n\t\t\t\t\t\t\t\t\t{loginFetcher.state === 'idle' &&\n\t\t\t\t\t\t\t\t\tloginFetcher.data?.status !== 'pending'\n\t\t\t\t\t\t\t\t\t\t? `Retrieve Auth Code`\n\t\t\t\t\t\t\t\t\t\t: `Retrieving Auth Code...`}\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</loginFetcher.Form>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{authError ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<div className=\"mt-4 text-red-500\">\n\t\t\t\t\t\t\t\tThere was an error: <pre>{authError}</pre>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"mt-4 text-red-500\">\n\t\t\t\t\t\t\t\tPlease try again or{' '}\n\t\t\t\t\t\t\t\t<Link to=\"/support\" className=\"underline\">\n\t\t\t\t\t\t\t\t\tcontact support\n\t\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\t\tif the problem persists.\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n","import {\n\tgetPreferences,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { Form, useNavigation } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst preferences = await getPreferences()\n\treturn { preferences }\n}\n\nexport async function action({ request }: { request: Request }) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\n\tconst minResolution = formData.get('minResolution')\n\tconst maxResolution = formData.get('maxResolution')\n\tconst fontSize = formData.get('fontSize')\n\tconst optOutPresence = formData.get('optOutPresence') === 'on'\n\tconst persistPlayground = formData.get('persistPlayground') === 'on'\n\tconst dismissExerciseWarning = formData.get('dismissExerciseWarning') === 'on'\n\n\tawait setPreferences({\n\t\tplayer: {\n\t\t\tminResolution: minResolution ? Number(minResolution) : undefined,\n\t\t\tmaxResolution: maxResolution ? Number(maxResolution) : undefined,\n\t\t},\n\t\tfontSize: fontSize ? Number(fontSize) : undefined,\n\t\tpresence: { optOut: optOutPresence },\n\t\tplayground: { persist: persistPlayground },\n\t\texerciseWarning: { dismissed: dismissExerciseWarning },\n\t})\n\n\treturn redirectWithToast('/preferences', {\n\t\ttitle: 'Preferences updated',\n\t\tdescription: 'Your preferences have been updated.',\n\t\ttype: 'success',\n\t})\n}\n\nexport default function AccountSettings() {\n\tconst rootData = useRootLoaderData()\n\tconst playerPreferences = rootData.preferences?.player\n\tconst fontSizePreference = rootData.preferences?.fontSize\n\tconst presencePreferences = rootData.preferences?.presence\n\tconst playgroundPreferences = rootData.preferences?.playground\n\tconst exerciseWarningPreferences = rootData.preferences?.exerciseWarning\n\tconst navigation = useNavigation()\n\n\tconst isSubmitting = navigation.state === 'submitting'\n\n\treturn (\n\t\t<div className=\"h-full w-full overflow-y-auto\">\n\t\t\t<main className=\"container mt-12 flex w-full max-w-3xl grow flex-col gap-4 pb-24\">\n\t\t\t\t<h1 className=\"text-h1 mb-4\">Preferences</h1>\n\t\t\t\t<Form method=\"post\" className=\"flex w-full max-w-sm flex-col gap-4\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"text-body-xl mb-2\">Video Player Preferences</h2>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"minResolution\">Minimum Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"minResolution\"\n\t\t\t\t\t\t\t\tname=\"minResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={playerPreferences?.minResolution}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Auto</option>\n\t\t\t\t\t\t\t\t<option value=\"480\">480p</option>\n\t\t\t\t\t\t\t\t<option value=\"720\">720p</option>\n\t\t\t\t\t\t\t\t<option value=\"1080\">1080p</option>\n\t\t\t\t\t\t\t\t<option value=\"1440\">1440p</option>\n\t\t\t\t\t\t\t\t<option value=\"2160\">2160p (4K)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"maxResolution\">Maximum Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"maxResolution\"\n\t\t\t\t\t\t\t\tname=\"maxResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={playerPreferences?.maxResolution}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Auto</option>\n\t\t\t\t\t\t\t\t<option value=\"720\">720p</option>\n\t\t\t\t\t\t\t\t<option value=\"1080\">1080p</option>\n\t\t\t\t\t\t\t\t<option value=\"1440\">1440p</option>\n\t\t\t\t\t\t\t\t<option value=\"2160\">2160p (4K)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Font Size Preference</h2>\n\t\t\t\t\t\t\t<SimpleTooltip content=\"Defaults to 16px\">\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"fontSize\">Font Size</label>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\tid=\"fontSize\"\n\t\t\t\t\t\t\t\tname=\"fontSize\"\n\t\t\t\t\t\t\t\tdefaultValue={fontSizePreference ?? 16}\n\t\t\t\t\t\t\t\tstep=\"1\"\n\t\t\t\t\t\t\t\tmin=\"12\"\n\t\t\t\t\t\t\t\tmax=\"26\"\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Presence Preference</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip content=\"This controls whether your name and avatar are displayed in the pile of faces in navigation\">\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"optOutPresence\"\n\t\t\t\t\t\t\t\tname=\"optOutPresence\"\n\t\t\t\t\t\t\t\tdefaultChecked={presencePreferences?.optOut}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"optOutPresence\">\n\t\t\t\t\t\t\t\tOpt out of presence features\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Persist Playground</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\t\tcontent={`When enabled, clicking \"Set to Playground\" will save the current playground in the \"saved-playgrounds\" directory.`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"persistPlayground\"\n\t\t\t\t\t\t\t\tname=\"persistPlayground\"\n\t\t\t\t\t\t\t\tdefaultChecked={playgroundPreferences?.persist}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"persistPlayground\">\n\t\t\t\t\t\t\t\tEnable saving playground\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Exercise Directory Warning</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\t\tcontent={`When enabled, you'll see a warning banner when you have changes in the exercises directory. This helps remind you to work in the playground directory instead.`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"dismissExerciseWarning\"\n\t\t\t\t\t\t\t\tname=\"dismissExerciseWarning\"\n\t\t\t\t\t\t\t\tdefaultChecked={exerciseWarningPreferences?.dismissed}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"dismissExerciseWarning\">\n\t\t\t\t\t\t\t\tDismiss exercise directory warnings\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"h-4\" />\n\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\tvalue=\"update-preferences\"\n\t\t\t\t\t\tdisabled={isSubmitting}\n\t\t\t\t\t>\n\t\t\t\t\t\t{isSubmitting ? 'Updating...' : 'Update Preferences'}\n\t\t\t\t\t</Button>\n\t\t\t\t</Form>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n","import { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { Link } from 'react-router'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport default function Support() {\n\tconst repoGroups = ENV.EPICSHOP_GITHUB_REPO.match(\n\t\t/github\\.com\\/(?<org>[^/?]+)\\/(?<repo>[^/?]+)/,\n\t)?.groups\n\n\tlet repoUrl = ENV.EPICSHOP_GITHUB_REPO\n\tlet repoIssuesUrl = repoUrl\n\tif (repoGroups?.org && repoGroups.repo) {\n\t\trepoUrl = `https://github.com/${repoGroups.org}/${repoGroups.repo}`\n\t\trepoIssuesUrl = `${repoUrl}/issues`\n\t}\n\treturn (\n\t\t<div className=\"container flex h-full max-w-3xl flex-col items-center justify-center gap-4 p-12\">\n\t\t\t<h1 className=\"text-5xl font-bold\">Support</h1>\n\t\t\t<p>\n\t\t\t\tWe're here to support you! Depending on the kind of support you need,\n\t\t\t\tyou will want to reach out in different places:\n\t\t\t</p>\n\t\t\t<ul className=\"flex list-disc flex-col gap-4\">\n\t\t\t\t<li>\n\t\t\t\t\t<strong>Technical issues:</strong>{' '}\n\t\t\t\t\t<a href=\"mailto:team@epicweb.dev\" className=\"underline\">\n\t\t\t\t\t\tteam@epicweb.dev\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\t– Helpful if you're having trouble with or have feedback for your\n\t\t\t\t\tEpicWeb.dev account or access to course content.\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<strong>Workshop App:</strong>{' '}\n\t\t\t\t\t<a\n\t\t\t\t\t\thref=\"https://github.com/epicweb-dev/epicshop/issues\"\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\tgithub.com/epicweb-dev/epicshop\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\t– Helpful if you're having trouble with or feedback for the local\n\t\t\t\t\tworkshop app.\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<strong>Workshop content:</strong>{' '}\n\t\t\t\t\t<a href={repoIssuesUrl} className=\"underline\">\n\t\t\t\t\t\t{repoUrl.replace('https://', '')}\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\t– Open an issue or pull request here to report an issue with the\n\t\t\t\t\tcontent of this workshop.\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<strong>Discord:</strong>{' '}\n\t\t\t\t\t<Link to=\"/discord\" className=\"underline\">\n\t\t\t\t\t\t/discord\n\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t– Connect your account with discord to get access to the private forum\n\t\t\t\t\tand ask questions of other students and the workshop instructor.\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\t)\n}\n","import {\n\tgetPreferences,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { Form, useLoaderData, useNavigation } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst preferences = await getPreferences()\n\treturn { preferences }\n}\n\nexport async function action({ request }: { request: Request }) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst dismissed = formData.get('dismissWarning') === 'on'\n\n\tawait setPreferences({\n\t\texerciseWarning: { dismissed },\n\t})\n\n\treturn redirectWithToast('/workspace-structure', {\n\t\ttitle: 'Preferences updated',\n\t\tdescription:\n\t\t\t'Your workspace structure warning preference has been updated.',\n\t\ttype: 'success',\n\t})\n}\n\nexport default function WorkspaceStructure() {\n\tconst { preferences } = useLoaderData<typeof loader>()\n\tconst navigation = useNavigation()\n\tconst isSubmitting = navigation.state === 'submitting'\n\n\treturn (\n\t\t<div className=\"h-full w-full overflow-y-auto\">\n\t\t\t<main className=\"container mt-12 flex w-full max-w-4xl grow flex-col gap-6 pb-24\">\n\t\t\t\t<h1 className=\"text-h1\">Workshop Structure & Guidelines</h1>\n\n\t\t\t\t<div className=\"border-destructive bg-destructive/10 rounded-lg border p-4\">\n\t\t\t\t\t<h2 className=\"text-destructive mb-2 text-lg font-semibold\">\n\t\t\t\t\t\t⚠️ Important: Work in the Right Directory\n\t\t\t\t\t</h2>\n\t\t\t\t\t<p className=\"text-destructive text-sm\">\n\t\t\t\t\t\t<strong>\n\t\t\t\t\t\t\tAlways work in the `playground` directory, not the `exercises`\n\t\t\t\t\t\t\tdirectory.\n\t\t\t\t\t\t</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p className=\"text-destructive mt-2 text-sm\">\n\t\t\t\t\t\tTo <strong>make this warning go away</strong>, either:\n\t\t\t\t\t\t<ol className=\"list-decimal pl-4\">\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t{`Undo your changes in the exercises directory with: `}\n\t\t\t\t\t\t\t\t<code className=\"bg-background rounded px-1 py-0.5 text-xs\">\n\t\t\t\t\t\t\t\t\tgit checkout exercises/\n\t\t\t\t\t\t\t\t</code>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\tRead below and check the box once you understand how this is\n\t\t\t\t\t\t\t\tsupposed to work.\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ol>\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"space-y-6\">\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<h2 className=\"text-h2 mb-3\">Directory Structure</h2>\n\t\t\t\t\t\t<div className=\"space-y-4\">\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">📁 exercises/</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t<strong>Templates only.</strong> These are the original\n\t\t\t\t\t\t\t\t\texercise files that serve as the starting point for each step.\n\t\t\t\t\t\t\t\t\t<strong className=\"text-destructive\">\n\t\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t\tDo not edit these files\n\t\t\t\t\t\t\t\t\t</strong>{' '}\n\t\t\t\t\t\t\t\t\tunless you're contributing to the workshop or are the\n\t\t\t\t\t\t\t\t\tinstructor building the content.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">🏗️ playground/</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t<strong>Your workspace.</strong> This is where you practice\n\t\t\t\t\t\t\t\t\tand develop your skills.\n\t\t\t\t\t\t\t\t\t<strong className=\"text-primary\"> Always work here</strong> to\n\t\t\t\t\t\t\t\t\tcomplete exercises and experiment with the code.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</section>\n\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<h2 className=\"text-h2 mb-3\">Workshop UI Tabs</h2>\n\t\t\t\t\t\t<div className=\"space-y-4\">\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">\n\t\t\t\t\t\t\t\t\t🏗️ Playground Tab\n\t\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tShows the <strong>current state of your playground</strong> -\n\t\t\t\t\t\t\t\t\tthis is your work in progress.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">📋 Problem Tab</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tShows the <strong>current state of the problem</strong> -\n\t\t\t\t\t\t\t\t\tuseful for referencing where you started in this exercise\n\t\t\t\t\t\t\t\t\tstep.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t\t<h3 className=\"mb-2 text-lg font-semibold\">✅ Solution Tab</h3>\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tShows the <strong>current state of the solution</strong> -\n\t\t\t\t\t\t\t\t\tuseful for checking how things should work when you're\n\t\t\t\t\t\t\t\t\tfinished and comparing to your own solution.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</section>\n\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<h2 className=\"text-h2 mb-3\">Exceptions to the Rule</h2>\n\t\t\t\t\t\t<div className=\"border-border bg-muted rounded-lg border p-4\">\n\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\tThe only times you should modify files in the{' '}\n\t\t\t\t\t\t\t\t<code className=\"bg-background rounded px-1 py-0.5 text-xs\">\n\t\t\t\t\t\t\t\t\texercises/\n\t\t\t\t\t\t\t\t</code>{' '}\n\t\t\t\t\t\t\t\tdirectory are:\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t<ul className=\"text-muted-foreground mt-2 space-y-1 text-sm\">\n\t\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t\t• <strong>You're the instructor</strong> building or\n\t\t\t\t\t\t\t\t\tmaintaining the workshop content\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t\t• <strong>You're contributing</strong> to the workshop source\n\t\t\t\t\t\t\t\t\tcode (bug fixes, improvements, etc.)\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</section>\n\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<h2 className=\"text-h2 mb-3\">Need a Refresher?</h2>\n\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\tFor a complete overview of the typical workflow, review the\n\t\t\t\t\t\t\tintroductory material for this workshop.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</section>\n\n\t\t\t\t\t<hr />\n\n\t\t\t\t\t<section>\n\t\t\t\t\t\t<div className=\"border-destructive bg-destructive/10 rounded-lg border p-4\">\n\t\t\t\t\t\t\t<h2 className=\"text-destructive mb-2 text-lg font-semibold\">\n\t\t\t\t\t\t\t\tMake this warning go away\n\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t<Form method=\"post\" className=\"space-y-4\">\n\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\t\t\tid=\"dismissWarning\"\n\t\t\t\t\t\t\t\t\t\tname=\"dismissWarning\"\n\t\t\t\t\t\t\t\t\t\tdefaultChecked={preferences?.exerciseWarning?.dismissed}\n\t\t\t\t\t\t\t\t\t\tclassName=\"border-border rounded\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<label htmlFor=\"dismissWarning\" className=\"text-sm\">\n\t\t\t\t\t\t\t\t\t\tI understand this and do not need further warnings about\n\t\t\t\t\t\t\t\t\t\tediting the exercises directory\n\t\t\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<Button type=\"submit\" varient=\"primary\" disabled={isSubmitting}>\n\t\t\t\t\t\t\t\t\t{isSubmitting ? 'Saving...' : 'Save Preference'}\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</section>\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n","import { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { Link, Outlet } from 'react-router'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { type Route } from './+types/_layout.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\treturn [{ title: `👷 | ${rootData?.workshopTitle}` }]\n}\n\nexport default function AdminLayout() {\n\treturn (\n\t\t<main className=\"container mx-auto mt-8\">\n\t\t\t<h1 className=\"text-4xl font-bold\">Admin</h1>\n\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t<nav>\n\t\t\t\t\t<ul className=\"flex gap-3\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/\">\n\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/admin\">\n\t\t\t\t\t\t\t\tAdmin\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/diff\">\n\t\t\t\t\t\t\t\tDiff Viewer\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"db\">\n\t\t\t\t\t\t\t\tDatabase\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"cache\">\n\t\t\t\t\t\t\t\tCache Management\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"version\">\n\t\t\t\t\t\t\t\tVersion\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</nav>\n\t\t\t\t<Outlet />\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n","import { getApps } from '@epic-web/workshop-utils/apps.server'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst apps = await getApps()\n\treturn Response.json({ apps })\n}\n","import {\n\tdeleteCacheEntry,\n\tdeleteWorkshopCache,\n\tgetAllWorkshopCaches,\n\tgetGlobalCaches,\n\tglobalCacheDirectoryExists,\n\tupdateCacheEntry,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getEnv } from '@epic-web/workshop-utils/env.server'\nimport { getErrorMessage } from '@epic-web/workshop-utils/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { href, useFetcher, useSearchParams } from 'react-router'\nimport { ClientOnly } from 'remix-utils/client-only'\nimport { z } from 'zod'\nimport {\n\tButton,\n\tIconButton,\n\ticonButtonClassName,\n} from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport {\n\tcalculateExpirationTime,\n\tcn,\n\tensureUndeployed,\n\tformatDuration,\n\tformatFileSize,\n\tformatTimeRemaining,\n\tuseDayjs,\n\tuseDoubleCheck,\n\tuseInterval,\n} from '#app/utils/misc.tsx'\nimport { type Route } from './+types/cache.ts'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tensureUndeployed()\n\tconst currentWorkshopId = getEnv().EPICSHOP_WORKSHOP_INSTANCE_ID\n\tconst allWorkshopCaches = await getAllWorkshopCaches()\n\tconst globalCaches = await getGlobalCaches()\n\tconst allCaches = [...allWorkshopCaches, ...globalCaches]\n\n\tconst url = new URL(request.url)\n\tconst filterQuery = url.searchParams.get('q') || ''\n\n\t// Ensure 'global' is always in available workshops if global cache directory exists\n\tconst availableWorkshopIds = new Set(allCaches.map((w) => w.workshopId))\n\tconst globalDirExists = await globalCacheDirectoryExists()\n\tif (globalDirExists) {\n\t\tavailableWorkshopIds.add('global')\n\t}\n\n\tconst selectedWorkshops = url.searchParams\n\t\t.get('workshops')\n\t\t?.split(',')\n\t\t.filter(Boolean) || [\n\t\tcurrentWorkshopId,\n\t\t...(globalDirExists ? ['global'] : []),\n\t]\n\n\t// Filter caches based on search query and selected workshops\n\tconst filteredCaches = allCaches\n\t\t.filter(\n\t\t\t(workshopCache) =>\n\t\t\t\tselectedWorkshops.includes(workshopCache.workshopId) ||\n\t\t\t\tselectedWorkshops.length === 0,\n\t\t)\n\t\t.map((workshopCache) => ({\n\t\t\t...workshopCache,\n\t\t\tcaches: workshopCache.caches\n\t\t\t\t.map((cache) => ({\n\t\t\t\t\t...cache,\n\t\t\t\t\tentries: cache.entries.filter(\n\t\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t\tfilterQuery === '' ||\n\t\t\t\t\t\t\tentry.key.toLowerCase().includes(filterQuery.toLowerCase()) ||\n\t\t\t\t\t\t\tcache.name.toLowerCase().includes(filterQuery.toLowerCase()),\n\t\t\t\t\t),\n\t\t\t\t}))\n\t\t\t\t.filter((cache) => cache.entries.length > 0 || filterQuery === ''),\n\t\t}))\n\t\t.filter(\n\t\t\t(workshopCache) => workshopCache.caches.length > 0 || filterQuery === '',\n\t\t)\n\n\treturn {\n\t\tcurrentWorkshopId,\n\t\tallWorkshopCaches: allCaches,\n\t\tfilteredCaches,\n\t\tfilterQuery,\n\t\tselectedWorkshops,\n\t\tavailableWorkshops: Array.from(availableWorkshopIds),\n\t}\n}\n\nconst ActionSchema = z.discriminatedUnion('intent', [\n\tz.object({\n\t\tintent: z.literal('delete-entry'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t\tfilename: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('delete-cache'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('delete-workshop-cache'),\n\t\tworkshopId: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('update-entry'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t\tfilename: z.string(),\n\t\tnewValue: z.string(),\n\t}),\n])\n\nexport async function action({ request }: Route.ActionArgs) {\n\tensureUndeployed()\n\n\tconst formData = await request.formData()\n\tconst rawData = Object.fromEntries(formData.entries())\n\tconst result = ActionSchema.safeParse(rawData)\n\n\tif (!result.success) {\n\t\treturn { status: 'error', error: 'Invalid request' } as const\n\t}\n\n\tconst data = result.data\n\n\ttry {\n\t\tswitch (data.intent) {\n\t\t\tcase 'delete-entry': {\n\t\t\t\tconst path = `${data.workshopId}/${data.cacheName}/${data.filename}`\n\t\t\t\tawait deleteCacheEntry(path)\n\t\t\t\treturn { status: 'success', message: 'Cache entry deleted' } as const\n\t\t\t}\n\t\t\tcase 'delete-cache': {\n\t\t\t\tawait deleteWorkshopCache(data.workshopId, data.cacheName)\n\t\t\t\treturn { status: 'success', message: 'Cache deleted' } as const\n\t\t\t}\n\t\t\tcase 'delete-workshop-cache': {\n\t\t\t\tawait deleteWorkshopCache(data.workshopId)\n\t\t\t\treturn { status: 'success', message: 'Workshop cache deleted' } as const\n\t\t\t}\n\t\t\tcase 'update-entry': {\n\t\t\t\tconst path = `${data.workshopId}/${data.cacheName}/${data.filename}`\n\t\t\t\ttry {\n\t\t\t\t\tconst parsedValue = JSON.parse(data.newValue)\n\t\t\t\t\tawait updateCacheEntry(path, parsedValue)\n\t\t\t\t\treturn { status: 'success', message: 'Cache entry updated' } as const\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\terror: getErrorMessage(error, 'Invalid JSON value'),\n\t\t\t\t\t} as const\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconsole.error('Cache action error:', error)\n\t\treturn { status: 'error', error: 'Operation failed' } as const\n\t}\n}\n\nfunction WorkshopChooser({\n\tselectedWorkshops,\n\tavailableWorkshops,\n\tcurrentWorkshopId,\n}: {\n\tselectedWorkshops: string[]\n\tavailableWorkshops: string[]\n\tcurrentWorkshopId: string\n}) {\n\tconst [searchParams, setSearchParams] = useSearchParams()\n\n\tconst handleWorkshopChange = (workshop: string, checked: boolean) => {\n\t\tconst newSelected = checked\n\t\t\t? [...selectedWorkshops, workshop]\n\t\t\t: selectedWorkshops.filter((w) => w !== workshop)\n\n\t\tconst params = new URLSearchParams(searchParams)\n\t\tif (newSelected.length > 0) {\n\t\t\tparams.set('workshops', newSelected.join(','))\n\t\t} else {\n\t\t\tparams.delete('workshops')\n\t\t}\n\t\tsetSearchParams(params)\n\t}\n\n\treturn (\n\t\t<div className=\"mb-6\">\n\t\t\t<h3 className=\"mb-3 text-lg font-semibold\">Workshop Filter</h3>\n\t\t\t<div className=\"flex flex-wrap gap-3\">\n\t\t\t\t{availableWorkshops.map((workshop) => (\n\t\t\t\t\t<label key={workshop} className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tchecked={selectedWorkshops.includes(workshop)}\n\t\t\t\t\t\t\tonChange={(e) => handleWorkshopChange(workshop, e.target.checked)}\n\t\t\t\t\t\t\tclassName=\"rounded\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclassName={`text-sm ${workshop === currentWorkshopId ? 'text-primary font-bold' : ''}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{workshop} {workshop === currentWorkshopId ? '(current)' : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction SearchFilter({ filterQuery }: { filterQuery: string }) {\n\tconst [searchParams, setSearchParams] = useSearchParams()\n\tconst [inputValue, setInputValue] = useState(filterQuery)\n\tconst inputRef = useRef<HTMLInputElement>(null)\n\n\t// Update input value when filterQuery changes (e.g., from URL)\n\tuseEffect(() => {\n\t\tsetInputValue(filterQuery)\n\t}, [filterQuery])\n\n\tconst handleSearch = (query: string) => {\n\t\tconst params = new URLSearchParams(searchParams)\n\t\tif (query) {\n\t\t\tparams.set('q', query)\n\t\t} else {\n\t\t\tparams.delete('q')\n\t\t}\n\t\tsetSearchParams(params)\n\t}\n\n\tconst handleClear = () => {\n\t\tsetInputValue('')\n\t\thandleSearch('')\n\t\tinputRef.current?.focus()\n\t}\n\n\treturn (\n\t\t<div className=\"mb-6\">\n\t\t\t<h3 className=\"mb-3 text-lg font-semibold\">Search Cache Entries</h3>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t<input\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tplaceholder=\"Search by key or cache name...\"\n\t\t\t\t\tvalue={inputValue}\n\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\tsetInputValue(e.target.value)\n\t\t\t\t\t\thandleSearch(e.target.value)\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"border-border bg-background text-foreground focus:ring-ring flex-1 rounded-md border px-3 py-2 focus:ring-2 focus:outline-none\"\n\t\t\t\t/>\n\t\t\t\t{inputValue ? (\n\t\t\t\t\t<IconButton onClick={handleClear} title=\"Clear search\">\n\t\t\t\t\t\t<Icon name=\"Close\" className=\"h-4 w-4\" />\n\t\t\t\t\t</IconButton>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Inline entry editor component\nfunction InlineEntryEditor({\n\tworkshopId,\n\tcacheName,\n\tfilename,\n\tcurrentValue,\n\tentryKey,\n}: {\n\tworkshopId: string\n\tcacheName: string\n\tfilename: string\n\tcurrentValue: any\n\tentryKey: string\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst [editValue, setEditValue] = useState(\n\t\tJSON.stringify(currentValue, null, 2),\n\t)\n\tconst [hasChanges, setHasChanges] = useState(false)\n\n\tconst handleSave = () => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'update-entry',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t\tfilename,\n\t\t\t\tnewValue: editValue,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t\tsetHasChanges(false)\n\t}\n\n\tconst handleChange = (value: string) => {\n\t\tsetEditValue(value)\n\t\tsetHasChanges(value !== JSON.stringify(currentValue, null, 2))\n\t}\n\n\tconst handleReset = () => {\n\t\tsetEditValue(JSON.stringify(currentValue, null, 2))\n\t\tsetHasChanges(false)\n\t}\n\n\treturn (\n\t\t<details className=\"mt-2\">\n\t\t\t<summary className=\"text-muted-foreground hover:text-foreground cursor-pointer text-sm\">\n\t\t\t\tEdit entry details\n\t\t\t</summary>\n\t\t\t<div className=\"border-border bg-muted mt-2 space-y-3 rounded border p-3\">\n\t\t\t\t<div>\n\t\t\t\t\t<label className=\"mb-1 block text-sm font-medium\">Key:</label>\n\t\t\t\t\t<code className=\"bg-background rounded border px-2 py-1 text-sm\">\n\t\t\t\t\t\t{entryKey}\n\t\t\t\t\t</code>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<label className=\"mb-1 block text-sm font-medium\">Value:</label>\n\t\t\t\t\t<textarea\n\t\t\t\t\t\tvalue={editValue}\n\t\t\t\t\t\tonChange={(e) => handleChange(e.target.value)}\n\t\t\t\t\t\tclassName=\"resize-vertical border-border bg-background text-foreground focus:ring-ring h-32 w-full rounded border p-2 font-mono text-sm focus:ring-2 focus:outline-none\"\n\t\t\t\t\t\tplaceholder=\"Enter JSON value...\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\tonClick={handleSave}\n\t\t\t\t\t\tdisabled={!hasChanges || fetcher.state !== 'idle'}\n\t\t\t\t\t>\n\t\t\t\t\t\t{fetcher.state !== 'idle' ? 'Saving...' : 'Save'}\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button varient=\"mono\" onClick={handleReset} disabled={!hasChanges}>\n\t\t\t\t\t\tReset\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</details>\n\t)\n}\n\nfunction SkippedFilesSection({\n\tskippedFiles,\n\tworkshopId,\n\tcacheName,\n}: {\n\tskippedFiles: Array<{\n\t\tfilename: string\n\t\terror: string\n\t\tsize: number\n\t\tskipped: true\n\t}>\n\tworkshopId: string\n\tcacheName: string\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\n\tif (skippedFiles.length === 0) return null\n\n\treturn (\n\t\t<div className=\"border-warning bg-warning mt-4 rounded border p-3\">\n\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t<Icon\n\t\t\t\t\tname=\"TriangleAlert\"\n\t\t\t\t\tclassName=\"text-warning-foreground h-4 w-4\"\n\t\t\t\t/>\n\t\t\t\t<h5 className=\"text-warning-foreground font-medium\">\n\t\t\t\t\tSkipped Files ({skippedFiles.length})\n\t\t\t\t</h5>\n\t\t\t</div>\n\t\t\t<p className=\"text-warning-foreground/80 mb-3 text-sm\">\n\t\t\t\tThese cache files were skipped because they exceed the 3MB size limit:\n\t\t\t</p>\n\t\t\t<div className=\"space-y-2\">\n\t\t\t\t{skippedFiles.map((skippedFile) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={skippedFile.filename}\n\t\t\t\t\t\tclassName=\"border-warning/20 bg-warning/5 flex items-center justify-between rounded border p-2\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t<div className=\"text-warning-foreground truncate font-mono text-sm font-medium\">\n\t\t\t\t\t\t\t\t{skippedFile.filename}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"text-warning-foreground/70 text-xs\">\n\t\t\t\t\t\t\t\t{skippedFile.error} • Size:{' '}\n\t\t\t\t\t\t\t\t<span title={`${skippedFile.size} bytes`}>\n\t\t\t\t\t\t\t\t\t{formatFileSize(skippedFile.size)}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"ml-2 flex shrink-0\">\n\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\tonConfirm={() => {\n\t\t\t\t\t\t\t\t\tvoid fetcher.submit(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tintent: 'delete-entry',\n\t\t\t\t\t\t\t\t\t\t\tworkshopId,\n\t\t\t\t\t\t\t\t\t\t\tcacheName,\n\t\t\t\t\t\t\t\t\t\t\tfilename: skippedFile.filename,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{ method: 'POST' },\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\ttitle=\"Delete large cache file\"\n\t\t\t\t\t\t\t\tclassName=\"text-destructive-foreground hover:bg-destructive/20 hover:text-destructive-foreground\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nexport default function CacheManagement({ loaderData }: Route.ComponentProps) {\n\tconst fetcher = useFetcher<typeof action>()\n\n\tconst deleteEntry = (\n\t\tworkshopId: string,\n\t\tcacheName: string,\n\t\tfilename: string,\n\t) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-entry',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t\tfilename,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst deleteCache = (workshopId: string, cacheName: string) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-cache',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst deleteWorkshopCache = (workshopId: string) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-workshop-cache',\n\t\t\t\tworkshopId,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst {\n\t\tcurrentWorkshopId,\n\t\tfilteredCaches,\n\t\tfilterQuery,\n\t\tselectedWorkshops,\n\t\tavailableWorkshops,\n\t} = loaderData\n\n\treturn (\n\t\t<div className=\"space-y-6\">\n\t\t\t<div>\n\t\t\t\t<h2 className=\"mb-2 text-2xl font-bold\">Cache Management</h2>\n\t\t\t\t<p className=\"text-muted-foreground\">\n\t\t\t\t\tCurrent Workshop:{' '}\n\t\t\t\t\t<span className=\"text-foreground font-semibold\">\n\t\t\t\t\t\t{currentWorkshopId}\n\t\t\t\t\t</span>\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<WorkshopChooser\n\t\t\t\tselectedWorkshops={selectedWorkshops}\n\t\t\t\tavailableWorkshops={availableWorkshops}\n\t\t\t\tcurrentWorkshopId={currentWorkshopId}\n\t\t\t/>\n\n\t\t\t<SearchFilter filterQuery={filterQuery} />\n\n\t\t\t{fetcher.data?.status === 'success' ? (\n\t\t\t\t<div className=\"border-border bg-success text-success-foreground rounded border p-4\">\n\t\t\t\t\t{fetcher.data.message}\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{fetcher.data?.status === 'error' ? (\n\t\t\t\t<div className=\"border-border bg-destructive text-destructive-foreground rounded border p-4\">\n\t\t\t\t\t{fetcher.data.error}\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{filteredCaches.length === 0 ? (\n\t\t\t\t<div className=\"text-muted-foreground py-8 text-center\">\n\t\t\t\t\tNo caches found matching your criteria.\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t<div className=\"space-y-6\">\n\t\t\t\t{filteredCaches.map((workshopCache) => (\n\t\t\t\t\t<details\n\t\t\t\t\t\tkey={workshopCache.workshopId}\n\t\t\t\t\t\topen={workshopCache.workshopId === currentWorkshopId}\n\t\t\t\t\t>\n\t\t\t\t\t\t<summary className=\"border-border bg-card hover:bg-accent cursor-pointer rounded-lg border p-4\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t\t<h3 className=\"text-card-foreground flex items-center gap-2 text-lg font-semibold\">\n\t\t\t\t\t\t\t\t\t<Icon name=\"Files\" className=\"h-5 w-5\" />\n\t\t\t\t\t\t\t\t\t{workshopCache.workshopId === 'global'\n\t\t\t\t\t\t\t\t\t\t? 'Global Caches'\n\t\t\t\t\t\t\t\t\t\t: workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t{workshopCache.workshopId === currentWorkshopId ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"bg-primary text-primary-foreground rounded px-2 py-1 text-xs\">\n\t\t\t\t\t\t\t\t\t\t\tCurrent\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\tdeleteWorkshopCache(workshopCache.workshopId)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\ttitle=\"Delete all workshop caches\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</summary>\n\n\t\t\t\t\t\t<div className=\"mt-4 space-y-4 pl-4\">\n\t\t\t\t\t\t\t{workshopCache.caches.map((cache) => {\n\t\t\t\t\t\t\t\tconst totalSize = cache.entries.reduce(\n\t\t\t\t\t\t\t\t\t(sum, entry) => sum + (entry.size || 0),\n\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst skippedSize = (cache.skippedFiles || []).reduce(\n\t\t\t\t\t\t\t\t\t(sum, file) => sum + file.size,\n\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst grandTotal = totalSize + skippedSize\n\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<details key={cache.name} className=\"bg-muted rounded-md\">\n\t\t\t\t\t\t\t\t\t\t<summary className=\"hover:bg-accent cursor-pointer p-3\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t\t\t\t\t\t<h4 className=\"text-muted-foreground flex items-center gap-2 font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Files\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t{cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t({cache.entries.length} entr\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{cache.entries.length === 1 ? 'y' : 'ies'})\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{grandTotal > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t•{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span title={`${grandTotal} bytes`}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(grandTotal)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttotal\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{skippedSize > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-warning\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span title={`${skippedSize} bytes`}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(skippedSize)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tskipped)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t</h4>\n\t\t\t\t\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdeleteCache(workshopCache.workshopId, cache.name)\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Delete cache\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</summary>\n\n\t\t\t\t\t\t\t\t\t\t<div className=\"p-3 pt-0\">\n\t\t\t\t\t\t\t\t\t\t\t{cache.entries.length === 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\tNo entries match your search.\n\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t\t\t\t{cache.skippedFiles && cache.skippedFiles.length > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<SkippedFilesSection\n\t\t\t\t\t\t\t\t\t\t\t\t\tskippedFiles={cache.skippedFiles}\n\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopId={workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t\t\t\t\tcacheName={cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t\t\t\t\t\t{cache.entries.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\t({ key, entry, filename, size, filepath }) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-background rounded border p-3\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-start justify-between\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mb-1 flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"truncate font-mono text-sm font-medium\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{size ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"bg-muted text-muted-foreground inline-flex items-center rounded px-1.5 py-0.5 text-xs whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle={`${size} bytes`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(size)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<CacheMetadata metadata={entry.metadata} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"ml-4 flex shrink-0 gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thref={href('/admin/cache/*', {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'*': `${workshopCache.workshopId}/${cache.name}/${filename}`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground hover:bg-muted focus:ring-ring inline-flex h-8 w-8 items-center justify-center rounded border focus:ring-2 focus:outline-none\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"View JSON\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"ExternalLink\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{filepath ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfile={filepath}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={iconButtonClassName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"Files\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Open in editor\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdeleteEntry(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopCache.workshopId,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcache.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfilename,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Delete entry\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<InlineEntryEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopId={workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcacheName={cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfilename={filename}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcurrentValue={entry.value}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tentryKey={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</details>\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</details>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Component for displaying cache metadata with live countdown\nfunction CacheMetadata({\n\tmetadata,\n}: {\n\tmetadata: {\n\t\tcreatedTime: number\n\t\tttl?: number | null\n\t\tswr?: number\n\t}\n}) {\n\tconst dayjs = useDayjs()\n\tconst [, setCurrentTime] = useState(Date.now())\n\tconst expirationTime = calculateExpirationTime(metadata)\n\n\t// Update time every second for live countdown\n\tuseInterval(() => {\n\t\tsetCurrentTime(Date.now())\n\t}, 1000)\n\n\tconst createdDate = dayjs(metadata.createdTime)\n\tconst timeRemaining = expirationTime\n\t\t? formatTimeRemaining(expirationTime)\n\t\t: { text: 'Never', isExpired: false, isExpiringSoon: false }\n\n\treturn (\n\t\t<div className=\"text-muted-foreground flex flex-col gap-1 text-xs\">\n\t\t\t<div>\n\t\t\t\tCreated: {createdDate.format('MMM D, YYYY HH:mm:ss')}{' '}\n\t\t\t\t<ClientOnly>{() => `(${createdDate.fromNow()})`}</ClientOnly>\n\t\t\t</div>\n\t\t\t<div className=\"flex flex-wrap items-center gap-3\">\n\t\t\t\t{metadata.ttl !== undefined && metadata.ttl !== null ? (\n\t\t\t\t\t<span>\n\t\t\t\t\t\tTTL:{' '}\n\t\t\t\t\t\t{metadata.ttl === Infinity ? (\n\t\t\t\t\t\t\t'Forever'\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<span title={`${metadata.ttl}ms`}>\n\t\t\t\t\t\t\t\t{formatDuration(metadata.ttl)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t{metadata.swr !== undefined ? (\n\t\t\t\t\t<span>\n\t\t\t\t\t\tSWR:{' '}\n\t\t\t\t\t\t<span title={`${metadata.swr}ms`}>\n\t\t\t\t\t\t\t{formatDuration(metadata.swr)}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t<div\n\t\t\t\t\tclassName={`inline-flex w-auto rounded-full px-2 py-[2px] font-medium ${\n\t\t\t\t\t\ttimeRemaining.isExpired\n\t\t\t\t\t\t\t? 'bg-destructive text-destructive-foreground'\n\t\t\t\t\t\t\t: timeRemaining.isExpiringSoon\n\t\t\t\t\t\t\t\t? 'bg-warning text-warning-foreground'\n\t\t\t\t\t\t\t\t: 'text-foreground'\n\t\t\t\t\t}`}\n\t\t\t\t>\n\t\t\t\t\t{expirationTime ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\tExpires: {dayjs(expirationTime).format('MMM D, YYYY HH:mm:ss')} (\n\t\t\t\t\t\t\t<span className=\"tabular-nums\">\n\t\t\t\t\t\t\t\t<ClientOnly>{() => timeRemaining.text}</ClientOnly>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'Expires: Never'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Double-check delete button\nfunction DoubleCheckButton({\n\tonConfirm,\n\tchildren,\n\tclassName,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'> & {\n\tonConfirm: () => void\n}) {\n\tconst doubleCheck = useDoubleCheck()\n\n\treturn (\n\t\t<IconButton\n\t\t\t{...doubleCheck.getButtonProps({\n\t\t\t\tonClick: doubleCheck.doubleCheck ? onConfirm : undefined,\n\t\t\t\t...props,\n\t\t\t})}\n\t\t\tclassName={cn(\n\t\t\t\tdoubleCheck.doubleCheck\n\t\t\t\t\t? 'bg-destructive text-destructive-foreground'\n\t\t\t\t\t: null,\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{doubleCheck.doubleCheck ? '✓' : children}\n\t\t</IconButton>\n\t)\n}\n","import { invariant } from '@epic-web/invariant'\nimport { readEntryByPath } from '@epic-web/workshop-utils/cache.server'\nimport { type Route } from './+types/cache.$.ts'\n\nexport async function loader({ params }: Route.LoaderArgs) {\n\tconst path = params['*']\n\tinvariant(path, 'Path is required')\n\tconst entry = await readEntryByPath(path)\n\treturn { path, entry }\n}\n","import { loadJSON } from '@epic-web/workshop-utils/data-storage.server'\nimport { readDb } from '@epic-web/workshop-utils/db.server'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { LaunchEditor } from '../launch-editor.tsx'\nimport { type Route } from './+types/db.ts'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst db = await readDb()\n\tconst { path: filepath } = await loadJSON()\n\n\treturn { db, filepath }\n}\n\nexport default function DbRoute({ loaderData }: Route.ComponentProps) {\n\tconst { db, filepath } = loaderData\n\treturn (\n\t\t<main>\n\t\t\t<h1 className=\"text-2xl font-bold\">Database</h1>\n\t\t\t<div className=\"prose mt-4\">\n\t\t\t\t<callout-danger>\n\t\t\t\t\t<strong>Warning:</strong> Editing the database directly can corrupt\n\t\t\t\t\tyour data. Be very careful!\n\t\t\t\t</callout-danger>\n\t\t\t</div>\n\t\t\t<LaunchEditor\n\t\t\t\tfile={filepath}\n\t\t\t\tclassName=\"flex max-w-full items-center gap-2\"\n\t\t\t>\n\t\t\t\t<SimpleTooltip content=\"Open the database file in your editor\">\n\t\t\t\t\t<Icon name=\"Files\" className=\"h-4 w-4\" title=\"Open in editor\" />\n\t\t\t\t</SimpleTooltip>\n\t\t\t\t<span className=\"truncate\" title={filepath}>\n\t\t\t\t\t{filepath}\n\t\t\t\t</span>\n\t\t\t</LaunchEditor>\n\t\t\t<pre className=\"mt-4 max-h-[400px] w-full overflow-auto rounded border bg-gray-900 p-4 text-sm text-white\">\n\t\t\t\t{JSON.stringify(db, null, 2)}\n\t\t\t</pre>\n\t\t</main>\n\t)\n}\n","import inspector from 'node:inspector'\nimport path from 'node:path'\nimport { getWorkshopRoot } from '@epic-web/workshop-utils/apps.server'\nimport { deleteCache } from '@epic-web/workshop-utils/cache.server'\nimport { deleteDb } from '@epic-web/workshop-utils/db.server'\nimport fsExtra from 'fs-extra'\n\nexport function isInspectorRunning(): boolean {\n\ttry {\n\t\treturn inspector.url() !== undefined\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport async function clearData() {\n\tif (ENV.EPICSHOP_DEPLOYED) return\n\tawait clearCaches()\n\tawait deleteDb()\n}\n\nexport async function clearCaches() {\n\tif (ENV.EPICSHOP_DEPLOYED) return\n\tawait fsExtra.remove(path.join(getWorkshopRoot(), 'node_modules', '.cache'))\n\tawait deleteCache()\n}\n\nexport async function startInspector() {\n\tif (ENV.EPICSHOP_DEPLOYED) return\n\tif (!isInspectorRunning()) {\n\t\tinspector.open()\n\t} else {\n\t\tconsole.info(`Inspector already running.`)\n\t}\n}\n\nexport async function stopInspector() {\n\tif (ENV.EPICSHOP_DEPLOYED) return\n\tif (isInspectorRunning()) {\n\t\tinspector.close()\n\t} else {\n\t\tconsole.info(`Inspector already stopped.`)\n\t}\n}\n","import { getApps } from '@epic-web/workshop-utils/apps.server'\nimport { getProcesses } from '@epic-web/workshop-utils/process-manager.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { clsx } from 'clsx'\nimport { data, Form, Link, useNavigation } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport {\n\tuseEpicProgress,\n\ttype SerializedProgress,\n} from '#app/routes/progress.tsx'\nimport { cn, ensureUndeployed, useDoubleCheck } from '#app/utils/misc.tsx'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { type Route } from './+types/index.tsx'\nimport {\n\tclearCaches,\n\tclearData,\n\tisInspectorRunning,\n\tstartInspector,\n\tstopInspector,\n} from './admin-utils.server.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\treturn [{ title: `👷 | ${rootData?.workshopTitle}` }]\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('adminLoader')\n\tconst apps = (await getApps({ request, timings })).filter(\n\t\t(a, i, ar) => ar.findIndex((b) => a.name === b.name) === i,\n\t)\n\tconst processes: Record<\n\t\tstring,\n\t\t{ port: number; pid?: number; color: string }\n\t> = {}\n\tconst testProcesses: Record<\n\t\tstring,\n\t\t{ pid?: number; exitCode?: number | null }\n\t> = {}\n\tfor (const [\n\t\tname,\n\t\t{ port, process, color },\n\t] of getProcesses().devProcesses.entries()) {\n\t\tprocesses[name] = { port, pid: process.pid, color }\n\t}\n\n\tfor (const [\n\t\tname,\n\t\t{ process, exitCode },\n\t] of getProcesses().testProcesses.entries()) {\n\t\ttestProcesses[name] = { pid: process?.pid, exitCode }\n\t}\n\treturn data(\n\t\t{\n\t\t\tapps,\n\t\t\tprocesses,\n\t\t\ttestProcesses,\n\t\t\tinspectorRunning: isInspectorRunning(),\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport async function action({ request }: Route.ActionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tswitch (intent) {\n\t\tcase 'clear-data': {\n\t\t\tawait clearData()\n\t\t\treturn { success: true }\n\t\t}\n\t\tcase 'clear-caches': {\n\t\t\tawait clearCaches()\n\t\t\treturn { success: true }\n\t\t}\n\t\tcase 'inspect': {\n\t\t\tawait startInspector()\n\t\t\treturn { success: true }\n\t\t}\n\t\tcase 'stop-inspect': {\n\t\t\tawait stopInspector()\n\t\t\treturn { success: true }\n\t\t}\n\t\tdefault: {\n\t\t\tthrow new Error(`Unknown intent: ${intent}`)\n\t\t}\n\t}\n}\n\nfunction sortProgress(a: SerializedProgress, b: SerializedProgress) {\n\treturn a.type === 'unknown' && b.type === 'unknown'\n\t\t? 0\n\t\t: a.type === 'unknown'\n\t\t\t? -1\n\t\t\t: b.type === 'unknown'\n\t\t\t\t? 1\n\t\t\t\t: 0\n}\n\nfunction linkProgress(progress: SerializedProgress) {\n\tswitch (progress.type) {\n\t\tcase 'workshop-instructions':\n\t\t\treturn '/'\n\t\tcase 'workshop-finished':\n\t\t\treturn '/finished'\n\t\tcase 'instructions':\n\t\t\treturn `/${progress.exerciseNumber.toString().padStart(2, '0')}`\n\t\tcase 'step':\n\t\t\treturn `/${progress.exerciseNumber\n\t\t\t\t.toString()\n\t\t\t\t.padStart(2, '0')}/${progress.stepNumber.toString().padStart(2, '0')}`\n\t\tcase 'finished':\n\t\t\treturn `/${progress.exerciseNumber.toString().padStart(2, '0')}/finished`\n\t\tdefault:\n\t\t\treturn ''\n\t}\n}\n\nexport default function AdminLayout({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tconst navigation = useNavigation()\n\tconst epicProgress = useEpicProgress()\n\n\tconst isStartingInspector = navigation.formData?.get('intent') === 'inspect'\n\tconst isStoppingInspector =\n\t\tnavigation.formData?.get('intent') === 'stop-inspect'\n\n\tconst progressStatus = {\n\t\tcompleted: 'bg-green-500',\n\t\tincomplete: 'bg-yellow-500',\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-6 p-6\">\n\t\t\t<div className=\"mb-2\">\n\t\t\t\t<h1 className=\"text-foreground text-2xl font-bold\">Admin Panel</h1>\n\t\t\t\t<p className=\"text-muted-foreground mt-1 text-sm\">\n\t\t\t\t\tManage workshop settings and monitor processes\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<div className=\"grid gap-6 md:grid-cols-2\">\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Progress</CardTitle>\n\t\t\t\t\t\t<CardDescription>EpicWeb.dev lesson progress</CardDescription>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t{epicProgress ? (\n\t\t\t\t\t\t\t<ul className=\"scrollbar-thin scrollbar-thumb-scrollbar flex max-h-72 flex-col gap-2 overflow-y-auto\">\n\t\t\t\t\t\t\t\t{epicProgress.sort(sortProgress).map((progress) => {\n\t\t\t\t\t\t\t\t\tconst status = progress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t\t? 'completed'\n\t\t\t\t\t\t\t\t\t\t: 'incomplete'\n\t\t\t\t\t\t\t\t\tconst label = [\n\t\t\t\t\t\t\t\t\t\tprogress.epicLessonSlug,\n\t\t\t\t\t\t\t\t\t\tprogress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t\t\t? `(${progress.epicCompletedAt})`\n\t\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\tkey={progress.epicLessonSlug}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"hover:bg-muted/50 flex items-center gap-3 rounded-md p-2\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'h-3 w-3 shrink-0 rounded-full',\n\t\t\t\t\t\t\t\t\t\t\t\t\tprogressStatus[status],\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\ttitle={status}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t{progress.type === 'unknown' ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex flex-1 items-center gap-2 truncate text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"truncate\">{label}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<SimpleTooltip content=\"This video is in the workshop on EpicWeb.dev, but not in the local workshop.\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"Close\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"text-destructive h-4 w-4 shrink-0\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\tto={linkProgress(progress)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"text-foreground flex-1 truncate text-sm hover:underline\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tto={progress.epicLessonUrl}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"text-muted-foreground hover:text-foreground shrink-0\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">No progress data</p>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Commands</CardTitle>\n\t\t\t\t\t\t<CardDescription>Workshop management actions</CardDescription>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<DoubleCheckAdminButton name=\"intent\" value=\"clear-caches\">\n\t\t\t\t\t\t\t\t\t<Icon name=\"Clear\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\tClear local caches\n\t\t\t\t\t\t\t\t</DoubleCheckAdminButton>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<DoubleCheckAdminButton\n\t\t\t\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\t\t\t\tvalue=\"clear-data\"\n\t\t\t\t\t\t\t\t\tclassName=\"border-destructive bg-destructive/80 text-destructive-foreground hover:bg-destructive hover:text-destructive-foreground\"\n\t\t\t\t\t\t\t\t\tdoubleCheckClassName=\"border-destructive bg-destructive text-destructive-foreground\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"TriangleAlert\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\tClear all local data (including auth data)\n\t\t\t\t\t\t\t\t</DoubleCheckAdminButton>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t{data.inspectorRunning ? (\n\t\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t\t<AdminButton name=\"intent\" value=\"stop-inspect\">\n\t\t\t\t\t\t\t\t\t\t<Icon name=\"Stop\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t{isStoppingInspector\n\t\t\t\t\t\t\t\t\t\t\t? 'Stopping inspector...'\n\t\t\t\t\t\t\t\t\t\t\t: 'Stop inspector'}\n\t\t\t\t\t\t\t\t\t</AdminButton>\n\t\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t\t<AdminButton name=\"intent\" value=\"inspect\">\n\t\t\t\t\t\t\t\t\t\t{isStartingInspector\n\t\t\t\t\t\t\t\t\t\t\t? 'Starting inspector...'\n\t\t\t\t\t\t\t\t\t\t\t: 'Start inspector'}\n\t\t\t\t\t\t\t\t\t</AdminButton>\n\t\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Apps</CardTitle>\n\t\t\t\t\t\t<CardDescription>Available workshop apps</CardDescription>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ul className=\"scrollbar-thin scrollbar-thumb-scrollbar flex max-h-48 flex-col gap-2 overflow-y-auto\">\n\t\t\t\t\t\t\t{data.apps.length > 0 ? (\n\t\t\t\t\t\t\t\tdata.apps.map((app) => (\n\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\tkey={app.name}\n\t\t\t\t\t\t\t\t\t\tclassName=\"hover:bg-muted/50 flex items-center gap-3 rounded-md p-2\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{data.processes[app.name] ? (\n\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"stopped\" />\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-sm\">{app.name}</span>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tNo apps available\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Processes</CardTitle>\n\t\t\t\t\t\t<CardDescription>Running development processes</CardDescription>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ul className=\"scrollbar-thin scrollbar-thumb-scrollbar flex max-h-48 flex-col gap-2 overflow-y-auto\">\n\t\t\t\t\t\t\t{Object.entries(data.processes).length > 0 ? (\n\t\t\t\t\t\t\t\tObject.entries(data.processes).map(([key, process]) => (\n\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-muted/30 rounded-md border p-3\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-sm font-semibold\">\n\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div className=\"text-muted-foreground mt-2 flex flex-wrap gap-x-4 gap-y-1 text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">Port:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t{process.port}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t{process.pid && (\n\t\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">PID:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{process.pid}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">Color:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"inline-block h-3 w-3 rounded-full\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={{ backgroundColor: process.color }}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\tNo processes running\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t{Object.entries(data.testProcesses).length > 0 && (\n\t\t\t\t\t<Card className=\"md:col-span-2\">\n\t\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t\t<CardTitle>Test Processes</CardTitle>\n\t\t\t\t\t\t\t<CardDescription>Test execution processes</CardDescription>\n\t\t\t\t\t\t</CardHeader>\n\t\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t\t<ul className=\"scrollbar-thin scrollbar-thumb-scrollbar flex flex-col gap-2 overflow-y-auto\">\n\t\t\t\t\t\t\t\t{Object.entries(data.testProcesses).map(([key, process]) => (\n\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-muted/30 rounded-md border p-3\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t{process.exitCode === null ||\n\t\t\t\t\t\t\t\t\t\t\tprocess.exitCode === undefined ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t\t\t\t\t) : process.exitCode === 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"stopped\" />\n\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t<Pinger status=\"taken\" />\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-sm font-semibold\">\n\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div className=\"text-muted-foreground mt-2 flex flex-wrap gap-x-4 gap-y-1 text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t{process.pid && (\n\t\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">PID:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{process.pid}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">Exit code:</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t{process.exitCode === null ||\n\t\t\t\t\t\t\t\t\t\t\t\tprocess.exitCode === undefined\n\t\t\t\t\t\t\t\t\t\t\t\t\t? 'Running'\n\t\t\t\t\t\t\t\t\t\t\t\t\t: process.exitCode}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</CardContent>\n\t\t\t\t\t</Card>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction Card({\n\tchildren,\n\tclassName,\n}: {\n\tchildren: React.ReactNode\n\tclassName?: string\n}) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'border-border bg-card rounded-lg border p-6 shadow-sm',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t)\n}\n\nfunction CardHeader({ children }: { children: React.ReactNode }) {\n\treturn <div className=\"mb-4\">{children}</div>\n}\n\nfunction CardTitle({ children }: { children: React.ReactNode }) {\n\treturn <h2 className=\"text-foreground text-lg font-semibold\">{children}</h2>\n}\n\nfunction CardDescription({ children }: { children: React.ReactNode }) {\n\treturn <p className=\"text-muted-foreground mt-1 text-sm\">{children}</p>\n}\n\nfunction CardContent({ children }: { children: React.ReactNode }) {\n\treturn <div>{children}</div>\n}\n\nfunction AdminButton({\n\tchildren,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'>) {\n\treturn (\n\t\t<button\n\t\t\t{...props}\n\t\t\tclassName={cn(\n\t\t\t\t'border-border bg-background text-foreground hover:bg-muted hover:text-foreground focus:ring-ring inline-flex w-full items-center justify-center gap-2 rounded-md border px-4 py-2 text-sm font-medium transition-colors focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none disabled:opacity-50',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</button>\n\t)\n}\n\nfunction DoubleCheckAdminButton({\n\tchildren,\n\tdoubleCheckClassName,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'> & {\n\tdoubleCheckClassName?: string\n}) {\n\tconst { doubleCheck, getButtonProps } = useDoubleCheck()\n\n\treturn (\n\t\t<AdminButton\n\t\t\t{...getButtonProps(props)}\n\t\t\tclassName={cn(\n\t\t\t\tprops.className,\n\t\t\t\tdoubleCheck\n\t\t\t\t\t? (doubleCheckClassName ??\n\t\t\t\t\t\t\t'border-destructive bg-destructive text-destructive-foreground')\n\t\t\t\t\t: null,\n\t\t\t)}\n\t\t>\n\t\t\t{doubleCheck ? (\n\t\t\t\t<>\n\t\t\t\t\t<Icon name=\"TriangleAlert\" className=\"h-4 w-4\" />\n\t\t\t\t\tAre you sure?\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\tchildren\n\t\t\t)}\n\t\t</AdminButton>\n\t)\n}\n\nfunction Pinger({\n\tstatus,\n}: {\n\tstatus: 'running' | 'starting' | 'stopped' | 'taken'\n}) {\n\tconst colors = {\n\t\trunning: {\n\t\t\tpinger: 'bg-green-400',\n\t\t\tcircle: 'bg-green-500',\n\t\t},\n\t\tstarting: {\n\t\t\tpinger: 'bg-sky-400',\n\t\t\tcircle: 'bg-sky-500',\n\t\t},\n\t\tstopped: {\n\t\t\tcircle: 'bg-muted-foreground',\n\t\t},\n\t\ttaken: {\n\t\t\tpinger: 'bg-red-400',\n\t\t\tcircle: 'bg-red-500',\n\t\t},\n\t}[status]\n\treturn (\n\t\t<span className=\"relative flex h-3 w-3 shrink-0\">\n\t\t\t{colors.pinger ? (\n\t\t\t\t<span\n\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t'absolute inline-flex h-full w-full animate-ping rounded-full opacity-75',\n\t\t\t\t\t\tcolors.pinger,\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<span\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'relative inline-flex h-3 w-3 rounded-full',\n\t\t\t\t\tcolors.circle,\n\t\t\t\t)}\n\t\t\t/>\n\t\t</span>\n\t)\n}\n","import { getEnv } from '@epic-web/workshop-utils/env.server'\nimport {\n\tgetCommitInfo,\n\tgetLatestWorkshopAppVersion,\n} from '@epic-web/workshop-utils/git.server'\nimport {\n\tcombineServerTimings,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport { dayjs } from '@epic-web/workshop-utils/utils.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { type HeadersFunction, useLoaderData, data } from 'react-router'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader() {\n\tconst timings = makeTimings('versionLoader')\n\tconst [commitInfo, latestVersion] = await Promise.all([\n\t\ttime(() => getCommitInfo(), { timings, type: 'getCommitInfo' }),\n\t\ttime(() => getLatestWorkshopAppVersion().catch((e) => getErrorMessage(e)), {\n\t\t\ttimings,\n\t\t\ttype: 'getLatestWorkshopAppVersion',\n\t\t}),\n\t])\n\n\tconst uptime = process.uptime() * 1000\n\tconst startDate = new Date(Date.now() - uptime)\n\n\treturn data(\n\t\t{\n\t\t\tworkshopInstanceId: getEnv().EPICSHOP_WORKSHOP_INSTANCE_ID,\n\t\t\tworkshopContextCwd: getEnv().EPICSHOP_CONTEXT_CWD,\n\t\t\tworkshopCommit: commitInfo\n\t\t\t\t? {\n\t\t\t\t\t\t...commitInfo,\n\t\t\t\t\t\tdateFormatted: dayjs(commitInfo.date).format('YYYY-MM-DD HH:mm:ss'),\n\t\t\t\t\t\tdateFromNow: dayjs(commitInfo.date).fromNow(),\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t\tlatestWorkshopAppVersion: latestVersion,\n\t\t\tworkshopAppVersion: getEnv().EPICSHOP_APP_VERSION,\n\t\t\tstartTime: startDate.toISOString(),\n\t\t\tstartTimeFormatted: dayjs(startDate).format('YYYY-MM-DD HH:mm:ss'),\n\t\t\tstartTimeFromNow: dayjs(startDate).fromNow(),\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ parentHeaders, loaderHeaders }) => {\n\treturn {\n\t\t'Server-Timing': combineServerTimings(parentHeaders, loaderHeaders),\n\t}\n}\n\nexport default function Version() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst workshopConfig = useWorkshopConfig()\n\n\treturn (\n\t\t<div>\n\t\t\t<h2 className=\"text-lg font-bold\">Workshop Version Information</h2>\n\t\t\t<p>Workshop Instance ID: {data.workshopInstanceId}</p>\n\t\t\t<p>Workshop Context CWD: {data.workshopContextCwd}</p>\n\t\t\t<h3 className=\"text-md font-bold\">Workshop Commit</h3>\n\t\t\t{data.workshopCommit ? (\n\t\t\t\t<>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tHash:{' '}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={`${workshopConfig.githubRepo}/commit/${data.workshopCommit.hash}`}\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{data.workshopCommit.hash}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p>Message: {data.workshopCommit.message}</p>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tDate: {data.workshopCommit.dateFormatted} (\n\t\t\t\t\t\t{data.workshopCommit.dateFromNow})\n\t\t\t\t\t</p>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<p>No commit information available</p>\n\t\t\t)}\n\t\t\t<h3 className=\"text-md font-bold\">Workshop App</h3>\n\t\t\t<p>\n\t\t\t\t{'Current Version: '}\n\t\t\t\t{data.workshopAppVersion ? (\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={`https://github.com/epicweb-dev/epicshop/releases/tag/v${data.workshopAppVersion}`}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.workshopAppVersion}\n\t\t\t\t\t</a>\n\t\t\t\t) : (\n\t\t\t\t\t'Unknown'\n\t\t\t\t)}\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t{'Latest Version: '}\n\t\t\t\t<a\n\t\t\t\t\thref={`https://github.com/epicweb-dev/epicshop/releases/tag/v${data.latestWorkshopAppVersion}`}\n\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t>\n\t\t\t\t\t{data.latestWorkshopAppVersion}\n\t\t\t\t</a>\n\t\t\t</p>\n\t\t\t<h3 className=\"text-md font-bold\">App Start Time</h3>\n\t\t\t<p>\n\t\t\t\t{data.startTimeFormatted} ({data.startTimeFromNow})\n\t\t\t</p>\n\t\t</div>\n\t)\n}\n","import { getApps } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { data, type LoaderFunctionArgs } from 'react-router'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('appsLoader')\n\tconst apps = await getApps({ request, timings })\n\treturn data(\n\t\t{ apps },\n\t\t{ headers: { 'Server-Timing': getServerTimeHeader(timings) } },\n\t)\n}\n","import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tisExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { userHasAccessToWorkshop } from '@epic-web/workshop-utils/epic-api.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport {\n\ttype LoaderFunctionArgs,\n\tuseLoaderData,\n\tuseNavigation,\n\tuseSearchParams,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport { Diff } from '#app/components/diff.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst reqUrl = new URL(request.url)\n\tconst searchParams = reqUrl.searchParams\n\tconst timings = makeTimings('diffLoader')\n\tconst cacheOptions = { request, timings }\n\tconst allAppsFull = await getApps()\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\n\tconst usingDefaultApp1 = !app1Name\n\n\t// defaults to first problem app\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: allAppsFull.filter(isExerciseStepApp).at(0)\n\n\t// defaults to last exercise step app\n\tconst app2 = app2Name\n\t\t? await getAppByName(app2Name)\n\t\t: allAppsFull.filter(isExerciseStepApp).at(-1)\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t}))\n\n\tconst diff = getDiffProp()\n\tconst app1Index = allApps.findIndex((a) => a.name === app1?.name)\n\tconst prevApp1Index = usingDefaultApp1\n\t\t? allApps.length - 2\n\t\t: app1Index === 0\n\t\t\t? -2\n\t\t\t: app1Index - 1\n\tconst prevApp2Index = prevApp1Index + 1\n\tconst nextApp1Index = usingDefaultApp1\n\t\t? 0\n\t\t: app1Index + 1 < allApps.length\n\t\t\t? app1Index + 1\n\t\t\t: -2\n\tconst nextApp2Index = nextApp1Index + 1\n\tconst prevApp1 = allAppsFull[prevApp1Index]?.name\n\tconst prevApp2 = allAppsFull[prevApp2Index]?.name\n\tconst nextApp1 = allAppsFull[nextApp1Index]?.name\n\tconst nextApp2 = allAppsFull[nextApp2Index]?.name\n\tconst prevSearchParams = new URLSearchParams(reqUrl.searchParams)\n\tprevSearchParams.set('app1', prevApp1 ?? '')\n\tprevSearchParams.set('app2', prevApp2 ?? '')\n\tconst nextSearchParams = new URLSearchParams(reqUrl.searchParams)\n\tnextSearchParams.set('app1', nextApp1 ?? '')\n\tnextSearchParams.set('app2', nextApp2 ?? '')\n\treturn {\n\t\tuserHasAccessPromise: userHasAccessToWorkshop({ request, timings }),\n\t\tallApps,\n\t\tdiff,\n\t\tprevLink:\n\t\t\tprevApp1 && prevApp2\n\t\t\t\t? { to: `/diff?${prevSearchParams}`, 'aria-label': 'Previous App' }\n\t\t\t\t: { to: '/diff' },\n\t\tnextLink:\n\t\t\tnextApp1 && nextApp2\n\t\t\t\t? { to: `/diff?${nextSearchParams}`, 'aria-label': 'Next App' }\n\t\t\t\t: { to: '/diff' },\n\t}\n}\n\nexport default function DiffViewer() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst [params] = useSearchParams()\n\tconst paramsWithForcedRefresh = new URLSearchParams(params)\n\tparamsWithForcedRefresh.set('forceFresh', 'diff')\n\tconst navigation = useNavigation()\n\tconst isNavigating = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 200,\n\t\tminDuration: 200,\n\t})\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn('h-screen-safe relative', {\n\t\t\t\t'cursor-wait opacity-30': isNavigating,\n\t\t\t})}\n\t\t>\n\t\t\t<div className=\"h-full pb-16\">\n\t\t\t\t<Diff\n\t\t\t\t\tdiff={data.diff}\n\t\t\t\t\tallApps={data.allApps}\n\t\t\t\t\tuserHasAccessPromise={data.userHasAccessPromise}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"bg-background fixed inset-x-0 bottom-0 z-10 flex h-16 items-center justify-end border-t\">\n\t\t\t\t<div className=\"flex h-full items-center justify-end\">\n\t\t\t\t\t<NavChevrons prev={data.prevLink} next={data.nextLink} />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n","import {\n\ttype ExerciseStepApp,\n\tgetExercise,\n\tgetNextExerciseApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { redirect } from 'react-router'\nimport { type Route } from './+types/diff.$shortcut.ts'\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('diffLoader')\n\n\tconst [exerciseNumber, stepNumber] = params.shortcut?.split('.') ?? []\n\tif (!exerciseNumber) {\n\t\treturn redirect(`/diff`)\n\t}\n\tconst exercise = await getExercise(Number(exerciseNumber), {\n\t\trequest,\n\t\ttimings,\n\t})\n\tconst headers = { 'Server-Timing': timings.toString() }\n\n\tif (!exercise) return redirect(`/diff`, { headers })\n\n\tconst step = stepNumber\n\t\t? exercise.steps.find((s) => s.stepNumber === Number(stepNumber))\n\t\t: exercise.steps.find(Boolean)\n\tconst exerciseStepApp = step?.problem ?? step?.solution\n\tif (!exerciseStepApp) {\n\t\treturn redirect(`/diff`, { headers })\n\t}\n\tlet nextApp = await getNextExerciseApp(exerciseStepApp, {\n\t\trequest,\n\t\ttimings,\n\t})\n\tif (!nextApp) {\n\t\tnextApp = exerciseStepApp\n\t}\n\n\treturn redirect(\n\t\t`/diff?app1=${makeId(exerciseStepApp)}&app2=${makeId(nextApp)}`,\n\t\t{ headers: { 'Server-Timing': timings.toString() } },\n\t)\n}\n\nfunction makeId(app: ExerciseStepApp) {\n\treturn `${pad(app.exerciseNumber)}.${pad(app.stepNumber)}.${app.type}`\n}\n\nfunction pad(number: number) {\n\treturn number.toString().padStart(2, '0')\n}\n","import { getExercises } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { data, type LoaderFunctionArgs } from 'react-router'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('appsLoader')\n\tconst exercises = await getExercises({ request, timings })\n\treturn data(\n\t\t{ exercises },\n\t\t{ headers: { 'Server-Timing': getServerTimeHeader(timings) } },\n\t)\n}\n","import { useEffect } from 'react'\nimport { type z } from 'zod'\n\nexport function useMcpUiInit(rootRef: React.RefObject<HTMLDivElement | null>) {\n\tuseEffect(() => {\n\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\t\tif (!rootRef.current) return\n\n\t\tconst height = rootRef.current.clientHeight\n\t\tconst width = rootRef.current.clientWidth\n\n\t\twindow.parent.postMessage(\n\t\t\t{ type: 'ui-size-change', payload: { height, width } },\n\t\t\t'*',\n\t\t)\n\t}, [rootRef])\n}\n\ntype MessageOptions = { schema?: z.ZodSchema }\n\ntype McpMessageReturnType<Options> = Promise<\n\tOptions extends { schema: z.ZodSchema } ? z.infer<Options['schema']> : unknown\n>\n\ntype McpMessageTypes = {\n\ttool: { toolName: string; params: Record<string, unknown> }\n\tprompt: { prompt: string }\n\tlink: { url: string }\n}\n\ntype McpMessageType = keyof McpMessageTypes\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'tool',\n\tpayload: McpMessageTypes['tool'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'prompt',\n\tpayload: McpMessageTypes['prompt'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'link',\n\tpayload: McpMessageTypes['link'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage<Options extends MessageOptions>(\n\ttype: 'link',\n\tpayload: McpMessageTypes['link'],\n\toptions?: Options,\n): McpMessageReturnType<Options>\n\nfunction sendMcpMessage(\n\ttype: McpMessageType,\n\tpayload: McpMessageTypes[McpMessageType],\n\toptions: MessageOptions = {},\n): McpMessageReturnType<typeof options> {\n\tconst { schema } = options\n\tconst messageId = crypto.randomUUID()\n\n\treturn new Promise((resolve, reject) => {\n\t\tif (!window.parent || window.parent === window) {\n\t\t\tconsole.log(`[MCP] No parent frame available. Would have sent message:`, {\n\t\t\t\ttype,\n\t\t\t\tmessageId,\n\t\t\t\tpayload,\n\t\t\t})\n\t\t\treject(new Error('No parent frame available'))\n\t\t\treturn\n\t\t}\n\n\t\twindow.parent.postMessage({ type, messageId, payload }, '*')\n\n\t\tfunction handleMessage(event: MessageEvent) {\n\t\t\tif (event.data.type !== 'ui-message-response') return\n\t\t\tif (event.data.messageId !== messageId) return\n\t\t\twindow.removeEventListener('message', handleMessage)\n\n\t\t\tconst { response, error } = event.data.payload\n\n\t\t\tif (error) return reject(error)\n\t\t\tif (!schema) return resolve(response)\n\n\t\t\tconst parseResult = schema.safeParse(response)\n\t\t\tif (!parseResult.success) return reject(parseResult.error)\n\n\t\t\treturn resolve(parseResult.data)\n\t\t}\n\n\t\twindow.addEventListener('message', handleMessage)\n\t})\n}\n\nexport { sendMcpMessage }\n\nexport function waitForRenderData<RenderData>(\n\tschema: z.ZodSchema<RenderData>,\n): Promise<RenderData> {\n\treturn new Promise((resolve, reject) => {\n\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\n\t\tfunction handleMessage(event: MessageEvent) {\n\t\t\tif (event.data?.type !== 'ui-lifecycle-iframe-render-data') return\n\t\t\twindow.removeEventListener('message', handleMessage)\n\n\t\t\tconst { renderData, error } = event.data.payload\n\n\t\t\tif (error) return reject(error)\n\t\t\tif (!schema) return resolve(renderData)\n\n\t\t\tconst parseResult = schema.safeParse(renderData)\n\t\t\tif (!parseResult.success) return reject(parseResult.error)\n\n\t\t\treturn resolve(parseResult.data)\n\t\t}\n\n\t\twindow.addEventListener('message', handleMessage)\n\t})\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { useEffect, useRef } from 'react'\nimport { data } from 'react-router'\nimport {\n\tDeferredEpicVideo,\n\tEpicVideoInfoProvider,\n} from '#app/components/epic-video.tsx'\nimport { type Route } from './+types/epic-video.tsx'\nimport { sendMcpMessage } from './__utils.ts'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('epicVideoLoader')\n\tconst videoUrl = new URL(request.url).searchParams.get('url')\n\tinvariantResponse(videoUrl, 'url param is required')\n\tconst videoInfos = getEpicVideoInfos([videoUrl], {\n\t\trequest,\n\t\ttimings,\n\t})\n\treturn data(\n\t\t{ videoInfos, videoUrl },\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport default function EpicVideoEmbedRoute({\n\tloaderData,\n}: Route.ComponentProps) {\n\tconst rootRef = useRef<HTMLDivElement>(null)\n\tuseEffect(() => {\n\t\tvoid loaderData.videoInfos?.finally(() => {\n\t\t\twindow.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*')\n\t\t\tif (!rootRef.current) return\n\n\t\t\tconst height = rootRef.current.clientHeight\n\t\t\tconst width = rootRef.current.clientWidth\n\n\t\t\twindow.parent.postMessage(\n\t\t\t\t{ type: 'ui-size-change', payload: { height, width } },\n\t\t\t\t'*',\n\t\t\t)\n\t\t})\n\t}, [loaderData.videoInfos])\n\n\tasync function handleLinksClick(event: React.MouseEvent<HTMLElement>) {\n\t\tconst target = event.target\n\t\tif (!(target instanceof HTMLAnchorElement)) return\n\n\t\tconst href = target.href\n\t\tif (!href) return\n\n\t\tevent.preventDefault()\n\t\tevent.stopPropagation()\n\n\t\tconst url = href.startsWith('http')\n\t\t\t? new URL(href)\n\t\t\t: new URL(href, window.location.origin)\n\t\tconst isLocal = url.host === window.location.host\n\n\t\tif (isLocal && url.pathname === '/login') {\n\t\t\tawait sendMcpMessage('tool', {\n\t\t\t\ttoolName: 'login',\n\t\t\t\tparams: { workshopDirectory: ENV.EPICSHOP_CONTEXT_CWD },\n\t\t\t})\n\t\t}\n\n\t\tawait sendMcpMessage('link', { url: url.toString() })\n\t}\n\n\treturn (\n\t\t<div ref={rootRef} onClickCapture={handleLinksClick}>\n\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={loaderData.videoInfos}>\n\t\t\t\t<DeferredEpicVideo url={loaderData.videoUrl} />\n\t\t\t</EpicVideoInfoProvider>\n\t\t</div>\n\t)\n}\n","import { invariant } from '@epic-web/invariant'\nimport { cachified, ogCache } from '@epic-web/workshop-utils/cache.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\ttype Timings,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport { Resvg } from '@resvg/resvg-js'\nimport { renderToStaticMarkup } from 'react-dom/server'\nimport { type LoaderFunctionArgs } from 'react-router'\nimport satori, { type SatoriOptions } from 'satori'\nimport { getDomainUrl, getErrorMessage } from '#app/utils/misc.tsx'\n\nconst WIDTH = 1200\nconst HEIGHT = 630\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('og', 'og image loader')\n\tconst url = new URL(request.url)\n\tconst workshopConfig = getWorkshopConfig()\n\tconst title = url.searchParams.get('title') || workshopConfig.title\n\tconst subtitle = url.searchParams.get('subtitle') || workshopConfig.subtitle\n\tconst urlPathname = url.searchParams.get('urlPathname') || ''\n\tconst logo = workshopConfig.product.logo.startsWith('http')\n\t\t? workshopConfig.product.logo\n\t\t: new URL(workshopConfig.product.logo, getDomainUrl(request)).toString()\n\n\tconst element = (\n\t\t<OgLayout\n\t\t\trequest={request}\n\t\t\tinstructor={workshopConfig.instructor}\n\t\t\turlPathname={urlPathname}\n\t\t\tworkshopTitle={\n\t\t\t\tworkshopConfig.title === title ? null : workshopConfig.title\n\t\t\t}\n\t\t\tproductLogo={logo}\n\t\t\tproductDisplayName={workshopConfig.product.displayName}\n\t\t>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\tflexDirection: 'column',\n\t\t\t\t\tjustifyContent: 'center',\n\t\t\t\t\talignItems: 'center',\n\t\t\t\t\theight: '100%',\n\t\t\t\t\twidth: '100%',\n\t\t\t\t\tcolor: 'white',\n\t\t\t\t\tpadding: 100,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<h1\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\tjustifyContent: 'center',\n\t\t\t\t\t\tfontSize: '80px',\n\t\t\t\t\t\t// https://github.com/vercel/satori/issues/498\n\t\t\t\t\t\ttextWrap: title.includes(' ') ? 'balance' : 'initial',\n\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{title}\n\t\t\t\t</h1>\n\t\t\t\t{subtitle ? (\n\t\t\t\t\t<p\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\tjustifyContent: 'center',\n\t\t\t\t\t\t\tfontSize: '40px',\n\t\t\t\t\t\t\t// https://github.com/vercel/satori/issues/498\n\t\t\t\t\t\t\ttextWrap: subtitle.includes(' ') ? 'balance' : 'initial',\n\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{subtitle}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</OgLayout>\n\t)\n\n\tconst renderHtml = url.searchParams.get('html')\n\tif (renderHtml === 'true') {\n\t\treturn new Response(renderToStaticMarkup(element), {\n\t\t\theaders: { 'Content-Type': 'text/html' },\n\t\t})\n\t}\n\n\tconst debug = url.searchParams.get('debug') === 'true'\n\n\ttry {\n\t\tconst ogImg = await cachified({\n\t\t\trequest,\n\t\t\ttimings,\n\t\t\ttimingKey: 'og-image',\n\t\t\t// if debug is true, then force, otherwise use undefined and it'll be derived from the request\n\t\t\tforceFresh: debug ? debug : undefined,\n\t\t\tkey: request.url,\n\t\t\tcache: ogCache,\n\t\t\tttl: 1000 * 60 * 60 * 24 * 7,\n\t\t\tstaleWhileRevalidate: 1000 * 60 * 60 * 24 * 365,\n\t\t\tgetFreshValue: async () => {\n\t\t\t\treturn await getOgImg(element, { request, timings })\n\t\t\t},\n\t\t})\n\t\t// @ts-ignore 🤷‍♂️ CLI doesn't like this but editor is fine 🙃\n\t\treturn new Response(ogImg, {\n\t\t\theaders: {\n\t\t\t\t'Cache-Control':\n\t\t\t\t\tENV.EPICSHOP_DEPLOYED && !(debug || url.searchParams.has('fresh'))\n\t\t\t\t\t\t? 'public, max-age=31536000, immutable'\n\t\t\t\t\t\t: 'no-cache no-store',\n\t\t\t\t'Content-Type': 'image/png',\n\t\t\t\t'Server-Timing': timings.toString(),\n\t\t\t},\n\t\t})\n\t} catch (error) {\n\t\treturn new Response(getErrorMessage(error), {\n\t\t\tstatus: 500,\n\t\t\theaders: { 'Server-Timing': timings.toString() },\n\t\t})\n\t}\n}\n\nasync function getOgImg(\n\tjsx: React.ReactNode,\n\t{ request, timings }: { request: Request; timings: Timings },\n) {\n\tconst url = new URL(request.url)\n\tconst svg = await satori(jsx, {\n\t\twidth: WIDTH,\n\t\theight: HEIGHT,\n\t\tdebug: url.searchParams.get('debug') === 'true',\n\t\tfonts: await Promise.all([\n\t\t\tgetFont({ font: 'Josefin Sans', request, timings }),\n\t\t]).then((fonts) => fonts.flat()),\n\t\tloadAdditionalAsset: async (code: string, segment: string) => {\n\t\t\tif (code === 'emoji') {\n\t\t\t\tconst svg = await getEmoji(segment, { request, timings })\n\t\t\t\tif (!svg) return ''\n\t\t\t\tconst base64 = Buffer.from(svg).toString('base64')\n\t\t\t\treturn `data:image/svg+xml;base64,${base64}`\n\t\t\t}\n\n\t\t\tconsole.error(`Unhandled asset code: \"${code}\" for segment \"${segment}\"`)\n\n\t\t\treturn ''\n\t\t},\n\t})\n\n\tconst resvg = new Resvg(svg)\n\tconst pngData = resvg.render()\n\tconst data = pngData.asPng()\n\n\treturn data\n}\n\nasync function getEmoji(\n\temoji: string,\n\t{ request, timings }: { request: Request; timings: Timings },\n) {\n\tconst emojiCode = emojiToCodePoints(emoji)\n\tif (!emojiCode) return null\n\tconst emojiUrl = `https://cdn.jsdelivr.net/gh/jdecked/twemoji@15/assets/svg/${emojiCode}.svg`\n\treturn cachified({\n\t\tcache: ogCache,\n\t\tkey: emojiUrl,\n\t\trequest,\n\t\ttimings,\n\t\ttimingKey: `loading ${emojiCode}`,\n\t\tgetFreshValue: async () => {\n\t\t\tconst response = await fetch(emojiUrl)\n\t\t\treturn response.text()\n\t\t},\n\t})\n}\n\nfunction emojiToCodePoints(emoji: string) {\n\tconst codePoints = []\n\tfor (let i = 0; i < emoji.length; i++) {\n\t\tconst codePoint = emoji.codePointAt(i)\n\t\tif (!codePoint) continue\n\t\tcodePoints.push(codePoint.toString(16))\n\t\tif (codePoint > 0xffff) {\n\t\t\t// Skip the next code unit for surrogate pairs\n\t\t\ti++\n\t\t}\n\t}\n\treturn codePoints.join('-')\n}\n\nasync function getFont({\n\tfont,\n\tweights = [200, 300, 400, 500, 600, 700],\n\ttimings,\n\trequest,\n}: {\n\tfont: string\n\tweights?: Array<number>\n\ttimings?: Timings\n\trequest?: Request\n}) {\n\tconst weightsString = weights.join(';')\n\tconst fetchUrl = `https://fonts.googleapis.com/css2?family=${font}:wght@${weightsString}`\n\tconst css = await cachified({\n\t\tkey: fetchUrl,\n\t\tcache: ogCache,\n\t\ttimings,\n\t\ttimingKey: `font-${font}`,\n\t\trequest,\n\t\tgetFreshValue: async () => {\n\t\t\treturn fetch(fetchUrl, {\n\t\t\t\theaders: {\n\t\t\t\t\t// Make sure it returns TTF.\n\t\t\t\t\t'User-Agent':\n\t\t\t\t\t\t'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',\n\t\t\t\t},\n\t\t\t}).then((response) => response.text())\n\t\t},\n\t})\n\n\tconst resource = css.matchAll(\n\t\t/src: url\\((.+)\\) format\\('(opentype|truetype)'\\)/g,\n\t)\n\n\treturn Promise.all(\n\t\t[...resource]\n\t\t\t.map((match) => match[1])\n\t\t\t.map((url) => {\n\t\t\t\tinvariant(\n\t\t\t\t\turl,\n\t\t\t\t\t() => `Expected a URL to be parsed from the google font:\\n${css}`,\n\t\t\t\t)\n\t\t\t\treturn fetch(url).then((response) => response.arrayBuffer())\n\t\t\t})\n\t\t\t.map(async (buffer, i) => ({\n\t\t\t\tname: font,\n\t\t\t\tstyle: 'normal',\n\t\t\t\tweight: weights[i],\n\t\t\t\tdata: await buffer,\n\t\t\t})),\n\t) as Promise<SatoriOptions['fonts']>\n}\n\nfunction OgLayout({\n\tinstructor,\n\tchildren,\n\trequest,\n\turlPathname = new URL(request.url).pathname.replace(/\\/og$/, ''),\n\tworkshopTitle,\n}: {\n\tinstructor: ReturnType<typeof getWorkshopConfig>['instructor']\n\trequest: Request\n\tchildren: React.ReactNode\n\tworkshopTitle?: string | null\n\turlPathname?: string | null\n\tproductLogo: string\n\tproductDisplayName: string\n}) {\n\tconst domain = getDomainUrl(request)\n\tconst protocolFreeDomain = domain.replace(/^https?:\\/\\//, '')\n\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\tfontFamily: 'Josefin Sans',\n\t\t\t\tdisplay: 'flex',\n\t\t\t\tflexDirection: 'column',\n\t\t\t\twidth: '100%',\n\t\t\t\theight: '100%',\n\t\t\t\tposition: 'relative',\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tright: 0,\n\t\t\t\t\tbottom: 0,\n\t\t\t\t\tleft: 0,\n\t\t\t\t\twidth: '100%',\n\t\t\t\t\theight: '100%',\n\t\t\t\t\tbackgroundColor: '#080B16',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<img\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\theight: '100%',\n\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\topacity: 0.3,\n\t\t\t\t\t}}\n\t\t\t\t\tsrc={`${domain}/og/background.png`}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div style={{ display: 'flex', position: 'absolute', top: 20, left: 30 }}>\n\t\t\t\t<img height={56} src={`${domain}/og/logo.svg`} />\n\t\t\t</div>\n\t\t\t{instructor ? (\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\tgap: 8,\n\t\t\t\t\t\tjustifyContent: 'center',\n\t\t\t\t\t\talignItems: 'center',\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 20,\n\t\t\t\t\t\tright: 30,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{instructor.avatar ? (\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tsrc={\n\t\t\t\t\t\t\t\tinstructor.avatar.startsWith('/')\n\t\t\t\t\t\t\t\t\t? `${domain}${instructor.avatar}`\n\t\t\t\t\t\t\t\t\t: instructor.avatar\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\twidth: 56,\n\t\t\t\t\t\t\t\theight: 56,\n\t\t\t\t\t\t\t\tborderRadius: '50%',\n\t\t\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{instructor.name ? (\n\t\t\t\t\t\t<h2\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\t\t\topacity: 0.8,\n\t\t\t\t\t\t\t\tcolor: 'white',\n\t\t\t\t\t\t\t\tfontSize: 30,\n\t\t\t\t\t\t\t\tfontWeight: 700,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{instructor.name}\n\t\t\t\t\t\t</h2>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t{children}\n\t\t\t{workshopTitle ? (\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tbottom: 20,\n\t\t\t\t\t\tleft: 30,\n\t\t\t\t\t\tcolor: 'white',\n\t\t\t\t\t\topacity: 0.8,\n\t\t\t\t\t\tfontSize: 20,\n\t\t\t\t\t\tfontWeight: 700,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{workshopTitle}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t{urlPathname == null ? null : (\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tbottom: 20,\n\t\t\t\t\t\tright: 30,\n\t\t\t\t\t\tcolor: 'white',\n\t\t\t\t\t\topacity: 0.8,\n\t\t\t\t\t\tfontSize: 20,\n\t\t\t\t\t\tfontWeight: 700,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{protocolFreeDomain + urlPathname.replace(/\\/$/, '')}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n","import { getProcesses } from '@epic-web/workshop-utils/process-manager.server'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst processes: Record<\n\t\tstring,\n\t\t{ port: number; pid?: number; color: string }\n\t> = {}\n\tfor (const [\n\t\tname,\n\t\t{ port, process, color },\n\t] of getProcesses().devProcesses.entries()) {\n\t\tprocesses[name] = { port, pid: process.pid, color }\n\t}\n\tconst testProcesses: Record<\n\t\tstring,\n\t\t{ pid?: number; exitCode?: number | null; output?: Array<any> }\n\t> = {}\n\tfor (const [\n\t\tname,\n\t\t{ process, exitCode, output },\n\t] of getProcesses().testProcesses.entries()) {\n\t\ttestProcesses[name] = { pid: process?.pid, exitCode, output }\n\t}\n\treturn Response.json({ processes, testProcesses })\n}\n","// TODO: make this a proper healthcheck\nexport const loader = () => new Response('🐨 All good here')\n","import { invariantResponse } from '@epic-web/invariant'\nimport { type Route } from './+types/lookout'\n\nconst SENTRY_HOST = new URL(ENV.SENTRY_DSN).hostname\nconst SENTRY_PROJECT_IDS = [ENV.SENTRY_PROJECT_ID]\n\nexport async function action({ request }: Route.ActionArgs) {\n\tconst envelope = await request.text()\n\tconst piece = envelope.split('\\n')[0]\n\tinvariantResponse(piece, 'no piece in envelope')\n\n\tconst header = JSON.parse(piece ?? '{}') as any\n\tconst dsn = new URL(header.dsn)\n\tconst projectId = dsn.pathname?.replace('/', '')\n\n\tinvariantResponse(\n\t\tdsn.hostname === SENTRY_HOST,\n\t\t`Invalid sentry hostname: ${dsn.hostname}`,\n\t)\n\tinvariantResponse(\n\t\tprojectId && SENTRY_PROJECT_IDS.includes(projectId),\n\t\t`Invalid sentry project id: ${projectId}`,\n\t)\n\n\tconst upstreamSentryURL = `https://${SENTRY_HOST}/api/${projectId}/envelope/`\n\ttry {\n\t\treturn await fetch(upstreamSentryURL, { method: 'POST', body: envelope })\n\t} catch (error) {\n\t\tconsole.error(`Error forwarding Sentry event: ${error}`)\n\t\treturn new Response('Sentry event not forwarded due to network error', {\n\t\t\tstatus: 200,\n\t\t})\n\t}\n}\n","import { generateRobotsTxt } from '@nasa-gcn/remix-seo'\nimport { type LoaderFunctionArgs } from 'react-router'\nimport { getDomainUrl } from '#app/utils/misc.tsx'\n\nexport function loader({ request }: LoaderFunctionArgs) {\n\treturn generateRobotsTxt([\n\t\t{ type: 'sitemap', value: `${getDomainUrl(request)}/sitemap.xml` },\n\t])\n}\n","import { generateSitemap } from '@nasa-gcn/remix-seo'\nimport { type ServerBuild, type LoaderFunctionArgs } from 'react-router'\nimport { getDomainUrl } from '#app/utils/misc.tsx'\n\nexport async function loader({ request, context }: LoaderFunctionArgs) {\n\tconst serverBuild = (await context.serverBuild) as ServerBuild\n\treturn generateSitemap(request, serverBuild.routes, {\n\t\tsiteUrl: getDomainUrl(request),\n\t\theaders: {\n\t\t\t'Cache-Control': `public, max-age=${60 * 5}`,\n\t\t},\n\t})\n}\n"],"names":["Sentry","presence","preferences","ENV","ConfettiShower","sizeClassName","childrenSizeClassName","AnchorOrLink","href","dayjs","Heading","headers","useInterval","formatDuration","index","finished","toast","showToast","data","action","request","formData","intent","get","id","error","status","muteNotification","success","Notifications","unmutedNotifications","fetcher","useFetcher","fetcherRef","useRef","toastedIds","Set","useEffect","notification","current","has","add","info","title","description","children","jsx","message","link","target","className","duration","Infinity","label","onClick","submit","method","useRoute","colorSchemeHint","timeZoneHint","reducedMotionHint","cookieName","ROUTE_PATH","ThemeFormSchema","z","object","theme","enum","loader","referrer","redirect","safeRedirect","submission","parseWithZod","schema","reply","value","responseInit","setTheme","dataWithPE","ThemeSwitch","requestInfo","useRequestInfo","peRedirectInput","usePERedirectInput","form","useForm","lastResult","onValidate","mode","session","nextMode","modeLabel","light","Icon","size","name","dark","system","jsxs","Form","getFormProps","type","SimpleTooltip","content","ErrorList","errors","errorId","useTheme","hints","useHints","fetchers","useFetchers","find","f","optimisticTheme","getUserLocations","cuid","cookie","links","rel","tailwindStylesheetUrl","appStylesheetUrl","sizes","meta","loaderData","getSeoMetaTags","instructor","workshopTitle","workshopSubtitle","timings","makeTimings","workshopConfig","getWorkshopConfig","subtitle","getTheme","confettiId","confettiHeaders","getConfetti","toastHeaders","getToast","isOnlinePromise","checkConnection","asyncStuff","promiseHash","userId","getUserId","getPreferences","progress","getProgress","catch","e","console","emptyProgress","user","getUserInfo","userHasAccess","userHasAccessToWorkshop","apps","getApps","repoUpdates","checkForUpdatesCached","getUnmutedNotifications","exerciseChanges","checkForExerciseChanges","loggedInProductHosts","getLoggedInProductHosts","presentUsers","getPresentUsers","mutedNotifications","getMutedNotifications","remoteCommit","includes","updatesAvailable","map","fullPath","relativePath","getEnv","protocol","URL","url","hostname","port","origin","domain","getDomainUrl","getHints","path","pathname","separator","sep","online","users","combineHeaders","toString","getSetClientIdCookieHeader","Document","env","style","lang","ClientHintCheck","Meta","charSet","Links","dangerouslySetInnerHTML","__html","JSON","stringify","ScrollRestoration","Scripts","App","useLoaderData","navigation","useNavigation","showSpinner","useSpinDelay","state","delay","minDuration","altDown","useAltDown","showKeyboardShortcuts","setShowKeyboardShortcuts","React","useState","handleToggle","prev","window","addEventListener","removeEventListener","fontSize","cn","exerciseWarning","dismissed","ExerciseWarningBanner","Outlet","Confetti","EpicToaster","UpdateToast","EpicProgress","KeyboardShortcutsDialog","open","onOpenChange","_UNSAFE_withComponentProps","AppWithProviders","Presence","TooltipProvider","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary","params","splat","segments","split","length","isNaN","Number","newPath","Response","Location","NotFound","location","useLocation","statusHandlers","Link","to","getSnapshot","subscribe","useEpicProgress","useRootLoaderData","progressFetcher","formAction","p","optimisticCompleted","optimisticLessonSlug","epicLessonSlug","epicCompletedAt","Date","now","useRequireEpicProgress","useNextExerciseRoute","currentPathname","scoreProgress","a","exerciseNumber","stepNumber","sortedProgress","sort","b","nextProgress","ex","padStart","st","problemRoute","solutionRoute","percentageClassNames","useExerciseProgressClassName","exerciseProgress","filter","percentComlete","reduce","acc","numerator","Math","useProgressItemClassName","progressItemSearch","progressItem","useProgressItem","ensureUndeployed","requireAuthInfo","complete","lessonSlug","invariantResponse","beforeProgress","result","updateProgress","lessonProgress","getCompletionAnnouncement","allOtherAreFinished","every","otherExerciseLessons","otherAreFinished","announcement","createConfettiHeaders","createToastHeaders","ProgressToggle","animationRef","buttonRef","Boolean","startAnimation","setStartAnimation","navigationLocationStateFrom","from","navigationLocationPathname","locationPathname","focus","key","latest","Promise","resolve","setTimeout","then","animationPromises","getAnimations","allSettled","EPICSHOP_DEPLOYED","motion","button","ref","clsx","div","initial","scale","opacity","animate","transition","ease","exercises","playgroundAppName","all","getExercises","getPlaygroundAppName","playgroundNumbersAndType","extractNumbersAndTypeFromAppNameOrPath","playground","appName","solutions","problems","steps","problem","solution","isMenuOpened","Vary","getServerTimeHeader","loaderHeaders","parentHeaders","combineServerTimings","opacities","shadows","getScoreClassNames","score","opacityNumber","round","shadowNumber","FacePile","loggedInUser","useOptionalUser","usePresence","product","displayNameShort","useWorkshopConfig","limit","numberOverLimit","shouldShowNumberOverLimit","tiffany","alt","src","overLimitLabel","slice","scoreClassNames","locations","imageUrl","imageUrlSmall","avatarUrl","hasAccess","local","some","loc","productHostEmojis","getUniqueProductHostEmojis","loggedInEmojis","getLoggedInProductEmojis","optOut","Tooltip","TooltipTrigger","asChild","tabIndex","TooltipContent","doingLabel","locationLabel","getLocationLabel","line1","getProductHostEmoji","productHost","line2","hosts","host","join","uniqueHosts","Array","useIsWide","makeMediaQueryStore","isWide","isHydrated","useHydrated","setMenuOpenedState","useRevalidationWS","watchPaths","setMenuOpened","document","NoUserBanner","MobileNavigation","onMenuOpenChange","Navigation","exercise","exercisePortion","s","displayName","useUserHasAccess","details","Fragment","EPICSHOP_GITHUB_REPO","Logo","Dialog","DialogTrigger","DialogContent","DialogHeader","DialogDescription","itemVariants","hidden","x","visible","NavigationExerciseListItem","progressClassName","li","variants","NavigationExerciseStepListItem","nextExerciseRoute","useParams","isOnline","useIsOnline","listVariants","when","staggerChildren","NavToggle","ul","NavLink","prefetch","isActive","showPlayground","getExercisePath","getExerciseStepPath","email","OPENED_MENU_WIDTH","app","menuControls","useAnimationControls","menuVariants","close","width","initialOpenRef","menuButtonRef","path01Variants","d","closed","path02Variants","moving","path01Controls","path02Controls","toggleMenu","start","handleKeyUp","event","click","height","viewBox","stroke","strokeWidth","y","handle","getSitemapEntries","logout","deleteCache","redirectWithToast","setPreferences","useConnectDiscordURL","Account","useUser","config","discordMember","useOptionalDiscordMember","connectDiscordURL","imageUrlLarge","slug","Button","varient","fileApp","resolveApps","dev","getBaseUrl","portNumber","filePath","firstExisting","endsWith","outputFiles","compileTs","file","text","getFileResponse","fsExtra","readFile","mimeType","mimeTypes","lookup","etagValue","etag","ifNoneMatch","Buffer","byteLength","ETag","args","api","getApiModule","mod","cleanupError","ApiModuleSchema","function","optional","apiFiles","readdir","test","apiFile","esbuildOptions","platform","sourcemap","define","apiCode","dataUrl","apiModule","safeParse","Error","stack","replace","relevantPaths","watchParams","URLSearchParams","append","js","baseApp","isPlaygroundApp","getAppByName","htmlFile","hasHtml","pathExists","html","indexFiles","startsWith","indexCss","indexJs","indexTs","indexTsx","scripts","appTitle","baseAppTitle","isExerciseStepApp","getExercise","isProblemApp","isSolutionApp","isExampleApp","isExportApp","generateExportAppHtml","generateBrowserAppHtml","script","scriptFile","testName","testFile","testFiles","testScriptPath","testScriptSrc","testScriptTag","testableHtml","useDiscordCTALink","DiscordCTA","DiscordRoute","flatMap","route","ExercisesLayout","PlaybackTimeSchema","time","number","expiresAt","string","transform","usePlayerPreferences","rootData","pendingPreferencesFetcher","submittingData","json","optimisticPlayerPrefs","player","PlayerPreferencesSchema","flatten","useLatest","MuxPlayer","muxPlayerRef","props","playerPreferences","playerPreferencesFetcher","metadataLoaded","setMetadataLoaded","currentTimeSessionKey","playbackId","currentTime","setCurrentTime","playerPreferencesRef","stored","sessionStorage","getItem","parse","getTime","removeItem","updatePreferences","useDebounce","subs","textTracks","t","kind","newPrefs","playbackRate","volumeRate","volume","isDeepEqual","encType","subtitlePref","preferredTextTrack","getTrackById","RealMuxPlayer","playbackRates","thumbnailTime","onRateChange","onVolumeChange","streamType","defaultHiddenCaptions","onTimeUpdate","setItem","toISOString","accentColor","targetLiveWindow","NaN","minResolution","getMinResolutionValue","maxResolution","getMaxResolutionValue","onLoadedMetadata","obj1","obj2","isArray","i","keys1","Object","keys","keys2","resolution","MinResolution","noLessThan480p","noLessThan540p","noLessThan720p","noLessThan1080p","noLessThan1440p","noLessThan2160p","MaxResolution","upTo720p","upTo1080p","upTo1440p","upTo2160p","getFileDescriptorSchema","appFile","union","literal","LaunchSchema","intersection","line","coerce","column","syncTo","array","workshopFile","getAll","syncToIsProvided","values","v","rawData","getFiles","fileDescriptor","filepath","colum","fileDescriptorApp","filesToOpen","originFiles","originFile","destFile","ensureDir","dirname","promises","copyFile","results","push","launchEditor","r","messages","useLaunchFetcher","onUpdate","LaunchEditorImpl","fileList","syncToType","showProgressBarField","LaunchGitHub","useApps","safePath","githubFileRoot","EPICSHOP_GITHUB_ROOT","EPICSHOP_CONTEXT_CWD","filename","appFileLine","lineNumber","EditFileOnGitHub","compact","handleClick","altKey","preventDefault","FormData","githubPath","LaunchEditor","mdxComponents","matches","getRootMatchLoaderData","ogTitle","ogDescription","desc","getExercise404Data","readmeFilepath","getWorkshopRoot","dirName","firstStep","articleId","slugify","exerciseReadme","exerciseTitle","firstType","epicVideoInfosPromise","getEpicVideoInfos","instructionsEpicVideoEmbeds","h1","ExerciseNumberRoute","firstStepNumber","String","instructionsCode","EpicVideoInfoProvider","Mdx","code","components","ElementScrollRestoration","elementQuery","Exercise404ErrorBoundary","SetPlaygroundSchema","reset","nullable","redirectTo","converseApp","solutionName","problemName","setPlayground","getErrorMessage","forceFresh","getDiffCode","SetPlayground","tooltipText","buttonProps","submitButton","PlaygroundChooser","allApps","Select","Root","onValueChange","Trigger","Value","placeholder","Portal","Content","position","align","ScrollUpButton","Viewport","Group","Label","SelectItem","ScrollDownButton","Item","ItemText","ItemIndicator","SetAppToPlayground","isOutdated","withParam","splitCookieName","computeSplitPercent","input","defaultValue","isFinite","min","max","pageTitle","exerciseStepApp","emoji","cacheOptions","allAppsFull","problemApp","solutionApp","getExerciseApp","reqUrl","pathnameParam","searchParams","delete","errorData","getStep404Data","requireExerciseApp","playgroundApp","getStepId","getStepNameAndId","exerciseNumberStr","stepNumberStr","stepName","stepId","ar","findIndex","getAppDisplayName","exerciseId","exerciseIndex","step","nextApp","prevApp","requireExercise","getNextExerciseApp","getPrevExerciseApp","exerciseApps","isLastStep","isFirstStep","subroute","cookieHeader","rawSplit","splitPercent","epicVideoEmbeds","prevStepLink","getAppPageRoute","nextStepLink","isUpToDate","diffFiles","getDiffFiles","ExercisePartRoute","inBrowserBrowserRef","containerRef","leftPaneRef","setSplitPercent","leftWidthPx","setLeftWidthPx","left","ro","ResizeObserver","entries","entry","contentRect","observe","getBoundingClientRect","disconnect","setCookie","percent","clamped","startDrag","initialClientX","container","rect","dragging","iframes","querySelectorAll","originalPointerEvents","el","pointerEvents","forEach","handleMove","clientX","cleanup","relativeX","onMouseMove","buttons","onTouchMove","firstTouch","touches","body","cursor","userSelect","titleBits","StepMdx","TouchedFiles","diffFilesPromise","NavChevrons","next","role","onMouseDown","onDoubleClick","onTouchStart","context","startApp","invariant","runAppDev","running","appRunningResult","waitOnApp","errorMessage","statusText","stopApp","closeProcess","stopPort","AppStopper","inFlightIntent","inFlightState","PortStopper","AppStarter","Loading","isRunning","portIsAvailable","getAppRunningState","appInfo","stackBlitzUrl","TestsList","Preview","diff","testActionSchema","testEventSchema","exitCode","boolean","output","timestamp","testEventQueueSchema","processEntry","getTestProcessEntry","eventStream","signal","setup","send","queue","sendEvent","interval","setInterval","isTestRunning","testProcess","process","handleStdOutData","handleStdErrData","handleExit","stdout","off","stderr","on","clearInterval","runAppTests","kill","clearTestProcessEntry","simpleReducer","getNext","TestOutput","dispatch","useReducer","version","lines","revalidator","useRevalidator","latestRevalidatorRef","ansi","useAnsiToHtml","lastMessage","useEventSource","parsed","revalidate","TestRunner","onRun","AnimatedBars","StopTest","ClearTest","onClear","toHtml","stripCursorMovements","latestOnRun","latestOnClear","onStop","latestOnStop","app1Name","app2Name","app1","app2","getDiffProp","diffCode","discordPostsPromise","fetchDiscordPosts","userHasAccessPromise","userHasAccessToExerciseStep","getTestState","tabs","isValidPreview","newSearchParams","set","useOutletContext","useSearchParams","preview","navigate","useNavigate","shouldHideTab","tab","devType","discordChannelId","getTabStatus","testExitCode","appData","activeTab","altDiffUrl","handleDiffTabClick","ctrlKey","shiftKey","metaKey","Tabs","List","preventScrollReset","StatusIndicator","forceMount","Playground","problemAppName","Tests","Diff","DiscordChat","TestUI","playgroundAppInfo","exerciseFormTemplate","forms","exerciseFormEmbedUrl","encodeURIComponent","nextExercise","finishedFilepath","finishedEpicVideoEmbeds","exerciseFinished","ExerciseFinished","finishedCode","Survey","iframeLoaded","setIframeLoaded","onLoad","onError","colorScheme","compiledFinished","getWorkshopFinished","lastExercises","workshopFormTemplate","workshop","workshopFormEmbedUrl","compiled","workshopFinished","workshopReadme","getWorkshopInstructions","ExerciseListItem","Index","exerciseLinks","lastExercise","lastStep","LastExerciseRedirect","CodeReceivedEventSchema","EVENTS","USER_CODE_RECEIVED","AuthResolvedEventSchema","AUTH_RESOLVED","AuthRejectedEventSchema","AUTH_REJECTED","default","EventSchema","handleCodeReceived","handleAuthResolved","handleAuthRejected","authEmitter","isAuthenticated","getAuthInfo","registerDevice","Login","loginFetcher","clickedVerificationLink","setClickedVerificationLink","authError","setAuthError","userCodeInfo","setUserCodeInfo","ButtonLink","optOutPresence","persistPlayground","dismissExerciseWarning","persist","AccountSettings","fontSizePreference","presencePreferences","playgroundPreferences","exerciseWarningPreferences","isSubmitting","htmlFor","defaultChecked","disabled","Support","repoGroups","match","groups","repoUrl","repoIssuesUrl","org","repo","WorkspaceStructure","AdminLayout","currentWorkshopId","EPICSHOP_WORKSHOP_INSTANCE_ID","allWorkshopCaches","getAllWorkshopCaches","globalCaches","getGlobalCaches","allCaches","filterQuery","availableWorkshopIds","w","workshopId","globalDirExists","globalCacheDirectoryExists","selectedWorkshops","filteredCaches","workshopCache","caches","cache","toLowerCase","availableWorkshops","ActionSchema","discriminatedUnion","cacheName","newValue","fromEntries","deleteCacheEntry","deleteWorkshopCache","parsedValue","updateCacheEntry","WorkshopChooser","setSearchParams","handleWorkshopChange","checked","newSelected","onChange","SearchFilter","inputValue","setInputValue","inputRef","handleSearch","query","handleClear","IconButton","InlineEntryEditor","currentValue","entryKey","editValue","setEditValue","hasChanges","setHasChanges","handleSave","handleChange","handleReset","SkippedFilesSection","skippedFiles","skippedFile","formatFileSize","DoubleCheckButton","onConfirm","CacheManagement","deleteEntry","totalSize","sum","skippedSize","grandTotal","CacheMetadata","metadata","iconButtonClassName","useDayjs","expirationTime","calculateExpirationTime","createdDate","createdTime","timeRemaining","formatTimeRemaining","isExpired","isExpiringSoon","format","ClientOnly","fromNow","ttl","swr","doubleCheck","useDoubleCheck","getButtonProps","readEntryByPath","db","readDb","loadJSON","DbRoute","processes","testProcesses","color","getProcesses","devProcesses","pid","inspectorRunning","isInspectorRunning","clearData","clearCaches","startInspector","stopInspector","sortProgress","linkProgress","epicProgress","isStartingInspector","isStoppingInspector","progressStatus","completed","incomplete","Card","CardHeader","CardTitle","CardDescription","CardContent","epicLessonUrl","DoubleCheckAdminButton","doubleCheckClassName","AdminButton","Pinger","backgroundColor","colors","pinger","circle","starting","stopped","taken","commitInfo","latestVersion","getCommitInfo","getLatestWorkshopAppVersion","uptime","startDate","workshopInstanceId","workshopContextCwd","workshopCommit","dateFormatted","date","dateFromNow","latestWorkshopAppVersion","workshopAppVersion","EPICSHOP_APP_VERSION","startTime","startTimeFormatted","startTimeFromNow","Version","githubRepo","hash","usingDefaultApp1","at","app1Index","prevApp1Index","prevApp2Index","nextApp1Index","nextApp2Index","prevApp1","prevApp2","nextApp1","nextApp2","prevSearchParams","nextSearchParams","prevLink","nextLink","DiffViewer","paramsWithForcedRefresh","isNavigating","shortcut","makeId","pad","videoUrl","videoInfos","EpicVideoEmbedRoute","rootRef","finally","parent","postMessage","clientHeight","clientWidth","payload","handleLinksClick","HTMLAnchorElement","stopPropagation","isLocal","sendMcpMessage","toolName","workshopDirectory","onClickCapture","DeferredEpicVideo","WIDTH","HEIGHT","urlPathname","logo","element","OgLayout","productLogo","productDisplayName","display","flexDirection","justifyContent","alignItems","padding","textWrap","textAlign","renderHtml","renderToStaticMarkup","debug","ogImg","cachified","timingKey","ogCache","staleWhileRevalidate","getFreshValue","getOgImg","svg","satori","fonts","getFont","font","flat","loadAdditionalAsset","segment","getEmoji","base64","resvg","Resvg","pngData","render","asPng","emojiCode","emojiToCodePoints","emojiUrl","response","fetch","codePoints","codePoint","codePointAt","weights","weightsString","fetchUrl","css","resource","matchAll","arrayBuffer","buffer","weight","protocolFreeDomain","fontFamily","top","right","bottom","objectFit","gap","avatar","borderRadius","margin","fontWeight","SENTRY_HOST","SENTRY_DSN","SENTRY_PROJECT_IDS","SENTRY_PROJECT_ID","envelope","piece","header","dsn","projectId","upstreamSentryURL","generateRobotsTxt","serverBuild","generateSitemap","routes","siteUrl"],"mappings":"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EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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"}