@epic-web/workshop-app 6.23.2 → 6.23.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.
- package/build/client/assets/{index-BQT6Cv4C.js → index-D4FRh1nQ.js} +2 -2
- package/build/client/assets/index-D4FRh1nQ.js.map +1 -0
- package/build/client/assets/{manifest-5865a9d7.js → manifest-8a795ec6.js} +1 -1
- package/build/server/index.js +6 -3
- package/build/server/index.js.map +1 -1
- package/package.json +3 -3
- package/build/client/assets/index-BQT6Cv4C.js.map +0 -1
|
@@ -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/extended-theme.ts","../../app/utils/misc.tsx","../../app/components/error-boundary.tsx","../../app/components/exercise-warning-banner.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/request-info.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/ui/dialog.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/components/apps.tsx","../../app/utils/launch-editor.server.ts","../../app/routes/launch-editor.tsx","../../app/components/mermaid.tsx","../../app/utils/mdx.tsx","../../app/routes/_app+/exercise+/$exerciseNumber.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.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/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+/admin-utils.server.tsx","../../app/routes/admin+/index.tsx","../../app/routes/admin+/version.tsx","../../app/routes/apps.tsx","../../app/routes/diff.tsx","../../app/routes/exercises.tsx","../../app/routes/og.tsx","../../app/routes/onboarding.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 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 { 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 function handleError(\n\terror: unknown,\n\t{ request }: LoaderFunctionArgs | ActionFunctionArgs,\n): void {\n\tif (request.signal.aborted) return\n\tif (ENV.EPICSHOP_IS_PUBLISHED) {\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 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\tlocation: z\n\t\t.object({\n\t\t\tworkshopTitle: z.string().nullable().optional(),\n\t\t\torigin: z.string().nullable().optional(),\n\t\t\texercise: z\n\t\t\t\t.object({\n\t\t\t\t\ttype: z\n\t\t\t\t\t\t.union([z.literal('problem'), z.literal('solution')])\n\t\t\t\t\t\t.nullable()\n\t\t\t\t\t\t.optional(),\n\t\t\t\t\texerciseNumber: z.number().nullable().optional(),\n\t\t\t\t\tstepNumber: z.number().nullable().optional(),\n\t\t\t\t})\n\t\t\t\t.nullable()\n\t\t\t\t.optional(),\n\t\t})\n\t\t.nullable()\n\t\t.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","import {\n\tcachified,\n\tmakeSingletonCache,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getAuthInfo, getPreferences } from '@epic-web/workshop-utils/db.server'\nimport {\n\tgetUserInfo,\n\tuserHasAccessToWorkshop,\n} from '@epic-web/workshop-utils/epic-api.server'\nimport { type Timings } from '@epic-web/workshop-utils/timing.server'\nimport { getUserId } from '@epic-web/workshop-utils/user.server'\nimport { PresenceSchema, partykitBaseUrl, type User } from './presence.js'\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\n\tif (preferences?.presence.optOut || !userId) {\n\t\treturn uniqueUsers(users.filter((u) => u.id !== userId))\n\t} else {\n\t\tconst user: User = { id: userId }\n\t\tconst config = getWorkshopConfig()\n\t\tconst url = request ? new URL(request.url) : undefined\n\t\tuser.location = {\n\t\t\tworkshopTitle: config.title,\n\t\t\torigin: url ? url.origin : undefined,\n\t\t}\n\t\tif (url) {\n\t\t\tif (url.pathname.startsWith('/exercise/')) {\n\t\t\t\tconst [exerciseNumber, stepNumber, type] = url.pathname\n\t\t\t\t\t.split('/')\n\t\t\t\t\t.slice(2)\n\t\t\t\tuser.location.exercise = {\n\t\t\t\t\texerciseNumber: isNaN(Number(exerciseNumber))\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: Number(exerciseNumber),\n\t\t\t\t\tstepNumber: isNaN(Number(stepNumber)) ? null : Number(stepNumber),\n\t\t\t\t\ttype:\n\t\t\t\t\t\ttype === 'problem'\n\t\t\t\t\t\t\t? 'problem'\n\t\t\t\t\t\t\t: type === 'solution'\n\t\t\t\t\t\t\t\t? 'solution'\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (authInfo) {\n\t\t\tconst [userInfo, hasAccess] = await Promise.all([\n\t\t\t\tgetUserInfo({ request, timings }),\n\t\t\t\tuserHasAccessToWorkshop({ request, timings }),\n\t\t\t])\n\n\t\t\tObject.assign(user, {\n\t\t\t\tname: userInfo?.name,\n\t\t\t\tavatarUrl: userInfo?.imageUrlLarge,\n\t\t\t\timageUrlSmall: userInfo?.imageUrlSmall,\n\t\t\t\timageUrlLarge: userInfo?.imageUrlLarge,\n\t\t\t\thasAccess,\n\t\t\t})\n\t\t}\n\n\t\treturn uniqueUsers([...users, user])\n\t}\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| '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\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 Config } from 'tailwindcss'\n\nconst removeProseMargin = {\n\t'> ul > li > *:first-child': {\n\t\tmarginTop: 'unset',\n\t},\n\t'> ul > li > *:last-child': {\n\t\tmarginBottom: 'unset',\n\t},\n\t'> ol > li > *:first-child': {\n\t\tmarginTop: 'unset',\n\t},\n\t'> ol > li > *:last-child': {\n\t\tmarginBottom: 'unset',\n\t},\n}\n\nconst removeCodeBackticks = {\n\t'code::before': {\n\t\tcontent: 'none',\n\t},\n\t'code::after': {\n\t\tcontent: 'none',\n\t},\n}\n\nconst proseColors = {\n\t'*': {\n\t\tcolor: 'hsl(var(--foreground))',\n\t},\n}\n\nexport const extendedTheme = {\n\ttypography: {\n\t\tDEFAULT: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\tsm: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\tbase: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\tlg: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\txl: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\t'2xl': { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t},\n\tcolors: {\n\t\tgray: {\n\t\t\t'50': '#fafafa',\n\t\t\t'100': '#f5f5f5',\n\t\t\t'200': '#e5e5e5',\n\t\t\t'300': '#d4d4d4',\n\t\t\t'400': '#a3a3a3',\n\t\t\t'500': '#737373',\n\t\t\t'600': '#525252',\n\t\t\t'700': '#404040',\n\t\t\t'800': '#262626',\n\t\t\t'900': '#171717',\n\t\t\t'950': '#0a0a0a',\n\t\t},\n\t\tborder: 'hsl(var(--border))',\n\t\tinput: 'hsl(var(--input))',\n\t\tring: 'hsl(var(--ring))',\n\t\tbackground: 'hsl(var(--background))',\n\t\thighlight: 'hsl(var(--highlight))',\n\t\tforeground: 'hsl(var(--foreground))',\n\t\t'foreground-destructive': 'hsl(var(--foreground-destructive))',\n\t\tscrollbar: 'var(--scrollbar)',\n\t\tprimary: {\n\t\t\tDEFAULT: 'hsl(var(--primary))',\n\t\t\tforeground: 'hsl(var(--primary-foreground))',\n\t\t},\n\t\tsecondary: {\n\t\t\tDEFAULT: 'hsl(var(--secondary))',\n\t\t\tforeground: 'hsl(var(--secondary-foreground))',\n\t\t},\n\t\tdestructive: {\n\t\t\tDEFAULT: 'hsl(var(--destructive))',\n\t\t\tforeground: 'hsl(var(--destructive-foreground))',\n\t\t},\n\t\tmuted: {\n\t\t\tDEFAULT: 'hsl(var(--muted))',\n\t\t\tforeground: 'hsl(var(--muted-foreground))',\n\t\t},\n\t\taccent: {\n\t\t\tDEFAULT: 'hsl(var(--accent))',\n\t\t\tforeground: 'hsl(var(--accent-foreground))',\n\t\t},\n\t\tpopover: {\n\t\t\tDEFAULT: 'hsl(var(--popover))',\n\t\t\tforeground: 'hsl(var(--popover-foreground))',\n\t\t},\n\t\tcard: {\n\t\t\tDEFAULT: 'hsl(var(--card))',\n\t\t\tforeground: 'hsl(var(--card-foreground))',\n\t\t},\n\t},\n\tborderRadius: {\n\t\tlg: `var(--radius)`,\n\t\tmd: `calc(var(--radius) - 2px)`,\n\t\tsm: 'calc(var(--radius) - 4px)',\n\t},\n\tfontSize: {\n\t\t// 1rem = 16px\n\t\t/** 80px size / 84px high / bold */\n\t\tmega: ['5rem', { lineHeight: '5.25rem', fontWeight: '700' }],\n\t\t/** 56px size / 62px high / bold */\n\t\th1: ['3.5rem', { lineHeight: '3.875rem', fontWeight: '700' }],\n\t\t/** 40px size / 48px high / bold */\n\t\th2: ['2.5rem', { lineHeight: '3rem', fontWeight: '700' }],\n\t\t/** 32px size / 36px high / bold */\n\t\th3: ['2rem', { lineHeight: '2.25rem', fontWeight: '700' }],\n\t\t/** 28px size / 36px high / bold */\n\t\th4: ['1.75rem', { lineHeight: '2.25rem', fontWeight: '700' }],\n\t\t/** 24px size / 32px high / bold */\n\t\th5: ['1.5rem', { lineHeight: '2rem', fontWeight: '700' }],\n\t\t/** 16px size / 20px high / bold */\n\t\th6: ['1rem', { lineHeight: '1.25rem', fontWeight: '700' }],\n\n\t\t/** 48px size / 52px high / normal */\n\t\t'body-5xl': ['3rem', { lineHeight: '3.25rem' }],\n\t\t/** 40px size / 44px high / normal */\n\t\t'body-4xl': ['2.5rem', { lineHeight: '2.75rem' }],\n\t\t/** 36px size / 40px high / normal */\n\t\t'body-3xl': ['2.25rem', { lineHeight: '2.5rem' }],\n\t\t/** 32px size / 36px high / normal */\n\t\t'body-2xl': ['2rem', { lineHeight: '2.25rem' }],\n\t\t/** 28px size / 36px high / normal */\n\t\t'body-xl': ['1.75rem', { lineHeight: '2.25rem' }],\n\t\t/** 24px size / 32px high / normal */\n\t\t'body-lg': ['1.5rem', { lineHeight: '2rem' }],\n\t\t/** 20px size / 28px high / normal */\n\t\t'body-md': ['1.25rem', { lineHeight: '1.75rem' }],\n\t\t/** 16px size / 20px high / normal */\n\t\t'body-sm': ['1rem', { lineHeight: '1.25rem' }],\n\t\t/** 14px size / 18px high / normal */\n\t\t'body-xs': ['0.875rem', { lineHeight: '1.125rem' }],\n\t\t/** 12px size / 16px high / normal */\n\t\t'body-2xs': ['0.75rem', { lineHeight: '1rem' }],\n\n\t\t/** 18px size / 24px high / semibold */\n\t\tcaption: ['1.125rem', { lineHeight: '1.5rem', fontWeight: '600' }],\n\t\t/** 12px size / 16px high / bold */\n\t\tbutton: ['0.75rem', { lineHeight: '1rem', fontWeight: '700' }],\n\t},\n\tkeyframes: {\n\t\t'accordion-down': {\n\t\t\tfrom: { height: '0' },\n\t\t\tto: { height: 'var(--radix-accordion-content-height)' },\n\t\t},\n\t\t'accordion-up': {\n\t\t\tfrom: { height: 'var(--radix-accordion-content-height)' },\n\t\t\tto: { height: '0' },\n\t\t},\n\t},\n\tanimation: {\n\t\t'accordion-down': 'accordion-down 0.2s ease-out',\n\t\t'accordion-up': 'accordion-up 0.2s ease-out',\n\t},\n} satisfies Config['theme']\n","import { type ExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport slugify from '@sindresorhus/slugify'\nimport { clsx, type ClassValue } from 'clsx'\nimport * as React from 'react'\nimport { useEffect, 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'\nimport { extendedTheme } from './extended-theme.ts'\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\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 left-0 top-1/2 -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\nfunction formatColors() {\n\tconst colors = []\n\tfor (const [key, color] of Object.entries(extendedTheme.colors)) {\n\t\tif (typeof color === 'string') {\n\t\t\tcolors.push(key)\n\t\t} else {\n\t\t\tconst colorGroup = Object.keys(color).map((subKey) =>\n\t\t\t\tsubKey === 'DEFAULT' ? '' : subKey,\n\t\t\t)\n\t\t\tcolors.push({ [key]: colorGroup })\n\t\t}\n\t}\n\treturn colors\n}\n\nconst customTwMerge = extendTailwindMerge({\n\textend: {\n\t\ttheme: {\n\t\t\tcolors: formatColors(),\n\t\t\tborderRadius: Object.keys(extendedTheme.borderRadius),\n\t\t},\n\t\tclassGroups: {\n\t\t\t'font-size': [{ text: Object.keys(extendedTheme.fontSize) }],\n\t\t\tanimate: [{ animate: Object.keys(extendedTheme.animation) }],\n\t\t},\n\t},\n})\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? undefined\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\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","// 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 } 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\nexport function GeneralErrorBoundary({\n\tdefaultStatusHandler = ({ error }) => (\n\t\t<p>\n\t\t\t{error.status} {error.data}\n\t\t</p>\n\t),\n\tstatusHandlers,\n\tunexpectedErrorHandler = (error) => <p>{getErrorMessage(error)}</p>,\n}: {\n\tdefaultStatusHandler?: StatusHandler\n\tstatusHandlers?: Record<number, StatusHandler>\n\tunexpectedErrorHandler?: (error: unknown) => React.ReactNode | null\n}) {\n\tconst error = useRouteError()\n\tconst params = useParams()\n\tconst isResponse = isRouteErrorResponse(error)\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\tif (typeof document !== 'undefined') {\n\t\tconsole.error(error)\n\t}\n\n\treturn (\n\t\t<div className=\"container flex items-center justify-center p-20 text-h2\">\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=\"fixed left-0 right-0 top-0 z-50 border-b border-destructive bg-destructive\">\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=\"container relative z-0 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=\"h-5 w-5 text-destructive-foreground\"\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-sm font-semibold text-destructive-foreground\">\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-xs text-destructive-foreground/80\">\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=\"flex items-center gap-2 text-xs text-destructive-foreground\">\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 { 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 left-0 top-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'h-full w-0 bg-highlight 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'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md 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',\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 { useRouteLoaderData } from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\n\n/**\n * @returns the request info from the root loader\n */\nexport function useRequestInfo() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\n\treturn data.requestInfo\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 './request-info.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-[10px] text-foreground-destructive\">\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\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\nexport function dataWithPE<Data>(\n\tformData: FormData,\n\t...args: Parameters<typeof data<Data>>\n) {\n\tensureProgressiveEnhancement(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.js'\nimport { useRequestInfo } from '#app/utils/request-info.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(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 './request-info.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, useRouteLoaderData } from 'react-router'\nimport { z } from 'zod'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { useIsOnline } from './online.ts'\nimport { useRequestInfo } from './request-info.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 = useRouteLoaderData('root') as RootLoaderData\n\treturn data?.preferences?.presence ?? null\n}\n\nexport function useOptionalWorkshopTitle() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\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 useUsersLocation() {\n\tconst workshopTitle = useOptionalWorkshopTitle()\n\tconst requestInfo = useRequestInfo()\n\tconst rawParams = useParams()\n\tconst paramsResult = ExerciseAppParamsSchema.safeParse(rawParams)\n\tconst params = paramsResult.success ? paramsResult.data : null\n\n\treturn {\n\t\tworkshopTitle,\n\t\torigin: requestInfo.origin,\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 {\n\t\tuserHasAccess = false,\n\t\tuserId,\n\t\tpresence,\n\t} = (useRouteLoaderData('root') as RootLoaderData) ?? {}\n\tconst [users, setUsers] = useState(presence?.users ?? [])\n\tconst usersLocation = useUsersLocation()\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\tlet message: Message | null = null\n\tif (user) {\n\t\tif (prefs?.optOut) {\n\t\t\tmessage = { type: 'remove-user', payload: { id: user.id } }\n\t\t} else {\n\t\t\tmessage = {\n\t\t\t\ttype: 'add-user',\n\t\t\t\tpayload: {\n\t\t\t\t\tid: user.id,\n\t\t\t\t\tname: user.name,\n\t\t\t\t\thasAccess: userHasAccess,\n\t\t\t\t\timageUrlSmall: user.imageUrlSmall,\n\t\t\t\t\timageUrlLarge: user.imageUrlLarge,\n\t\t\t\t\tlocation: usersLocation,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t} else if (userId?.id) {\n\t\tmessage = {\n\t\t\ttype: 'add-user',\n\t\t\tpayload: { id: userId.id, location: usersLocation },\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\nfunction scoreUsers(\n\tuser: { id?: string | null; location: User['location'] },\n\tusers: Array<User>,\n) {\n\tconst { location } = user\n\tconst scoredUsers = users.map((user) => {\n\t\tlet score = 0\n\t\tconst available = 5\n\t\tif (user.hasAccess) {\n\t\t\tscore += 1\n\t\t}\n\t\tif (location?.workshopTitle === user.location?.workshopTitle) {\n\t\t\tscore += 1\n\t\t\tif (\n\t\t\t\tlocation?.exercise?.exerciseNumber &&\n\t\t\t\tlocation.exercise.exerciseNumber ===\n\t\t\t\t\tuser.location?.exercise?.exerciseNumber\n\t\t\t) {\n\t\t\t\tscore += 1\n\t\t\t\tif (\n\t\t\t\t\tlocation.exercise.stepNumber &&\n\t\t\t\t\tlocation.exercise.stepNumber === user.location.exercise.stepNumber\n\t\t\t\t) {\n\t\t\t\t\tscore += 1\n\t\t\t\t\tif (\n\t\t\t\t\t\tlocation.exercise.type &&\n\t\t\t\t\t\tlocation.exercise.type === user.location.exercise.type\n\t\t\t\t\t) {\n\t\t\t\t\t\tscore += 1\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { user, score: Math.floor((score / available) * 10) / 10 }\n\t})\n\treturn scoredUsers.sort((a, b) => {\n\t\tif (a.user.id === user?.id) return -1\n\t\tif (b.user.id === user?.id) return 1\n\t\tif (a.score === b.score) return 0\n\t\treturn a.score > b.score ? -1 : 1\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 } = (useRouteLoaderData('root') as RootLoaderData) ?? {}\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 { createId as cuid } from '@paralleldrive/cuid2'\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\tgetPreferences,\n\treadOnboardingData,\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 { checkConnectionCached } from '@epic-web/workshop-utils/utils.server'\n\nimport {\n\tdata,\n\tredirect,\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 { 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 = ({ data }) => {\n\tif (!data) return []\n\n\treturn getSeoMetaTags({\n\t\tinstructor: data.instructor,\n\t\ttitle: data.workshopTitle,\n\t\tdescription: data.workshopSubtitle,\n\t\trequestInfo: data.requestInfo,\n\t})\n}\n\nexport type RootLoaderData = Route.ComponentProps['loaderData']\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\tonboardingVideo,\n\t} = workshopConfig\n\n\tconst onboarding = await readOnboardingData()\n\tif (\n\t\t!ENV.EPICSHOP_DEPLOYED &&\n\t\t!onboarding?.tourVideosWatched.includes(onboardingVideo)\n\t) {\n\t\tif (new URL(request.url).pathname !== '/onboarding') {\n\t\t\tthrow redirect('/onboarding')\n\t\t}\n\t}\n\tconst theme = getTheme(request)\n\tconst { confettiId, headers: confettiHeaders } = getConfetti(request)\n\tconst { toast, headers: toastHeaders } = await getToast(request)\n\tconst isOnlinePromise = checkConnectionCached({ 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})\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\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'antialiased h-screen-safe',\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</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=\"whitespace-pre-wrap break-all text-body-lg\">\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 { useRouteLoaderData } from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\n\nexport function useWorkshopConfig() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\n\tif (!data?.workshopConfig) {\n\t\tthrow new Error('useWorkshopConfig requires a workshopConfig.')\n\t}\n\treturn data.workshopConfig\n}\n","import { useTheme } from '#app/routes/theme/index.js'\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/request-info.js'\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 * 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'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\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'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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%] 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=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity data-[state=open]:bg-accent data-[state=open]:text-muted-foreground hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 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 font-semibold leading-none 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-sm text-muted-foreground', 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 { useRouteLoaderData } from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\n\nexport function useOptionalUser() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\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 = useRouteLoaderData('root') as RootLoaderData\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 = useRouteLoaderData('root') as RootLoaderData\n\treturn data?.userHasAccess ?? false\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\tuseRouteLoaderData,\n\ttype ActionFunctionArgs,\n} from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { createConfettiHeaders } from '#app/utils/confetti.server.ts'\nimport { combineHeaders, ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.js'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nexport function useEpicProgress() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\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(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=\"absolute right-0 h-20 w-20 rounded-full bg-foreground/20\"\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'duration-100 group-hover:bg-background': !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.js'\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTrigger,\n} from '#app/components/ui/dialog.js'\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.js'\nimport { cn, getExercisePath, getExerciseStepPath } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { usePresence, type User } 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 locationLabel = getLocationLabel(user.location)\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 = user.location?.origin?.includes('localhost')\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>\n\t\t\t\t\t\t\t\t\t{imageUrl ? (\n\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\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\tclassName={cn(\n\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\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\tsrc={imageUrl}\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<div\n\t\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\t\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\t\tclassName={cn(\n\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\tscoreClassNames,\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<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t)}\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>\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{locationLabel\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{locationLabel?.line1 ? (\n\t\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line1}</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t{locationLabel?.line2 ? (\n\t\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line2}</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\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>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\ttabIndex={0}\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'flex items-center justify-center rounded-full border bg-accent text-xs text-accent-foreground',\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-ellipsis whitespace-nowrap text-center',\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\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 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-gradient-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=\"flex w-full flex-grow flex-col justify-between overflow-x-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar\"\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 whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap px-2 py-0.5 pr-3 outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"ml-4 mt-2 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'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"font-semibold leading-tight\"\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=\"ml-3 mt-0.5 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 whitespace-nowrap px-2 py-0.5 pr-3 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:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap px-2 py-0.5 pr-3 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:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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'relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap text-lg font-bold 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'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"flex-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 flex-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=\"flex-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=\"flex-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=\"flex flex-grow flex-col justify-between overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar\"\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 whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap px-2 py-0.5 pr-3 outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"ml-4 mt-2 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'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"font-semibold leading-tight\"\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=\"ml-3 mt-0.5 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 whitespace-nowrap px-2 py-0.5 pr-3 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:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap px-2 py-0.5 pr-3 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:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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'relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap text-lg font-bold 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'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 flex-grow flex-col justify-center\">\n\t\t\t\t\t\t\t<div className=\"orientation-sideways w-full font-mono text-sm font-medium uppercase leading-none\">\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 flex-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=\"flex-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=\"flex-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 pl-3 pt-[15px]\">\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 flex-shrink-0 items-center justify-between overflow-hidden border-r sm:w-full sm:border-b sm:border-r-0',\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 whitespace-nowrap font-mono text-sm 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'\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 w-fit border-2 border-foreground bg-foreground\">\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 w-fit border-2 border-foreground bg-foreground\">\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","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.js'\nimport { useOptionalDiscordMember, useUser } from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { 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\n\treturn (\n\t\t<main className=\"container flex h-full w-full max-w-3xl flex-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=\"flex-shrink-0\" size=\"lg\" />\n\t\t\t)}\n\t\t\t<h1 className=\"mb-1 text-2xl\">Your Account</h1>\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=\"/onboarding\" className=\"underline\">\n\t\t\t\t\t\tReview onboarding\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\tconst url = new URL(request.headers.get('referer') ?? '')\n\tconst appName = url.pathname.split('/').pop()\n\treturn appName\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\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 flex-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\tuseRouteLoaderData,\n} from 'react-router'\nimport { z } from 'zod'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { useDebounce } from '#app/utils/misc.tsx'\nimport './mux-player.css'\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 data = useRouteLoaderData('root') as RootLoaderData\n\treturn data?.preferences?.player ?? null\n}\n\ntype MuxPlayerProps = React.ComponentProps<typeof RealMuxPlayer>\n\nconst ignoredInputs = [\n\t'INPUT',\n\t'SELECT',\n\t'BUTTON',\n\t'TEXTAREA',\n\t'MUX-PLAYER',\n\t'SUMMARY',\n]\n\nconst ignoredRoles = ['button', 'option', 'combobox', 'tab', 'tablist']\n\nfunction shouldIgnoreHotkey(el: unknown) {\n\tlet current = el\n\twhile (current) {\n\t\tif (!(current instanceof HTMLElement)) return false\n\n\t\tconst isIgnored =\n\t\t\tignoredInputs.includes(current.tagName) ||\n\t\t\tignoredRoles.includes(current.getAttribute('role') || '') ||\n\t\t\tcurrent.isContentEditable\n\t\tif (isIgnored) return true\n\t\tcurrent = current.parentElement\n\t}\n\n\treturn false\n}\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\tReact.useEffect(() => {\n\t\tfunction handleUserKeyPress(e: KeyboardEvent) {\n\t\t\tif (!muxPlayerRef.current) return\n\t\t\tconst activeElement = document.activeElement\n\n\t\t\tif (shouldIgnoreHotkey(activeElement)) return\n\t\t\tif (shouldIgnoreHotkey(e.target)) return\n\n\t\t\tif (e.key === ' ') {\n\t\t\t\te.preventDefault()\n\t\t\t\tif (muxPlayerRef.current.paused) {\n\t\t\t\t\t// Only attempt to play if metadata is loaded to avoid AbortError\n\t\t\t\t\tif (metadataLoaded) {\n\t\t\t\t\t\tvoid muxPlayerRef.current.play().catch(() => {})\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tmuxPlayerRef.current.pause()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (e.key === 'ArrowRight') {\n\t\t\t\te.preventDefault()\n\t\t\t\tmuxPlayerRef.current.currentTime =\n\t\t\t\t\tmuxPlayerRef.current.currentTime +\n\t\t\t\t\t(muxPlayerRef.current.forwardSeekOffset || 10)\n\t\t\t}\n\t\t\tif (e.key === 'ArrowLeft') {\n\t\t\t\te.preventDefault()\n\t\t\t\tmuxPlayerRef.current.currentTime =\n\t\t\t\t\tmuxPlayerRef.current.currentTime -\n\t\t\t\t\t(muxPlayerRef.current.forwardSeekOffset || 10)\n\t\t\t}\n\t\t\tif (e.key === 'f' && !e.metaKey && !e.ctrlKey) {\n\t\t\t\te.preventDefault()\n\t\t\t\tvoid (document.fullscreenElement\n\t\t\t\t\t? document.exitFullscreen()\n\t\t\t\t\t: muxPlayerRef.current.requestFullscreen())\n\t\t\t}\n\t\t}\n\t\twindow.document.addEventListener('keydown', handleUserKeyPress)\n\t\treturn () => {\n\t\t\twindow.document.removeEventListener('keydown', handleUserKeyPress)\n\t\t}\n\t}, [muxPlayerRef, metadataLoaded])\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, 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://twitter.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\tonLoadedMetadata={() => setMetadataLoaded(true)}\n\t\t\t\tminResolution={getMinResolutionValue(playerPreferences?.minResolution)}\n\t\t\t\tmaxResolution={getMaxResolutionValue(playerPreferences?.maxResolution)}\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 'EpicWeb.dev 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 'EpicWeb.dev Video'\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 flex-shrink-0 shadow-lg\">\n\t\t\t\t<div className=\"not-prose absolute inset-0 z-10 flex items-center justify-center p-8 text-foreground-destructive\">\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 flex-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({ url, title }: { url: string; title: string }) {\n\treturn (\n\t\t<a\n\t\t\thref={url}\n\t\t\ttarget=\"_blank\"\n\t\t\tclassName=\"flex items-center gap-1 text-base no-underline opacity-70 transition hover:underline hover:opacity-100\"\n\t\t\trel=\"noreferrer\"\n\t\t>\n\t\t\t<Icon className=\"flex-shrink-0\" name=\"Video\" size=\"lg\" />\n\t\t\t{title} <span aria-hidden>↗︎</span>\n\t\t</a>\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 = (\n\t\t<div>\n\t\t\t<VideoLink url={url} title={title} />\n\t\t</div>\n\t)\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/>\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}: {\n\turl: string\n\ttitle?: string\n\tmuxPlaybackId: string\n\ttranscript: string\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={timestampIndexStart}>{textBeforeTimestamp}</span>,\n\t\t)\n\t\ttranscriptElements.push(\n\t\t\t<button\n\t\t\t\tkey={timestamp}\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 url={urlString} title={title} />\n\t\t\t\t<details>\n\t\t\t\t\t<summary>Transcript</summary>\n\t\t\t\t\t<div className=\"whitespace-pre-line rounded-md bg-accent p-2 text-accent-foreground\">\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 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 (url.host === 'www.epicai.pro') {\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 { useRouteLoaderData } from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\n\nexport function useApps() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\n\tif (!data) {\n\t\tthrow new Error('useApps requires a data object from the root loader')\n\t}\n\treturn data.apps\n}\n","// copied (and barely modified) from create-react-app:\n// https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7/packages/react-dev-utils/launchEditor.js\n\nimport child_process from 'child_process'\nimport fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport { getRelativePath } from '@epic-web/workshop-utils/apps.server'\nimport fsExtra from 'fs-extra'\nimport shellQuote from 'shell-quote'\n\nfunction readablePath(filePath: string = '') {\n\tconst relative = getRelativePath(filePath)\n\tconst name = path.basename(relative)\n\tconst dir = path.dirname(relative)\n\treturn `'${name}' from:\\n'${dir}'`\n}\n\nfunction isTerminalEditor(editor: string) {\n\tswitch (editor) {\n\t\tcase 'vim':\n\t\tcase 'emacs':\n\t\tcase 'nano':\n\t\t\treturn true\n\t}\n\treturn false\n}\n\n// Map from full process name to binary that starts the process\n// We can't just re-use full process name, because it will spawn a new instance\n// of the app every time\nconst COMMON_EDITORS_OSX = {\n\t'/Applications/Atom.app/Contents/MacOS/Atom': 'atom',\n\t'/Applications/Atom Beta.app/Contents/MacOS/Atom Beta':\n\t\t'/Applications/Atom Beta.app/Contents/MacOS/Atom Beta',\n\t'/Applications/Brackets.app/Contents/MacOS/Brackets': 'brackets',\n\t'/Applications/Sublime Text.app/Contents/MacOS/Sublime Text':\n\t\t'/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl',\n\t'/Applications/Sublime Text Dev.app/Contents/MacOS/Sublime Text':\n\t\t'/Applications/Sublime Text Dev.app/Contents/SharedSupport/bin/subl',\n\t'/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2':\n\t\t'/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl',\n\t'/Applications/Cursor.app/Contents/MacOS/Cursor': 'cursor',\n\t'/Applications/Visual Studio Code.app/Contents/MacOS/Electron': 'code',\n\t'/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron':\n\t\t'code-insiders',\n\t'/Applications/VSCodium.app/Contents/MacOS/Electron': 'vscodium',\n\t'/Applications/AppCode.app/Contents/MacOS/appcode':\n\t\t'/Applications/AppCode.app/Contents/MacOS/appcode',\n\t'/Applications/CLion.app/Contents/MacOS/clion':\n\t\t'/Applications/CLion.app/Contents/MacOS/clion',\n\t'/Applications/IntelliJ IDEA.app/Contents/MacOS/idea':\n\t\t'/Applications/IntelliJ IDEA.app/Contents/MacOS/idea',\n\t'/Applications/PhpStorm.app/Contents/MacOS/phpstorm':\n\t\t'/Applications/PhpStorm.app/Contents/MacOS/phpstorm',\n\t'/Applications/PyCharm.app/Contents/MacOS/pycharm':\n\t\t'/Applications/PyCharm.app/Contents/MacOS/pycharm',\n\t'/Applications/PyCharm CE.app/Contents/MacOS/pycharm':\n\t\t'/Applications/PyCharm CE.app/Contents/MacOS/pycharm',\n\t'/Applications/RubyMine.app/Contents/MacOS/rubymine':\n\t\t'/Applications/RubyMine.app/Contents/MacOS/rubymine',\n\t'/Applications/WebStorm.app/Contents/MacOS/webstorm':\n\t\t'/Applications/WebStorm.app/Contents/MacOS/webstorm',\n\t'/Applications/MacVim.app/Contents/MacOS/MacVim': 'mvim',\n\t'/Applications/GoLand.app/Contents/MacOS/goland':\n\t\t'/Applications/GoLand.app/Contents/MacOS/goland',\n\t'/Applications/Rider.app/Contents/MacOS/rider':\n\t\t'/Applications/Rider.app/Contents/MacOS/rider',\n\t'/Applications/Zed/Zed.app/Contents/MacOS/zed': 'zed',\n} as const\n\nconst COMMON_EDITORS_LINUX = {\n\tatom: 'atom',\n\tBrackets: 'brackets',\n\tcursor: 'cursor',\n\tcode: 'code',\n\t'code-insiders': 'code-insiders',\n\tvscodium: 'vscodium',\n\temacs: 'emacs',\n\tgvim: 'gvim',\n\t'idea.sh': 'idea',\n\t'phpstorm.sh': 'phpstorm',\n\t'pycharm.sh': 'pycharm',\n\t'rubymine.sh': 'rubymine',\n\tsublime_text: 'sublime_text',\n\tvim: 'vim',\n\t'webstorm.sh': 'webstorm',\n\t'goland.sh': 'goland',\n\t'rider.sh': 'rider',\n\tzed: 'zed',\n}\n\nconst COMMON_EDITORS_WIN = [\n\t'Brackets.exe',\n\t'Cursor.exe',\n\t'Code.exe',\n\t'Code - Insiders.exe',\n\t'VSCodium.exe',\n\t'atom.exe',\n\t'sublime_text.exe',\n\t'notepad++.exe',\n\t'clion.exe',\n\t'clion64.exe',\n\t'idea.exe',\n\t'idea64.exe',\n\t'phpstorm.exe',\n\t'phpstorm64.exe',\n\t'pycharm.exe',\n\t'pycharm64.exe',\n\t'rubymine.exe',\n\t'rubymine64.exe',\n\t'webstorm.exe',\n\t'webstorm64.exe',\n\t'goland.exe',\n\t'goland64.exe',\n\t'rider.exe',\n\t'rider64.exe',\n\t'zed.exe',\n]\n\n// Transpiled version of: /^([A-Za-z]:[/\\\\])?[\\p{L}0-9/.\\-_\\\\]+$/u\n// Non-transpiled version requires support for Unicode property regex. Allows\n// alphanumeric characters, periods, dashes, slashes, and underscores.\nconst WINDOWS_FILE_NAME_WHITELIST =\n\t/^([A-Za-z]:[/\\\\])?(?:[\\x2D-9A-Z\\\\_a-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u08A0-\\u08B4\\u08B6-\\u08BD\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C60\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C88\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FEF\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7B9\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB65\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]|\\uD800[\\uDC00-\\uDC0B\\uDC0D-\\uDC26\\uDC28-\\uDC3A\\uDC3C\\uDC3D\\uDC3F-\\uDC4D\\uDC50-\\uDC5D\\uDC80-\\uDCFA\\uDE80-\\uDE9C\\uDEA0-\\uDED0\\uDF00-\\uDF1F\\uDF2D-\\uDF40\\uDF42-\\uDF49\\uDF50-\\uDF75\\uDF80-\\uDF9D\\uDFA0-\\uDFC3\\uDFC8-\\uDFCF]|\\uD801[\\uDC00-\\uDC9D\\uDCB0-\\uDCD3\\uDCD8-\\uDCFB\\uDD00-\\uDD27\\uDD30-\\uDD63\\uDE00-\\uDF36\\uDF40-\\uDF55\\uDF60-\\uDF67]|\\uD802[\\uDC00-\\uDC05\\uDC08\\uDC0A-\\uDC35\\uDC37\\uDC38\\uDC3C\\uDC3F-\\uDC55\\uDC60-\\uDC76\\uDC80-\\uDC9E\\uDCE0-\\uDCF2\\uDCF4\\uDCF5\\uDD00-\\uDD15\\uDD20-\\uDD39\\uDD80-\\uDDB7\\uDDBE\\uDDBF\\uDE00\\uDE10-\\uDE13\\uDE15-\\uDE17\\uDE19-\\uDE35\\uDE60-\\uDE7C\\uDE80-\\uDE9C\\uDEC0-\\uDEC7\\uDEC9-\\uDEE4\\uDF00-\\uDF35\\uDF40-\\uDF55\\uDF60-\\uDF72\\uDF80-\\uDF91]|\\uD803[\\uDC00-\\uDC48\\uDC80-\\uDCB2\\uDCC0-\\uDCF2\\uDD00-\\uDD23\\uDF00-\\uDF1C\\uDF27\\uDF30-\\uDF45]|\\uD804[\\uDC03-\\uDC37\\uDC83-\\uDCAF\\uDCD0-\\uDCE8\\uDD03-\\uDD26\\uDD44\\uDD50-\\uDD72\\uDD76\\uDD83-\\uDDB2\\uDDC1-\\uDDC4\\uDDDA\\uDDDC\\uDE00-\\uDE11\\uDE13-\\uDE2B\\uDE80-\\uDE86\\uDE88\\uDE8A-\\uDE8D\\uDE8F-\\uDE9D\\uDE9F-\\uDEA8\\uDEB0-\\uDEDE\\uDF05-\\uDF0C\\uDF0F\\uDF10\\uDF13-\\uDF28\\uDF2A-\\uDF30\\uDF32\\uDF33\\uDF35-\\uDF39\\uDF3D\\uDF50\\uDF5D-\\uDF61]|\\uD805[\\uDC00-\\uDC34\\uDC47-\\uDC4A\\uDC80-\\uDCAF\\uDCC4\\uDCC5\\uDCC7\\uDD80-\\uDDAE\\uDDD8-\\uDDDB\\uDE00-\\uDE2F\\uDE44\\uDE80-\\uDEAA\\uDF00-\\uDF1A]|\\uD806[\\uDC00-\\uDC2B\\uDCA0-\\uDCDF\\uDCFF\\uDE00\\uDE0B-\\uDE32\\uDE3A\\uDE50\\uDE5C-\\uDE83\\uDE86-\\uDE89\\uDE9D\\uDEC0-\\uDEF8]|\\uD807[\\uDC00-\\uDC08\\uDC0A-\\uDC2E\\uDC40\\uDC72-\\uDC8F\\uDD00-\\uDD06\\uDD08\\uDD09\\uDD0B-\\uDD30\\uDD46\\uDD60-\\uDD65\\uDD67\\uDD68\\uDD6A-\\uDD89\\uDD98\\uDEE0-\\uDEF2]|\\uD808[\\uDC00-\\uDF99]|\\uD809[\\uDC80-\\uDD43]|[\\uD80C\\uD81C-\\uD820\\uD840-\\uD868\\uD86A-\\uD86C\\uD86F-\\uD872\\uD874-\\uD879][\\uDC00-\\uDFFF]|\\uD80D[\\uDC00-\\uDC2E]|\\uD811[\\uDC00-\\uDE46]|\\uD81A[\\uDC00-\\uDE38\\uDE40-\\uDE5E\\uDED0-\\uDEED\\uDF00-\\uDF2F\\uDF40-\\uDF43\\uDF63-\\uDF77\\uDF7D-\\uDF8F]|\\uD81B[\\uDE40-\\uDE7F\\uDF00-\\uDF44\\uDF50\\uDF93-\\uDF9F\\uDFE0\\uDFE1]|\\uD821[\\uDC00-\\uDFF1]|\\uD822[\\uDC00-\\uDEF2]|\\uD82C[\\uDC00-\\uDD1E\\uDD70-\\uDEFB]|\\uD82F[\\uDC00-\\uDC6A\\uDC70-\\uDC7C\\uDC80-\\uDC88\\uDC90-\\uDC99]|\\uD835[\\uDC00-\\uDC54\\uDC56-\\uDC9C\\uDC9E\\uDC9F\\uDCA2\\uDCA5\\uDCA6\\uDCA9-\\uDCAC\\uDCAE-\\uDCB9\\uDCBB\\uDCBD-\\uDCC3\\uDCC5-\\uDD05\\uDD07-\\uDD0A\\uDD0D-\\uDD14\\uDD16-\\uDD1C\\uDD1E-\\uDD39\\uDD3B-\\uDD3E\\uDD40-\\uDD44\\uDD46\\uDD4A-\\uDD50\\uDD52-\\uDEA5\\uDEA8-\\uDEC0\\uDEC2-\\uDEDA\\uDEDC-\\uDEFA\\uDEFC-\\uDF14\\uDF16-\\uDF34\\uDF36-\\uDF4E\\uDF50-\\uDF6E\\uDF70-\\uDF88\\uDF8A-\\uDFA8\\uDFAA-\\uDFC2\\uDFC4-\\uDFCB]|\\uD83A[\\uDC00-\\uDCC4\\uDD00-\\uDD43]|\\uD83B[\\uDE00-\\uDE03\\uDE05-\\uDE1F\\uDE21\\uDE22\\uDE24\\uDE27\\uDE29-\\uDE32\\uDE34-\\uDE37\\uDE39\\uDE3B\\uDE42\\uDE47\\uDE49\\uDE4B\\uDE4D-\\uDE4F\\uDE51\\uDE52\\uDE54\\uDE57\\uDE59\\uDE5B\\uDE5D\\uDE5F\\uDE61\\uDE62\\uDE64\\uDE67-\\uDE6A\\uDE6C-\\uDE72\\uDE74-\\uDE77\\uDE79-\\uDE7C\\uDE7E\\uDE80-\\uDE89\\uDE8B-\\uDE9B\\uDEA1-\\uDEA3\\uDEA5-\\uDEA9\\uDEAB-\\uDEBB]|\\uD869[\\uDC00-\\uDED6\\uDF00-\\uDFFF]|\\uD86D[\\uDC00-\\uDF34\\uDF40-\\uDFFF]|\\uD86E[\\uDC00-\\uDC1D\\uDC20-\\uDFFF]|\\uD873[\\uDC00-\\uDEA1\\uDEB0-\\uDFFF]|\\uD87A[\\uDC00-\\uDFE0]|\\uD87E[\\uDC00-\\uDE1D])+$/\n\nfunction addWorkspaceToArgumentsIfExists(\n\targs: Array<string>,\n\tworkspace: string | null,\n) {\n\tif (workspace) {\n\t\targs.unshift(workspace)\n\t}\n\treturn args\n}\n\nfunction getArgumentsForLineNumber(\n\teditor: string,\n\tfileName: string,\n\tlineNumber: number,\n\tcolNumber: number | undefined,\n\tworkspace: string | null,\n) {\n\tconst editorBasename = path.basename(editor).replace(/\\.(exe|cmd|bat)$/i, '')\n\tswitch (editorBasename) {\n\t\tcase 'atom':\n\t\tcase 'Atom':\n\t\tcase 'Atom Beta':\n\t\tcase 'subl':\n\t\tcase 'sublime':\n\t\tcase 'sublime_text':\n\t\t\treturn [`${fileName}:${lineNumber}:${colNumber}`]\n\t\tcase 'wstorm':\n\t\tcase 'charm':\n\t\t\treturn [`${fileName}:${lineNumber}`]\n\t\tcase 'notepad++':\n\t\t\treturn [`-n${lineNumber}`, `-c${colNumber}`, fileName]\n\t\tcase 'vim':\n\t\tcase 'mvim':\n\t\tcase 'joe':\n\t\tcase 'gvim':\n\t\t\treturn [`+${lineNumber}`, fileName]\n\t\tcase 'emacs':\n\t\tcase 'emacsclient':\n\t\t\treturn [`+${lineNumber}:${colNumber}`, fileName]\n\t\tcase 'rmate':\n\t\tcase 'mate':\n\t\tcase 'mine':\n\t\t\treturn ['--line', lineNumber, fileName]\n\t\tcase 'cursor':\n\t\tcase 'code':\n\t\tcase 'Code':\n\t\tcase 'code-insiders':\n\t\tcase 'Code - Insiders':\n\t\tcase 'vscodium':\n\t\tcase 'VSCodium':\n\t\t\treturn addWorkspaceToArgumentsIfExists(\n\t\t\t\t['-g', `${fileName}:${lineNumber}:${colNumber}`],\n\t\t\t\tworkspace,\n\t\t\t)\n\t\tcase 'appcode':\n\t\tcase 'clion':\n\t\tcase 'clion64':\n\t\tcase 'idea':\n\t\tcase 'idea64':\n\t\tcase 'phpstorm':\n\t\tcase 'phpstorm64':\n\t\tcase 'pycharm':\n\t\tcase 'pycharm64':\n\t\tcase 'rubymine':\n\t\tcase 'rubymine64':\n\t\tcase 'webstorm':\n\t\tcase 'webstorm64':\n\t\tcase 'goland':\n\t\tcase 'goland64':\n\t\tcase 'rider':\n\t\tcase 'rider64':\n\t\t\treturn addWorkspaceToArgumentsIfExists(\n\t\t\t\t['--line', lineNumber.toString(), fileName],\n\t\t\t\tworkspace,\n\t\t\t)\n\t}\n\n\t// For all others, drop the lineNumber until we have\n\t// a mapping above, since providing the lineNumber incorrectly\n\t// can result in errors or confusing behavior.\n\treturn [fileName]\n}\n\nfunction guessEditor(): Array<string | null> {\n\t// Explicit config always wins\n\tif (process.env.EPICSHOP_EDITOR) {\n\t\treturn shellQuote.parse(process.env.EPICSHOP_EDITOR).map((a) => String(a))\n\t}\n\n\t// We can find out which editor is currently running by:\n\t// `ps x` on macOS and Linux\n\t// `Get-Process` on Windows\n\ttry {\n\t\tif (process.platform === 'darwin') {\n\t\t\tconst output = child_process.execSync('ps x').toString()\n\t\t\tconst processNames = Object.keys(COMMON_EDITORS_OSX) as Array<\n\t\t\t\tkeyof typeof COMMON_EDITORS_OSX\n\t\t\t>\n\t\t\tfor (let i = 0; i < processNames.length; i++) {\n\t\t\t\tconst processName = processNames[i]\n\t\t\t\tif (processName && output.includes(processName)) {\n\t\t\t\t\tconst editor = COMMON_EDITORS_OSX[processName]\n\t\t\t\t\treturn [editor]\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (process.platform === 'win32') {\n\t\t\t// Some processes need elevated rights to get its executable path.\n\t\t\t// Just filter them out upfront. This also saves 10-20ms on the command.\n\t\t\tconst output = child_process\n\t\t\t\t.execSync(\n\t\t\t\t\t'wmic process where \"executablepath is not null\" get executablepath',\n\t\t\t\t)\n\t\t\t\t.toString()\n\t\t\tconst runningProcesses = output.split('\\r\\n')\n\t\t\tfor (let i = 0; i < runningProcesses.length; i++) {\n\t\t\t\tconst processPath = runningProcesses[i]?.trim()\n\t\t\t\tif (!processPath) continue\n\t\t\t\tconst processName = path.basename(processPath)\n\t\t\t\tif (COMMON_EDITORS_WIN.includes(processName)) {\n\t\t\t\t\treturn [processPath]\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (process.platform === 'linux') {\n\t\t\t// --no-heading No header line\n\t\t\t// x List all processes owned by you\n\t\t\t// -o comm Need only names column\n\t\t\tconst output = child_process\n\t\t\t\t.execSync('ps x --no-heading -o comm --sort=comm')\n\t\t\t\t.toString()\n\t\t\tconst processNames = Object.keys(COMMON_EDITORS_LINUX)\n\t\t\tfor (let i = 0; i < processNames.length; i++) {\n\t\t\t\tconst processName = processNames[i]\n\t\t\t\tif (!processName) continue\n\t\t\t\tif (output.includes(processName)) {\n\t\t\t\t\t// @ts-expect-error 🤷♂️ it's fine\n\t\t\t\t\treturn [COMMON_EDITORS_LINUX[processName]]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore...\n\t}\n\n\t// Last resort, use old skool env vars\n\tif (process.env.VISUAL) {\n\t\treturn [process.env.VISUAL]\n\t} else if (process.env.EDITOR) {\n\t\treturn [process.env.EDITOR]\n\t}\n\n\treturn [null]\n}\n\nlet _childProcess: ReturnType<typeof child_process.spawn> | null = null\nexport type Result =\n\t| { status: 'success' }\n\t| { status: 'error'; message: string }\nexport async function launchEditor(\n\tpathList: string[] | string,\n\tlineNumber: number = 1,\n\tcolNumber: number = 1,\n): Promise<Result> {\n\t// Sanitize lineNumber to prevent malicious use on win32\n\t// via: https://github.com/nodejs/node/blob/c3bb4b1aa5e907d489619fb43d233c3336bfc03d/lib/child_process.js#L333\n\t// and it should be a positive integer\n\tif (lineNumber && !(Number.isInteger(lineNumber) && lineNumber > 0)) {\n\t\treturn { status: 'error', message: 'lineNumber must be a positive integer' }\n\t}\n\n\t// colNumber is optional, but should be a positive integer too\n\t// default is 1\n\tif (colNumber && !(Number.isInteger(colNumber) && colNumber > 0)) {\n\t\tcolNumber = 1\n\t}\n\n\tconst editorInfo = guessEditor()\n\tconst editor = editorInfo[0]\n\tlet args = editorInfo.slice(1).filter(Boolean)\n\n\tif (!editor) {\n\t\treturn { status: 'error', message: 'No editor found' }\n\t}\n\n\tif (editor.toLowerCase() === 'none') {\n\t\treturn { status: 'error', message: 'Editor set to \"none\"' }\n\t}\n\n\tif (typeof pathList === 'string') {\n\t\tpathList = [pathList]\n\t}\n\n\ttype accumulator = {\n\t\tfileList: string[]\n\t\terrorsList: string[]\n\t}\n\n\tconst initArgs: accumulator = { fileList: [], errorsList: [] }\n\n\tconst { fileList, errorsList } = pathList.reduce(\n\t\t(acc: accumulator, fileName: string) => {\n\t\t\tif (\n\t\t\t\tprocess.platform === 'linux' &&\n\t\t\t\tfileName.startsWith('/mnt/') &&\n\t\t\t\t/Microsoft/i.test(os.release())\n\t\t\t) {\n\t\t\t\t// Assume WSL / \"Bash on Ubuntu on Windows\" is being used, and\n\t\t\t\t// that the file exists on the Windows file system.\n\t\t\t\t// `os.release()` is \"4.4.0-43-Microsoft\" in the current release\n\t\t\t\t// build of WSL, see: https://github.com/Microsoft/BashOnWindows/issues/423#issuecomment-221627364\n\t\t\t\t// When a Windows editor is specified, interop functionality can\n\t\t\t\t// handle the path translation, but only if a relative path is used.\n\t\t\t\tfileName = path.relative('', fileName)\n\t\t\t}\n\n\t\t\tconst fileExists = fs.existsSync(fileName)\n\t\t\t// cmd.exe on Windows is vulnerable to RCE attacks given a file name of the\n\t\t\t// form \"C:\\Users\\myusername\\Downloads\\& curl 172.21.93.52\". Use a whitelist\n\t\t\t// to validate user-provided file names. This doesn't cover the entire range\n\t\t\t// of valid file names but should cover almost all of them in practice.\n\t\t\t// if the file exists, then we're good.\n\t\t\tif (\n\t\t\t\t!fileExists &&\n\t\t\t\tprocess.platform === 'win32' &&\n\t\t\t\t!WINDOWS_FILE_NAME_WHITELIST.test(fileName)\n\t\t\t) {\n\t\t\t\tacc.errorsList.push(fileName)\n\t\t\t} else {\n\t\t\t\tif (!fileExists) {\n\t\t\t\t\tfsExtra.ensureDirSync(path.dirname(fileName))\n\t\t\t\t\tfsExtra.writeFileSync(fileName, '', 'utf8')\n\t\t\t\t}\n\n\t\t\t\tacc.fileList.push(fileName.trim())\n\t\t\t}\n\t\t\treturn acc\n\t\t},\n\t\tinitArgs,\n\t)\n\n\t// TODO: figure out how to send error messages as JSX from here...\n\tfunction getErrorMessage() {\n\t\tlet message: string\n\t\tif (errorsList.length) {\n\t\t\tconst readableName =\n\t\t\t\terrorsList.length === 1 ? readablePath(errorsList[0]) : 'some files'\n\t\t\tmessage = `Could not open ${readableName} in the editor.\\n\\nWhen running on Windows, file names are checked against a whitelist to protect against remote code execution attacks.\\nFile names may consist only of alphanumeric characters (all languages), periods, dashes, slashes, and underscores. Maybe you have your files in a folder that includes a space in the pathname? Rename the folder to remove the space and try again.`\n\t\t} else {\n\t\t\tmessage = 'pathList must contain at least one valid file path'\n\t\t}\n\t\treturn {\n\t\t\tstatus: 'error',\n\t\t\tmessage,\n\t\t} as Result\n\t}\n\n\tconst workspace = null\n\tif (lineNumber && fileList.length === 1) {\n\t\tconst fileName = fileList[0]\n\t\tif (!fileName) {\n\t\t\treturn getErrorMessage()\n\t\t}\n\t\targs = args.concat(\n\t\t\tgetArgumentsForLineNumber(\n\t\t\t\teditor,\n\t\t\t\tfileName,\n\t\t\t\tlineNumber,\n\t\t\t\tcolNumber,\n\t\t\t\tworkspace,\n\t\t\t)\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.map(String),\n\t\t)\n\t} else {\n\t\tconst argList = fileList.filter(Boolean)\n\t\tif (!argList.length) {\n\t\t\treturn getErrorMessage()\n\t\t}\n\t\targs.push(...argList)\n\t}\n\n\tif (_childProcess && isTerminalEditor(editor)) {\n\t\t// There's an existing editor process already and it's attached\n\t\t// to the terminal, so go kill it. Otherwise two separate editor\n\t\t// instances attach to the stdin/stdout which gets confusing.\n\t\t_childProcess.kill('SIGKILL')\n\t}\n\n\treturn new Promise((res) => {\n\t\tif (process.platform === 'win32') {\n\t\t\t// On Windows, launch the editor in a shell because spawn can only\n\t\t\t// launch .exe files.\n\t\t\t_childProcess = child_process.spawn(\n\t\t\t\t'cmd.exe',\n\t\t\t\t['/C', editor].concat(args).filter(Boolean),\n\t\t\t\t{ stdio: ['inherit', 'inherit', 'pipe'] },\n\t\t\t)\n\t\t} else {\n\t\t\t_childProcess = child_process.spawn(editor, args, {\n\t\t\t\tstdio: ['inherit', 'inherit', 'pipe'],\n\t\t\t})\n\t\t}\n\t\t_childProcess.stderr?.on('data', (data: string | Uint8Array) => {\n\t\t\tconst message = String(data)\n\t\t\t// Filter out the specific error message for environment variable issues\n\t\t\tif (!message.includes('Node.js environment variables are disabled')) {\n\t\t\t\tprocess.stderr.write(data) // Only write non-filtered messages to stderr\n\t\t\t}\n\t\t})\n\t\t_childProcess.on('exit', async (errorCode) => {\n\t\t\t_childProcess = null\n\n\t\t\tif (errorCode) {\n\t\t\t\tconst readableName =\n\t\t\t\t\tfileList.length === 1 ? readablePath(fileList[0]) : 'some files'\n\t\t\t\treturn res({\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tmessage: `Could not open ${readableName} in the editor.\\n\\nThe editor process exited with an error code (${errorCode}).`,\n\t\t\t\t})\n\t\t\t} else if (errorsList.length) {\n\t\t\t\t// show error message even when the editor was opened successfully,\n\t\t\t\t// if some file path was not valid in windows\n\t\t\t\treturn res(getErrorMessage())\n\t\t\t} else {\n\t\t\t\treturn res({ status: 'success' })\n\t\t\t}\n\t\t})\n\n\t\t_childProcess.on('error', async (error: Error & { code?: string }) => {\n\t\t\tif (error.code === 'EBADF') {\n\t\t\t\treturn res({\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t'Unable to launch editor. This commonly happens when running in a containerized or server environment without terminal access.',\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn res({ status: 'error', message: error.message })\n\t\t})\n\t})\n}\n","import path from 'path'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport { clsx } from 'clsx'\nimport fsExtra from 'fs-extra'\nimport { useEffect } from 'react'\nimport { Link, useFetcher, type ActionFunctionArgs } from 'react-router'\nimport { z, type ZodTypeAny } from 'zod'\nimport { useApps } from '#app/components/apps'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { launchEditor } from '#app/utils/launch-editor.server.ts'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.js'\nimport { useRequestInfo } from '#app/utils/request-info'\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(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\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\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\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 type=\"hidden\" name=\"line\" value={typeof line === 'number' ? line : undefined} />\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={clsx(\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)}\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\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=\"launch_button !no-underline\"\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}/${appFile}`.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, useRef } from 'react'\n\nexport function Mermaid({\n\tcode,\n\tonSvg,\n}: {\n\tcode: string\n\tonSvg?: (svg: string) => void\n}) {\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('mermaid-svg', 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])\n\treturn <div ref={ref} />\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/index.js'\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 right-0 top-0 z-50 m-2 flex items-baseline justify-end gap-4 opacity-0 transition duration-300 ease-in-out focus-within:opacity-100 group-hover: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 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 {\n\tdata,\n\ttype HeadersFunction,\n\tLink,\n\tisRouteErrorResponse,\n\tuseRouteError,\n} from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.js'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\nimport { getSeoMetaTags } from '#app/utils/seo.js'\nimport { type Route } from './+types/$exerciseNumber.tsx'\n\nexport const meta: Route.MetaFunction = ({ data, matches }) => {\n\tconst number = data?.exercise.exerciseNumber.toString().padStart(2, '0')\n\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\n\tif (!data || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `📝 | ${number}. ${data.exercise.title} | ${rootData?.workshopTitle}`,\n\t\tdescription: `Introduction for ${number}. ${data.exercise.title}`,\n\t\togTitle: data.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 new Response('Not found', { 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}`,\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 flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 scrollbar-thin scrollbar-thumb-scrollbar 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)] font-extrabold leading-none\">\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-b-4 border-t 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=\"flex h-full items-center justify-center bg-foreground px-7 text-background\"\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\tconst error = useRouteError()\n\n\tif (typeof document !== 'undefined') {\n\t\tconsole.error(error)\n\t}\n\n\treturn isRouteErrorResponse(error) ? (\n\t\terror.status === 404 ? (\n\t\t\t<p>Sorry, we couldn't find that step.</p>\n\t\t) : (\n\t\t\t<p>\n\t\t\t\t{error.status} {error.data}\n\t\t\t</p>\n\t\t)\n\t) : (\n\t\t<p>{getErrorMessage(error)}</p>\n\t)\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport { getExercises } 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 {\n\tdata,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tOutlet,\n\tisRouteErrorResponse,\n\tuseRouteError,\n} from 'react-router'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('stepLoader')\n\tinvariantResponse(params.exerciseNumber, 'exerciseNumber is required')\n\tconst exercises = await getExercises({ request, timings })\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst exercise = exercises.find(\n\t\t(e) => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tif (!exercise) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\n\n\tconst result = data(\n\t\t{\n\t\t\texerciseNumber: exercise.exerciseNumber,\n\t\t\texerciseTitle: exercise.title,\n\t\t\ttitle: workshopTitle,\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},\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\treturn result\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 StepRoute() {\n\treturn <Outlet />\n}\n\nexport function ErrorBoundary() {\n\tconst error = useRouteError()\n\n\tif (typeof document !== 'undefined') {\n\t\tconsole.error(error)\n\t}\n\n\treturn isRouteErrorResponse(error) ? (\n\t\terror.status === 404 ? (\n\t\t\t<p>Sorry, we couldn't find that step.</p>\n\t\t) : (\n\t\t\t<p>\n\t\t\t\t{error.status} {error.data}\n\t\t\t</p>\n\t\t)\n\t) : (\n\t\t<p>{getErrorMessage(error)}</p>\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\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\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 { data, 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.js'\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\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\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 data({ status: 'error', error: message } as const, {\n\t\t\tstatus: 500,\n\t\t\theaders: await createToastHeaders({\n\t\t\t\ttype: 'error',\n\t\t\t\ttitle: 'Error',\n\t\t\t\tdescription:\n\t\t\t\t\t'There was an error setting the playground. Check the terminal for details.',\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(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'flex h-full w-full items-center justify-between text-left radix-placeholder:text-gray-500 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=\"w-80 flex-1 overflow-hidden text-ellipsis whitespace-nowrap scrollbar-thin scrollbar-thumb-scrollbar\">\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=\"relative flex cursor-pointer select-none items-center rounded px-10 py-2 leading-none opacity-80 radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100\"\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({ appName }: { appName: string }) {\n\tif (ENV.EPICSHOP_DEPLOYED) return null\n\treturn (\n\t\t<SetPlayground\n\t\t\tappName={appName}\n\t\t\ttooltipText=\"Playground is not set to the right app. Click to set Playground.\"\n\t\t>\n\t\t\t<span className=\"flex items-center justify-center gap-1 text-foreground-destructive hover:underline\">\n\t\t\t\t<Icon name=\"Unlinked\" className=\"animate-ping\" />{' '}\n\t\t\t\t<span className=\"uppercase\">Set to Playground</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/request-info.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 StepContext.Provider')\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 (\n\t\t<StepContext.Provider value={{ inBrowserBrowserRef }}>\n\t\t\t{children}\n\t\t</StepContext.Provider>\n\t)\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// @ts-expect-error 🤷♂️\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{/* @ts-expect-error 🤷♂️ */}\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// @ts-expect-error 🤷♂️\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\t{/* @ts-expect-error 🤷♂️ */}\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 z-10 select-none rounded bg-background px-9 py-8 text-foreground\"\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=\"mb-2 border-b border-b-gray-50 border-opacity-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\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\tLink,\n\tOutlet,\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.js'\nimport { type RootLoaderData } from '#app/root.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 { getSeoMetaTags } from '#app/utils/seo.js'\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'\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 = ({ data, matches, params }) => {\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\n\tif (!data || !rootData) return [{ title: '🦉 | Error' }]\n\tconst { emoji, stepNumber, title, exerciseNumber, exerciseTitle } =\n\t\tpageTitle(data)\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 { title: workshopTitle } = getWorkshopConfig()\n\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 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 (!problemApp && !solutionApp) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\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} 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 flex-grow flex-col\">\n\t\t\t<main\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName=\"flex 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-[var(--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 pl-10 pr-5 text-sm font-medium leading-tight\">\n\t\t\t\t\t\t<div className=\"flex h-14 items-center justify-between gap-x-2 overflow-x-auto whitespace-nowrap py-2\">\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\tdata.playground?.appName !== data.problem.name ? (\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 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</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 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 scrollbar-thin scrollbar-thumb-scrollbar 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\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\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-b-4 border-t 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}\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=\"hidden w-1 cursor-col-resize bg-border hover:bg-accent 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 />\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\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t\t503: () => (\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h1>Service Unavailable</h1>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\tSorry, we're having a temporary problem. Please try again later.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<button onClick={() => window.location.reload()}>Refresh</button>\n\t\t\t\t\t</div>\n\t\t\t\t),\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.js'\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(formData, { status: 'app-started' } 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(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(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(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 uppercase leading-none\"\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 {\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n\ttype ForwardedRef,\n} from 'react'\nimport { Form, useSearchParams, type NavigateFunction } from 'react-router'\nimport { z } from 'zod'\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/request-info.ts'\nimport { LinkButton } from './button.tsx'\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from './ui/tooltip.tsx'\n\nconst historyCallDataSchema = z.intersection(\n\tz.object({\n\t\ttype: z.literal('epicshop:history-call'),\n\t}),\n\tz.union([\n\t\tz.object({\n\t\t\tmethod: z.literal('pushState'),\n\t\t\targs: z.union([\n\t\t\t\tz.tuple([z.object({}).passthrough(), z.unknown()]),\n\t\t\t\tz.tuple([z.object({}).passthrough(), z.unknown(), z.string()]),\n\t\t\t]),\n\t\t}),\n\t\tz.object({\n\t\t\tmethod: z.literal('replaceState'),\n\t\t\targs: z.union([\n\t\t\t\tz.tuple([z.object({}).passthrough(), z.unknown()]),\n\t\t\t\tz.tuple([z.object({}).passthrough(), z.unknown(), z.string()]),\n\t\t\t]),\n\t\t}),\n\t\tz.object({\n\t\t\tmethod: z.literal('go'),\n\t\t\targs: z.tuple([z.number().optional()]),\n\t\t}),\n\t\tz.object({ method: z.literal('forward'), args: z.tuple([]) }),\n\t\tz.object({ method: z.literal('back'), args: z.tuple([]) }),\n\t\tz.object({\n\t\t\tmethod: z.literal('popstate'),\n\t\t\tpathname: z.string(),\n\t\t\tdelta: z.number(),\n\t\t}),\n\t]),\n)\n\nconst loadedSchema = z.object({\n\ttype: z.literal('epicshop:loaded'),\n\turl: z.string(),\n})\n\nconst messageSchema = z.union([historyCallDataSchema, loadedSchema])\n\nfunction getNewIndex(prevIndex: number, delta: number, max: number) {\n\t// keep the index bound between 0 and the history length\n\treturn Math.min(Math.max(prevIndex + delta, 0), max)\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}\n\nexport type InBrowserBrowserRef = {\n\thandleExtrnalNavigation: (pathname?: string) => void\n}\n\nexport const InBrowserBrowser = forwardRef<InBrowserBrowserRef, Props>(\n\tInBrowserBrowserImpl,\n)\n\nfunction InBrowserBrowserImpl(\n\t{ name, port, portIsAvailable, isRunning, baseUrl, id, initialRoute }: Props,\n\tref: ForwardedRef<InBrowserBrowserRef>,\n) {\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 <AppStarter name={name} />\n\t}\n}\ntype RealBrowserProps = {\n\tbaseUrl: string\n\tid: string\n\tname: string\n\tinitialRoute: string\n}\n\nconst InBrowserBrowserForRealz = forwardRef<\n\tInBrowserBrowserRef,\n\tRealBrowserProps\n>(InBrowserBrowserForRealzImpl)\n\n// we're doing this to ensure all of this complex stuff doesn't happen unless\n// the iframe is actually rendered.\nfunction InBrowserBrowserForRealzImpl(\n\t{ baseUrl, id, name, initialRoute }: RealBrowserProps,\n\tref: ForwardedRef<InBrowserBrowserRef>,\n) {\n\tconst theme = useTheme()\n\tconst [searchParams, setSearchParams] = useSearchParams()\n\tconst searchParamsPathname = searchParams.get('pathname') ?? initialRoute\n\tconst [iframeKeyNumber, setIframeKeyNumber] = useState(0)\n\tconst iframeKey = id + iframeKeyNumber\n\tconst lastDirectionRef = useRef<'forward' | 'back' | 'new'>('new')\n\tconst lastDirectionTimeout = useRef<ReturnType<typeof setTimeout> | null>(\n\t\tnull,\n\t)\n\tconst [iframeContext, setIFrameContext] = useState({\n\t\thistory: [searchParamsPathname],\n\t\tindex: 0,\n\t})\n\tconst [pathnameInputValue, setPathnameInputValue] =\n\t\tuseState(searchParamsPathname)\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\n\tconst appUrl = new URL(searchParamsPathname, baseUrl)\n\tconst currentAppUrl = useRef(appUrl)\n\tuseEffect(() => {\n\t\tcurrentAppUrl.current = appUrl\n\t})\n\n\t/** changing the iframeSrcUrl will trigger a reload of the iframe */\n\tconst [iframeSrcUrl, setIframeSrcUrl] = useState(appUrl)\n\n\tconst currentId = useRef(id)\n\t// if the id changes, then we're going to reload the iframe, but we want to\n\t// make sure to preserve the pathname so we set the src to the current pathname\n\t// this is one of the few side-effects in render that are \"ok\"\n\tif (currentId.current !== id) {\n\t\tcurrentId.current = id\n\t\tsetIframeSrcUrl(currentAppUrl.current)\n\t}\n\tuseEffect(() => {\n\t\tcurrentId.current = id\n\t})\n\n\tuseEffect(() => {\n\t\tfunction handleMessage(messageEvent: MessageEvent) {\n\t\t\tif (messageEvent.source !== iframeRef.current?.contentWindow) return\n\n\t\t\tconst result = messageSchema.safeParse(messageEvent.data, {\n\t\t\t\tpath: ['messageEvent', 'data'],\n\t\t\t})\n\t\t\tif (!result.success) return\n\t\t\tconst { data } = result\n\n\t\t\tif (data.type === 'epicshop:loaded') {\n\t\t\t\tsetIFrameContext((prevContext) => {\n\t\t\t\t\tconst newIndex = (i: number) =>\n\t\t\t\t\t\tgetNewIndex(prevContext.index, i, prevContext.history.length - 1)\n\t\t\t\t\tif (lastDirectionRef.current === 'back') {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(-1) }\n\t\t\t\t\t} else if (lastDirectionRef.current === 'forward') {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(1) }\n\t\t\t\t\t} else if (lastDirectionRef.current === 'new') {\n\t\t\t\t\t\tconst currentFullPath = prevContext.history[prevContext.index]\n\t\t\t\t\t\tconst newUrl = new URL(data.url)\n\t\t\t\t\t\tconst newFullPath = newUrl.pathname + newUrl.search\n\n\t\t\t\t\t\tif (currentFullPath === newFullPath) return prevContext\n\n\t\t\t\t\t\tconst newHistory = [\n\t\t\t\t\t\t\t...prevContext.history.slice(0, prevContext.index + 1),\n\t\t\t\t\t\t\tnewFullPath,\n\t\t\t\t\t\t]\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\thistory: newHistory,\n\t\t\t\t\t\t\tindex: newHistory.length - 1,\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Error('Unexpected lastDirectionRef value')\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst { method } = data\n\t\t\tsetIFrameContext((prevContext) => {\n\t\t\t\tconst newIndex = (i: number) =>\n\t\t\t\t\tgetNewIndex(prevContext.index, i, prevContext.history.length - 1)\n\t\t\t\tconst currentPathname = prevContext.history[prevContext.index]\n\t\t\t\tswitch (method) {\n\t\t\t\t\tcase 'popstate': {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(data.delta) }\n\t\t\t\t\t}\n\t\t\t\t\tcase 'forward': {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(1) }\n\t\t\t\t\t}\n\t\t\t\t\tcase 'back': {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(-1) }\n\t\t\t\t\t}\n\t\t\t\t\tcase 'pushState': {\n\t\t\t\t\t\tconst pathname = data.args[2] ?? currentPathname\n\t\t\t\t\t\tconst newHistory = [\n\t\t\t\t\t\t\t...prevContext.history.slice(0, prevContext.index + 1),\n\t\t\t\t\t\t\tpathname,\n\t\t\t\t\t\t].filter(Boolean)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...prevContext,\n\t\t\t\t\t\t\thistory: newHistory,\n\t\t\t\t\t\t\tindex: newHistory.length - 1,\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'replaceState': {\n\t\t\t\t\t\tconst pathname = data.args[2] ?? currentPathname\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...prevContext,\n\t\t\t\t\t\t\thistory: [\n\t\t\t\t\t\t\t\t...prevContext.history.slice(0, prevContext.index),\n\t\t\t\t\t\t\t\tpathname,\n\t\t\t\t\t\t\t\t...prevContext.history.slice(prevContext.index + 1),\n\t\t\t\t\t\t\t].filter(Boolean),\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'go': {\n\t\t\t\t\t\tconst [delta = 0] = data.args\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(delta) }\n\t\t\t\t\t}\n\t\t\t\t}\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\t// setSearchParams is unstable\n\t// https://github.com/remix-run/react-router/issues/9991\n\tconst setSearchParamsLatestRef = useRef(setSearchParams)\n\tuseEffect(() => {\n\t\tsetSearchParamsLatestRef.current = setSearchParams\n\t}, [setSearchParams])\n\n\tconst iframePathname = iframeContext.history[iframeContext.index]\n\tuseEffect(() => {\n\t\tif (!iframePathname) return\n\n\t\tsetPathnameInputValue(iframePathname)\n\n\t\tconst newSearchParams = new URLSearchParams(window.location.search)\n\t\tif (iframePathname === '/') {\n\t\t\tnewSearchParams.delete('pathname')\n\t\t} else {\n\t\t\tnewSearchParams.set('pathname', iframePathname)\n\t\t}\n\t\tconst newSearch = newSearchParams.toString()\n\t\tif (`?${newSearch}` !== window.location.search) {\n\t\t\tsetSearchParamsLatestRef.current(newSearchParams, { replace: true })\n\t\t}\n\t}, [iframePathname])\n\n\tconst navigateChild: NavigateFunction = (...params) => {\n\t\tconst to = params[0]\n\t\tif (typeof to === 'number') {\n\t\t\t// this part feels very brittle to me...\n\t\t\tlastDirectionRef.current = to > 0 ? 'forward' : 'back'\n\t\t} else {\n\t\t\tlastDirectionRef.current = 'new'\n\t\t}\n\t\tif (lastDirectionTimeout.current) {\n\t\t\tclearTimeout(lastDirectionTimeout.current)\n\t\t}\n\t\tlastDirectionTimeout.current = setTimeout(() => {\n\t\t\tlastDirectionRef.current = 'new'\n\t\t}, 100)\n\t\tiframeRef.current?.contentWindow?.postMessage(\n\t\t\t{ type: 'epicshop:navigate-call', params },\n\t\t\t'*',\n\t\t)\n\t}\n\n\tfunction handleExtrnalNavigation(\n\t\tnewPathnameInputValue: string = pathnameInputValue,\n\t) {\n\t\tsetPathnameInputValue(newPathnameInputValue)\n\n\t\tconst currentPathname = iframeContext.history[iframeContext.index]\n\t\tvoid navigateChild(newPathnameInputValue, {\n\t\t\treplace: currentPathname === newPathnameInputValue,\n\t\t})\n\t}\n\n\tuseImperativeHandle(ref, () => ({ handleExtrnalNavigation }))\n\n\tconst atEndOfHistory =\n\t\tiframeContext.index === iframeContext.history.length - 1\n\tconst atStartOfHistory = iframeContext.index <= 0\n\tconst existingSearchParamHiddenInputs: Array<React.ReactElement> = []\n\tfor (const [key, value] of searchParams.entries()) {\n\t\tif (key === 'pathname') continue\n\n\t\texistingSearchParamHiddenInputs.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<TooltipProvider>\n\t\t\t<div className=\"flex h-full flex-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=\"hidden aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40 sm:flex\"\n\t\t\t\t\t\t\t\t\tdisabled={atStartOfHistory}\n\t\t\t\t\t\t\t\t\tonClick={() => navigateChild(-1)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"ArrowLeft\" 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>Go back</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\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=\"hidden aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40 sm:flex\"\n\t\t\t\t\t\t\t\t\tdisabled={atEndOfHistory}\n\t\t\t\t\t\t\t\t\tonClick={() => navigateChild(1)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"ArrowRight\" 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>Go forward</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\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\tsetIframeSrcUrl(appUrl)\n\t\t\t\t\t\t\t\t\t\tsetIframeKeyNumber(iframeKeyNumber + 1)\n\t\t\t\t\t\t\t\t\t\t// TODO: figure out how we can avoid having to do this...\n\t\t\t\t\t\t\t\t\t\t// I stayed up for hours one night trying and couldn't work out\n\t\t\t\t\t\t\t\t\t\t// why react router wouldn't update the UI when using back/forward\n\t\t\t\t\t\t\t\t\t\t// after a refresh.\n\t\t\t\t\t\t\t\t\t\tsetIFrameContext({\n\t\t\t\t\t\t\t\t\t\t\thistory: [appUrl.pathname],\n\t\t\t\t\t\t\t\t\t\t\tindex: 0,\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<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<Form\n\t\t\t\t\t\tmethod=\"get\"\n\t\t\t\t\t\treplace\n\t\t\t\t\t\tclassName=\"flex flex-1 gap-2\"\n\t\t\t\t\t\tonSubmit={() => handleExtrnalNavigation()}\n\t\t\t\t\t>\n\t\t\t\t\t\t{existingSearchParamHiddenInputs}\n\t\t\t\t\t\t<div className=\"flex flex-1 items-center border-x bg-background p-3 leading-none text-foreground\">\n\t\t\t\t\t\t\t<a href={appUrl.toString()} target=\"_blank\" rel=\"noreferrer\">\n\t\t\t\t\t\t\t\t{iframeSrcUrl.host}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\taria-label=\"pathname\"\n\t\t\t\t\t\t\t\tclassName=\"w-full flex-1 bg-background focus-visible:outline-none\"\n\t\t\t\t\t\t\t\tvalue={pathnameInputValue}\n\t\t\t\t\t\t\t\tname=\"pathname\"\n\t\t\t\t\t\t\t\tonChange={(e) => setPathnameInputValue(e.currentTarget.value)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{/* TODO: Reconsider if this is needed as browsers don't usually have a submit button in address bar */}\n\t\t\t\t\t\t{/* <button type=\"submit\">Go</button> */}\n\t\t\t\t\t</Form>\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={appUrl.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 flex-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 flex-grow bg-white\"\n\t\t\t\t\t\tstyle={{ colorScheme: theme }}\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 { Icon } from '#app/components/icons'\nimport {\n\tInBrowserBrowser,\n\ttype InBrowserBrowserRef,\n} from '#app/components/in-browser-browser'\nimport { Loading } from '#app/components/loading.js'\nimport { useTheme } from '#app/routes/theme/index.js'\nimport { cn, getBaseUrl } from '#app/utils/misc'\nimport { useRequestInfo } from '#app/utils/request-info'\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 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={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=\"relative h-full flex-grow overflow-y-auto scrollbar-thin scrollbar-thumb-scrollbar\">\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 bottom-5 right-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 flex-grow bg-white\"\n\t\t\t\t\tstyle={{ colorScheme: theme }}\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 flex-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 flex-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\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\tisAppRunning,\n\tisPortAvailable,\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","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.js'\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 max-w-none whitespace-pre-wrap dark:prose-invert prose-pre:m-0 prose-pre:mb-1 prose-pre:rounded-none',\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 flex w-full items-center justify-between border-b p-4 pr-3 font-mono text-sm font-medium leading-none hover:bg-foreground/20',\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=\"font-mono text-xs font-normal uppercase text-muted-foreground\">\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=\"transition group-radix-state-open:rotate-180\"\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 {\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 './apps.tsx'\nimport { DeferredEpicVideo } from './epic-video.tsx'\nimport { Icon } from './icons.tsx'\nimport { useRevalidationWS } from './revalidation-ws.tsx'\nimport { SimpleTooltip } from './ui/tooltip.tsx'\nimport { useUserHasAccess } from './user.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 Diff({\n\tdiff,\n\tallApps,\n}: {\n\tdiff: Promise<diffProp> | diffProp\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\tconst userHasAccess = useUserHasAccess()\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\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 the diff.\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 diff tab works.\n\t\t\t\t</p>\n\t\t\t\t<DeferredEpicVideo url=\"https://www.epicweb.dev/tips/epic-workshop-diff-tab-demo\" />\n\t\t\t</div>\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=\"p-6 text-foreground-destructive\">\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=\"flex h-full flex-1 items-center overflow-x-auto scrollbar-thin scrollbar-thumb-scrollbar\"\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=\"flex-grow overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar\">\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=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">\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=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">\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'flex h-full w-full max-w-[50%] items-center justify-between px-3 text-left radix-placeholder:text-gray-500 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<SelectValue\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'relative flex cursor-pointer select-none items-center rounded px-10 py-2 leading-none opacity-80 radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100',\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\nconst SelectValue: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => {\n\treturn (\n\t\t<Select.Value {...props} ref={forwardedRef}>\n\t\t\t{props.value}\n\t\t</Select.Value>\n\t)\n}\n","import {\n\tcachified,\n\tfsCache,\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.js'\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\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: fsCache,\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=\"flex-1 overflow-y-scroll bg-accent pb-4 scrollbar-thin scrollbar-thumb-scrollbar\">\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=\"flex h-full w-full flex-col items-center justify-center text-foreground-destructive\">\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=\"rounded-xl border bg-background 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=\"flex items-center justify-center gap-1 rounded-full bg-accent 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=\"flex-1 overflow-ellipsis text-muted-foreground\">\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.js'\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=\"animate-pulse text-foreground-destructive\"\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 flex-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 h-full flex-1 flex-grow items-center justify-center\">\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 { 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>\n\t\t\t\t\t<div className=\"text-foreground-secondary flex h-full items-center justify-center text-2xl\">\n\t\t\t\t\t\tNon-UI playground\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"text-foreground-secondary flex flex-wrap gap-1 text-center\">\n\t\t\t\t\t\t\tNavigate to{' '}\n\t\t\t\t\t\t\t<SimpleTooltip content={playgroundAppInfo.fullPath}>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tvoid navigator.clipboard.writeText(\n\t\t\t\t\t\t\t\t\t\t\tplaygroundAppInfo.fullPath,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\tshowToast.success('Copied playground path to clipboard')\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\tthe playground directory\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</SimpleTooltip>{' '}\n\t\t\t\t\t\t\tin your editor and terminal to work on this exercise!\n\t\t\t\t\t\t</div>\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.js'\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.js'\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=\"max-h-48 overflow-y-auto p-4 scrollbar-thin scrollbar-thumb-scrollbar\">\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=\"flex items-baseline gap-2 text-foreground-destructive\">\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=\"max-h-48 overflow-y-auto p-4 scrollbar-thin scrollbar-thumb-scrollbar\"\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/>\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} 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.js'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.js'\nimport { createToastHeaders } from '#app/utils/toast.server.js'\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\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\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\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(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(formData, { success: true })\n\t\t}\n\t\tcase 'clear': {\n\t\t\tclearTestProcessEntry(app)\n\t\t\treturn dataWithPE(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 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\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-y-auto\">\n\t\t\t<div className=\"flex h-12 w-full flex-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 flex-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 h-full 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 flex-1 overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar\">\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 flex-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 flex-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 flex-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 { useState } from 'react'\nimport { DeferredEpicVideo } from '#app/components/epic-video.js'\nimport { Icon } from '#app/components/icons'\nimport { InBrowserTestRunner } from '#app/components/in-browser-test-runner'\nimport { useUserHasAccess } from '#app/components/user.js'\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}: {\n\tappInfo: Pick<PlaygroundApp, 'appName' | 'name' | 'test'> | 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<TestUI playgroundAppInfo={playgroundAppInfo} />\n\t\t</PlaygroundWindow>\n\t)\n}\n\nexport function TestUI({\n\tplaygroundAppInfo,\n}: {\n\tplaygroundAppInfo: Pick<PlaygroundApp, 'name' | 'test'> | null\n}) {\n\tconst [inBrowserTestKey, setInBrowserTestKey] = useState(0)\n\tconst userHasAccess = useUserHasAccess()\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 w-full flex-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 uppercase leading-none\"\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 { compileMarkdownString } from '@epic-web/workshop-utils/compile-mdx.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { userHasAccessToWorkshop } 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 { useRef } from 'react'\nimport {\n\tLink,\n\tuseLoaderData,\n\tuseNavigate,\n\tuseSearchParams,\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\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 { useAltDown } from '#app/utils/misc.tsx'\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 } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exerciseStepTypeIndexLoader')\n\tconst userHasAccess = await userHasAccessToWorkshop({\n\t\trequest,\n\t\ttimings,\n\t})\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\tif (!userHasAccess) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: await compileMarkdownString(\n\t\t\t\t\t`<h1>Access Denied</h1><p>You must login or register for the workshop to view the diff</p>`,\n\t\t\t\t),\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\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} 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\tconst data = useLoaderData<typeof loader>()\n\tconst [searchParams] = useSearchParams()\n\n\tconst preview = searchParams.get('preview')\n\tconst inBrowserBrowserRef = useRef<InBrowserBrowserRef>(null)\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!data.playground ||\n\t\t\t\tdata.playground.test.type === 'none'\n\t\t\t)\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution') {\n\t\t\tif (data[tab]?.dev.type === 'none') return true\n\t\t\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\t\t\treturn data[tab]?.dev.type !== 'browser' && !data[tab]?.stackBlitzUrl\n\t\t\t}\n\t\t}\n\t\tif (tab === 'playground' && ENV.EPICSHOP_DEPLOYED) return true\n\t\treturn false\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: data.problem?.name ?? '',\n\t\tapp2: data.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-w-0 flex-1 flex-col overflow-y-auto 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=\"h-14 min-h-14 overflow-x-auto whitespace-nowrap border-b scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t{tabs.map((tab) => {\n\t\t\t\t\tconst hidden = shouldHideTab(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 relative h-full px-6 py-4 font-mono text-sm uppercase outline-none 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',\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{tab}\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-96 flex-grow flex-col overflow-y-auto\">\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"playground\"\n\t\t\t\t\tclassName=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\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={data.playground}\n\t\t\t\t\t\tproblemAppName={data.problem?.name}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t\tallApps={data.allApps}\n\t\t\t\t\t\tisUpToDate={data.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=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\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={data.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=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\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={data.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=\"flex w-full flex-grow items-start justify-center self-start overflow-hidden radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Tests\n\t\t\t\t\t\tappInfo={data.playground}\n\t\t\t\t\t\tproblemAppName={data.problem?.name}\n\t\t\t\t\t\tallApps={data.allApps}\n\t\t\t\t\t\tisUpToDate={data.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=\"diff\"\n\t\t\t\t\tclassName=\"flex h-full w-full flex-grow items-start justify-center self-start radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Diff diff={data.diff} allApps={data.allApps} />\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=\"flex h-full w-full flex-grow items-start justify-center self-start radix-state-inactive:hidden\"\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 {\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},\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 } = useLoaderData<typeof loader>()\n\n\treturn <TestUI key={appInfo.name} playgroundAppInfo={appInfo} />\n}\n","import {\n\tgetExerciseApp,\n\tisProblemApp,\n\tisSolutionApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\n\nexport async function loader({ params }: LoaderFunctionArgs) {\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 new Response('Not found', { status: 404 })\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.js'\nimport { type RootLoaderData } from '#app/root.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 { getSeoMetaTags } from '#app/utils/seo.js'\nimport { type Route } from './+types/$exerciseNumber_.finished.tsx'\n\nexport const meta: Route.MetaFunction = ({ data, matches }) => {\n\tconst number = data?.exercise.exerciseNumber.toString().padStart(2, '0')\n\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\n\tif (!data || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🦉 | ${number}. ${data.exercise.title} | ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${number}. ${data.exercise.title}`,\n\t\togTitle: `Finished: ${data.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 flex-grow flex-col\">\n\t\t\t<main className=\"flex 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 pl-10 pr-5 text-sm font-medium leading-tight\">\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 h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 scrollbar-thin scrollbar-thumb-scrollbar 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-b-4 border-t 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 flex-shrink-0\">\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center text-body-md text-foreground-destructive\">\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:flex-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.js'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.js'\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 = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\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 flex-grow flex-col\">\n\t\t\t<main className=\"grid h-full flex-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 pl-10 pr-5 text-sm font-medium uppercase leading-none\">\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 h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 scrollbar-thin scrollbar-thumb-scrollbar 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-b-4 border-t 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 flex-shrink-0\">\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center text-foreground-destructive\">\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 flex-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\texercise,\n}: {\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>\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=\"flex flex-col divide-y divide-border dark:divide-border/50\">\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) => (\n\t\t\t\t<ExerciseListItem key={exercise.exerciseNumber} exercise={exercise} />\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 flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 scrollbar-thin scrollbar-thumb-scrollbar 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)] font-extrabold leading-none\">\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=\"pb-5 pt-10\">\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 * as client from 'openid-client'\nimport { z } from 'zod'\nimport { EVENTS } from './auth-events.ts'\nimport { getErrorMessage } from './misc.tsx'\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\tconst {\n\t\tproduct: { host },\n\t} = getWorkshopConfig()\n\tconst { ISSUER = `https://${host}/oauth` } = process.env\n\ttry {\n\t\tconst config = await client.discovery(new URL(ISSUER), 'EPICSHOP_APP')\n\t\tconst deviceResponse = await client.initiateDeviceAuthorization(config, {})\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\tthrow new Error('Device authorization timed out')\n\t\t}, deviceResponse.expires_in * 1000)\n\n\t\ttry {\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\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\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\tconst userinfoResult = UserInfoSchema.safeParse(userinfoRaw)\n\t\t\tif (!userinfoResult.success) {\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\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\n\t\t\tawait getUserInfo({ forceFresh: true })\n\n\t\t\tauthEmitter.emit(EVENTS.AUTH_RESOLVED)\n\t\t} catch (error) {\n\t\t\tclearTimeout(timeout)\n\t\t\tthrow error\n\t\t}\n\t} catch (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.js'\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 flex-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, useRouteLoaderData } 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 { type RootLoaderData } from '#app/root.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\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 data = useRouteLoaderData('root') as RootLoaderData\n\tconst playerPreferences = data?.preferences?.player\n\tconst fontSizePreference = data?.preferences?.fontSize\n\tconst presencePreferences = data?.preferences?.presence\n\tconst playgroundPreferences = data?.preferences?.playground\n\tconst exerciseWarningPreferences = data?.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 flex-grow flex-col gap-4 pb-24\">\n\t\t\t\t<h1 className=\"mb-4 text-h1\">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=\"mb-2 text-body-xl\">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=\"rounded-md border border-border bg-background px-2 py-1 text-foreground\"\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=\"rounded-md border border-border bg-background px-2 py-1 text-foreground\"\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=\"rounded-md border border-border bg-background px-2 py-1 text-foreground\"\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, Link, 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 flex-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=\"rounded-lg border border-destructive bg-destructive/10 p-4\">\n\t\t\t\t\t<h2 className=\"mb-2 text-lg font-semibold text-destructive\">\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-sm text-destructive\">\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=\"mt-2 text-sm text-destructive\">\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=\"rounded bg-background 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=\"mb-3 text-h2\">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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"mb-3 text-h2\">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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"mb-3 text-h2\">Exceptions to the Rule</h2>\n\t\t\t\t\t\t<div className=\"rounded-lg border border-border bg-muted p-4\">\n\t\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\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=\"rounded bg-background 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=\"mt-2 space-y-1 text-sm text-muted-foreground\">\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=\"mb-3 text-h2\">Need a Refresher?</h2>\n\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t\t\tFor a complete overview of the typical workflow, check out the{' '}\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto=\"/onboarding\"\n\t\t\t\t\t\t\t\tclassName=\"text-primary underline hover:no-underline\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tonboarding page\n\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\tto review the expected workflow.\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=\"rounded-lg border border-destructive bg-destructive/10 p-4\">\n\t\t\t\t\t\t\t<h2 className=\"mb-2 text-lg font-semibold text-destructive\">\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=\"rounded border-border\"\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 { type RootLoaderData } from '#app/root.tsx'\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 = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\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=\"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.js'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst apps = await getApps()\n\treturn Response.json({ apps })\n}\n","import { getAllFileCacheEntries } from '@epic-web/workshop-utils/cache.server'\nimport { ensureUndeployed } from '#app/utils/misc.js'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst entries = await getAllFileCacheEntries()\n\treturn Response.json({ entries })\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 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 (!global.__inspector_open__) {\n\t\tglobal.__inspector_open__ = true\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 (global.__inspector_open__) {\n\t\tglobal.__inspector_open__ = false\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 { data, Form, Link, useNavigation } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport {\n\tuseEpicProgress,\n\ttype SerializedProgress,\n} from '#app/routes/progress.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { type Route } from './+types/index.tsx'\nimport {\n\tclearCaches,\n\tclearData,\n\tstartInspector,\n\tstopInspector,\n} from './admin-utils.server.tsx'\n\ndeclare global {\n\tvar __inspector_open__: boolean | undefined\n}\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\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: global.__inspector_open__,\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-blue-500',\n\t\tincomplete: 'bg-yellow-500',\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Progress</h2>\n\t\t\t\t{epicProgress ? (\n\t\t\t\t\t<ul className=\"flex max-h-72 flex-col gap-2 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t{epicProgress.sort(sortProgress).map((progress) => {\n\t\t\t\t\t\t\tconst status = progress.epicCompletedAt\n\t\t\t\t\t\t\t\t? 'completed'\n\t\t\t\t\t\t\t\t: 'incomplete'\n\t\t\t\t\t\t\tconst label = [\n\t\t\t\t\t\t\t\tprogress.epicLessonSlug,\n\t\t\t\t\t\t\t\tprogress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t? `(${progress.epicCompletedAt})`\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\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={progress.epicLessonSlug}\n\t\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-2\"\n\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\t\tclassName={`h-3 w-3 rounded-full ${progressStatus[status]}`}\n\t\t\t\t\t\t\t\t\t\ttitle={status}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t{progress.type === 'unknown' ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-red-500\">\n\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<Icon name=\"Close\" />\n\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</span>\n\t\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\t\t<Link to={linkProgress(progress)}>{label}</Link>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t<Link to={progress.epicLessonUrl}>\n\t\t\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\"></Icon>\n\t\t\t\t\t\t\t\t\t</Link>\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})}\n\t\t\t\t\t</ul>\n\t\t\t\t) : (\n\t\t\t\t\t<p>No progress data</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Commands</h2>\n\t\t\t\t<ul className=\"max-h-48 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t<button name=\"intent\" value=\"clear-caches\">\n\t\t\t\t\t\t\t\tClear local caches\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</Form>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t<button name=\"intent\" value=\"clear-data\">\n\t\t\t\t\t\t\t\tClear all local data (including auth data)\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</Form>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t{data.inspectorRunning ? (\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"stop-inspect\">\n\t\t\t\t\t\t\t\t\t{isStartingInspector\n\t\t\t\t\t\t\t\t\t\t? 'Stopping inspector...'\n\t\t\t\t\t\t\t\t\t\t: 'Stop inspector'}\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) : (\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"inspect\">\n\t\t\t\t\t\t\t\t\t{isStoppingInspector\n\t\t\t\t\t\t\t\t\t\t? 'Starting inspector...'\n\t\t\t\t\t\t\t\t\t\t: 'Start inspector'}\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)}\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Apps</h2>\n\t\t\t\t<ul className=\"max-h-48 list-none overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t{data.apps.map((app) => (\n\t\t\t\t\t\t<li key={app.name} className=\"flex items-center gap-2 py-1\">\n\t\t\t\t\t\t\t{data.processes[app.name] ? (\n\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<Pinger status=\"stopped\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{app.name}\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Processes</h2>\n\t\t\t\t<ul className=\"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t{Object.entries(data.processes).map(([key, process]) => (\n\t\t\t\t\t\t<li key={key}>\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t{key} - Port: {process.port} - PID {process.pid} -{' '}\n\t\t\t\t\t\t\t\t{process.color}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Test Processes</h2>\n\t\t\t\t<ul className=\"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t{Object.entries(data.testProcesses).map(([key, process]) => (\n\t\t\t\t\t\t<li key={key}>\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t{key} - PID {process.pid} - Exit code: {process.exitCode}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\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-gray-500',\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\">\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\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\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\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<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{ENV.EPICSHOP_APP_VERSION ? (\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={`https://github.com/epicweb-dev/epicshop/releases/tag/v${ENV.EPICSHOP_APP_VERSION}`}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{ENV.EPICSHOP_APP_VERSION}\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 { 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\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('grid h-full grid-rows-[1fr,auto]', {\n\t\t\t\t'cursor-wait opacity-30': isNavigating,\n\t\t\t})}\n\t\t>\n\t\t\t<div className=\"overflow-y-auto\">\n\t\t\t\t<Diff diff={data.diff} allApps={data.allApps} />\n\t\t\t</div>\n\t\t\t<div className=\"flex h-16 items-center justify-end border-t\">\n\t\t\t\t<NavChevrons prev={data.prevLink} next={data.nextLink} />\n\t\t\t</div>\n\t\t</div>\n\t)\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 { 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.js'\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\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 { invariantResponse } from '@epic-web/invariant'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetAuthInfo,\n\tmarkOnboardingVideoWatched,\n} from '@epic-web/workshop-utils/db.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport {\n\tdata,\n\tredirect,\n\ttype ActionFunctionArgs,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tForm,\n\tuseLoaderData,\n} from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport {\n\tDeferredEpicVideo,\n\tEpicVideoInfoProvider,\n} from '#app/components/epic-video.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('onboarding')\n\n\tconst { onboardingVideo } = getWorkshopConfig()\n\tconst videoInfos = getEpicVideoInfos([onboardingVideo], { request, timings })\n\treturn data(\n\t\t{ onboardingVideo, videoInfos },\n\t\t{ headers: { 'Server-Timing': timings.toString() } },\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': loaderHeaders.get('Server-Timing') ?? '',\n\t}\n\treturn headers\n}\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tconst data = await request.formData()\n\tconst authInfo = await getAuthInfo()\n\tconst intent = data.get('intent')\n\tinvariantResponse(intent === 'complete', 'Invalid intent')\n\tconst { onboardingVideo } = getWorkshopConfig()\n\tawait markOnboardingVideoWatched(onboardingVideo)\n\n\tif (authInfo) throw redirect('/')\n\telse throw redirect('/login')\n}\n\nexport default function Onboarding() {\n\tconst data = useLoaderData<typeof loader>()\n\treturn (\n\t\t<main className=\"flex h-full w-full flex-col items-center justify-between gap-4\">\n\t\t\t<div className=\"container flex h-full w-full max-w-5xl flex-1 flex-col items-center gap-4 overflow-y-scroll py-12 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t<h1 className=\"text-5xl\">Onboarding</h1>\n\t\t\t\t<p className=\"text-xl\">Welcome to EpicWeb.dev!</p>\n\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\tBefore you get started, <strong>you must watch the tour video</strong>\n\t\t\t\t\t! You're going to be spending a lot of time in here, so it's important\n\t\t\t\t\tyou understand how to work effectively in this workshop\n\t\t\t\t</p>\n\t\t\t\t<div className=\"w-[780px] max-w-full\">\n\t\t\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={data.videoInfos}>\n\t\t\t\t\t\t<DeferredEpicVideo url={data.onboardingVideo} />\n\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<Form method=\"post\" className=\"pb-4\">\n\t\t\t\t<Button name=\"intent\" value=\"complete\" varient=\"primary\">\n\t\t\t\t\tI've watched it. Let's go!\n\t\t\t\t</Button>\n\t\t\t</Form>\n\t\t</main>\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","ConfettiShower","sizeClassName","childrenSizeClassName","AnchorOrLink","Heading","headers","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","href","target","className","duration","Infinity","label","onClick","submit","method","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","user","cuid","cookie","links","rel","tailwindStylesheetUrl","appStylesheetUrl","sizes","meta","getSeoMetaTags","instructor","workshopTitle","workshopSubtitle","timings","makeTimings","workshopConfig","getWorkshopConfig","subtitle","onboardingVideo","onboarding","readOnboardingData","ENV","EPICSHOP_DEPLOYED","tourVideosWatched","includes","URL","url","pathname","getTheme","confettiId","confettiHeaders","getConfetti","toastHeaders","getToast","isOnlinePromise","checkConnectionCached","asyncStuff","promiseHash","userId","getUserId","getPreferences","progress","getProgress","catch","e","console","emptyProgress","getUserInfo","userHasAccess","userHasAccessToWorkshop","apps","getApps","repoUpdates","checkForUpdatesCached","getUnmutedNotifications","exerciseChanges","checkForExerciseChanges","presentUsers","getPresentUsers","mutedNotifications","getMutedNotifications","remoteCommit","updatesAvailable","map","fullPath","relativePath","getEnv","protocol","hostname","port","origin","domain","getDomainUrl","getHints","path","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","fontSize","cn","exerciseWarning","dismissed","ExerciseWarningBanner","Outlet","Confetti","EpicToaster","UpdateToast","EpicProgress","_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","useRouteLoaderData","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","React","buttonRef","Boolean","startAnimation","setStartAnimation","useState","navigationLocationStateFrom","from","navigationLocationPathname","locationPathname","focus","key","latest","Promise","resolve","setTimeout","then","animationPromises","getAnimations","allSettled","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","locationLabel","getLocationLabel","imageUrl","imageUrlSmall","avatarUrl","hasAccess","local","doingLabel","Tooltip","TooltipTrigger","asChild","tabIndex","TooltipContent","line1","line2","useIsWide","makeMediaQueryStore","isWide","isHydrated","useHydrated","setMenuOpenedState","useRevalidationWS","watchPaths","setMenuOpened","document","NoUserBanner","MobileNavigation","onMenuOpenChange","Navigation","exercise","exercisePortion","s","join","host","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","open","initialOpenRef","menuButtonRef","path01Variants","d","closed","path02Variants","moving","path01Controls","path02Controls","toggleMenu","start","handleKeyUp","event","click","addEventListener","removeEventListener","height","viewBox","stroke","strokeWidth","y","handle","getSitemapEntries","logout","deleteCache","redirectWithToast","optOut","setPreferences","useConnectDiscordURL","Account","useUser","config","discordMember","useOptionalDiscordMember","connectDiscordURL","imageUrlLarge","Button","varient","index","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","Array","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","player","ignoredInputs","ignoredRoles","shouldIgnoreHotkey","el","HTMLElement","isIgnored","tagName","getAttribute","isContentEditable","parentElement","PlayerPreferencesSchema","json","flatten","useLatest","MuxPlayer","muxPlayerRef","props","playerPreferences","playerPreferencesFetcher","metadataLoaded","setMetadataLoaded","currentTimeSessionKey","playbackId","currentTime","setCurrentTime","playerPreferencesRef","stored","sessionStorage","getItem","parse","getTime","removeItem","handleUserKeyPress","activeElement","preventDefault","paused","play","pause","forwardSeekOffset","metaKey","ctrlKey","fullscreenElement","exitFullscreen","requestFullscreen","window","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","onLoadedMetadata","minResolution","getMinResolutionValue","maxResolution","getMaxResolutionValue","obj1","obj2","isArray","i","keys1","Object","keys","keys2","resolution","MinResolution","noLessThan480p","noLessThan540p","noLessThan720p","noLessThan1080p","noLessThan1440p","noLessThan2160p","MaxResolution","upTo720p","upTo1080p","upTo1440p","upTo2160p","getRelativePath","getErrorMessage","getFileDescriptorSchema","appFile","union","literal","LaunchSchema","intersection","line","coerce","column","syncTo","array","workshopFile","getAll","syncToIsProvided","values","some","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","FormData","githubPath","LaunchEditor","mdxComponents","matches","rootData","m","ogTitle","ogDescription","desc","readmeFilepath","getWorkshopRoot","dirName","firstStep","articleId","slugify","exerciseReadme","exerciseTitle","firstType","epicVideoInfosPromise","getEpicVideoInfos","instructionsEpicVideoEmbeds","h1","ExerciseNumberRoute","loaderData","firstStepNumber","String","instructionsCode","EpicVideoInfoProvider","Mdx","code","components","ElementScrollRestoration","elementQuery","useRouteError","isRouteErrorResponse","StepRoute","SetPlaygroundSchema","reset","nullable","redirectTo","converseApp","solutionName","problemName","setPlayground","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","withParam","splitCookieName","computeSplitPercent","input","defaultValue","isFinite","min","max","pageTitle","exerciseStepApp","emoji","cacheOptions","allAppsFull","problemApp","solutionApp","requireExerciseApp","getExerciseApp","reqUrl","pathnameParam","searchParams","delete","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","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","pointerEvents","forEach","handleMove","clientX","cleanup","relativeX","onMouseMove","buttons","onTouchMove","firstTouch","touches","body","cursor","userSelect","titleBits","StepMdx","TouchedFiles","diffFilesPromise","NavChevrons","prev","next","role","onMouseDown","onDoubleClick","onTouchStart","reload","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","ansi","useAnsiToHtml","lastMessage","useEventSource","parsed","TestRunner","onRun","AnimatedBars","StopTest","ClearTest","onClear","toHtml","stripCursorMovements","latestOnRun","latestOnClear","onStop","latestOnStop","app1Name","app2Name","app1","app2","getDiffProp","diffCode","compileMarkdownString","discordPostsPromise","fetchDiscordPosts","isUpToDate","tabs","isValidPreview","newSearchParams","set","useSearchParams","preview","navigate","useNavigate","shouldHideTab","tab","activeTab","altDiffUrl","handleDiffTabClick","shiftKey","Tabs","List","preventScrollReset","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","revalidator","useRevalidator","revalidate","ButtonLink","optOutPresence","persistPlayground","dismissExerciseWarning","persist","AccountSettings","fontSizePreference","presencePreferences","playgroundPreferences","exerciseWarningPreferences","isSubmitting","htmlFor","defaultChecked","disabled","Support","repoGroups","match","groups","repoUrl","repoIssuesUrl","org","repo","WorkspaceStructure","AdminLayout","getAllFileCacheEntries","processes","testProcesses","color","getProcesses","devProcesses","pid","inspectorRunning","global","__inspector_open__","clearData","clearCaches","startInspector","stopInspector","sortProgress","linkProgress","epicProgress","isStartingInspector","isStoppingInspector","progressStatus","completed","incomplete","epicLessonUrl","Pinger","colors","pinger","circle","starting","stopped","taken","commitInfo","latestVersion","getCommitInfo","getLatestWorkshopAppVersion","uptime","startDate","workshopCommit","dateFormatted","dayjs","date","format","dateFromNow","fromNow","latestWorkshopAppVersion","startTime","startTimeFormatted","startTimeFromNow","Version","githubRepo","hash","EPICSHOP_APP_VERSION","usingDefaultApp1","at","app1Index","prevApp1Index","prevApp2Index","nextApp1Index","nextApp2Index","prevApp1","prevApp2","nextApp1","nextApp2","prevSearchParams","nextSearchParams","prevLink","nextLink","DiffViewer","paramsWithForcedRefresh","isNavigating","WIDTH","HEIGHT","urlPathname","logo","element","OgLayout","productLogo","productDisplayName","display","flexDirection","justifyContent","alignItems","padding","textWrap","textAlign","renderHtml","renderToStaticMarkup","debug","ogImg","cachified","timingKey","cache","ogCache","ttl","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","backgroundColor","objectFit","gap","avatar","borderRadius","margin","fontWeight","videoInfos","authInfo","markOnboardingVideoWatched","Onboarding","DeferredEpicVideo","SENTRY_HOST","SENTRY_DSN","SENTRY_PROJECT_IDS","SENTRY_PROJECT_ID","envelope","piece","header","dsn","projectId","upstreamSentryURL","generateRobotsTxt","context","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/extended-theme.ts","../../app/utils/misc.tsx","../../app/components/error-boundary.tsx","../../app/components/exercise-warning-banner.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/request-info.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/ui/dialog.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/components/apps.tsx","../../app/utils/launch-editor.server.ts","../../app/routes/launch-editor.tsx","../../app/components/mermaid.tsx","../../app/utils/mdx.tsx","../../app/routes/_app+/exercise+/$exerciseNumber.tsx","../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.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/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+/admin-utils.server.tsx","../../app/routes/admin+/index.tsx","../../app/routes/admin+/version.tsx","../../app/routes/apps.tsx","../../app/routes/diff.tsx","../../app/routes/exercises.tsx","../../app/routes/og.tsx","../../app/routes/onboarding.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 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 { 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 function handleError(\n\terror: unknown,\n\t{ request }: LoaderFunctionArgs | ActionFunctionArgs,\n): void {\n\tif (request.signal.aborted) return\n\tif (ENV.EPICSHOP_IS_PUBLISHED) {\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 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\tlocation: z\n\t\t.object({\n\t\t\tworkshopTitle: z.string().nullable().optional(),\n\t\t\torigin: z.string().nullable().optional(),\n\t\t\texercise: z\n\t\t\t\t.object({\n\t\t\t\t\ttype: z\n\t\t\t\t\t\t.union([z.literal('problem'), z.literal('solution')])\n\t\t\t\t\t\t.nullable()\n\t\t\t\t\t\t.optional(),\n\t\t\t\t\texerciseNumber: z.number().nullable().optional(),\n\t\t\t\t\tstepNumber: z.number().nullable().optional(),\n\t\t\t\t})\n\t\t\t\t.nullable()\n\t\t\t\t.optional(),\n\t\t})\n\t\t.nullable()\n\t\t.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","import {\n\tcachified,\n\tmakeSingletonCache,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getAuthInfo, getPreferences } from '@epic-web/workshop-utils/db.server'\nimport {\n\tgetUserInfo,\n\tuserHasAccessToWorkshop,\n} from '@epic-web/workshop-utils/epic-api.server'\nimport { type Timings } from '@epic-web/workshop-utils/timing.server'\nimport { getUserId } from '@epic-web/workshop-utils/user.server'\nimport { PresenceSchema, partykitBaseUrl, type User } from './presence.js'\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\n\tif (preferences?.presence.optOut || !userId) {\n\t\treturn uniqueUsers(users.filter((u) => u.id !== userId))\n\t} else {\n\t\tconst user: User = { id: userId }\n\t\tconst config = getWorkshopConfig()\n\t\tconst url = request ? new URL(request.url) : undefined\n\t\tuser.location = {\n\t\t\tworkshopTitle: config.title,\n\t\t\torigin: url ? url.origin : undefined,\n\t\t}\n\t\tif (url) {\n\t\t\tif (url.pathname.startsWith('/exercise/')) {\n\t\t\t\tconst [exerciseNumber, stepNumber, type] = url.pathname\n\t\t\t\t\t.split('/')\n\t\t\t\t\t.slice(2)\n\t\t\t\tuser.location.exercise = {\n\t\t\t\t\texerciseNumber: isNaN(Number(exerciseNumber))\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: Number(exerciseNumber),\n\t\t\t\t\tstepNumber: isNaN(Number(stepNumber)) ? null : Number(stepNumber),\n\t\t\t\t\ttype:\n\t\t\t\t\t\ttype === 'problem'\n\t\t\t\t\t\t\t? 'problem'\n\t\t\t\t\t\t\t: type === 'solution'\n\t\t\t\t\t\t\t\t? 'solution'\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (authInfo) {\n\t\t\tconst [userInfo, hasAccess] = await Promise.all([\n\t\t\t\tgetUserInfo({ request, timings }),\n\t\t\t\tuserHasAccessToWorkshop({ request, timings }),\n\t\t\t])\n\n\t\t\tObject.assign(user, {\n\t\t\t\tname: userInfo?.name,\n\t\t\t\tavatarUrl: userInfo?.imageUrlLarge,\n\t\t\t\timageUrlSmall: userInfo?.imageUrlSmall,\n\t\t\t\timageUrlLarge: userInfo?.imageUrlLarge,\n\t\t\t\thasAccess,\n\t\t\t})\n\t\t}\n\n\t\treturn uniqueUsers([...users, user])\n\t}\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| '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\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 Config } from 'tailwindcss'\n\nconst removeProseMargin = {\n\t'> ul > li > *:first-child': {\n\t\tmarginTop: 'unset',\n\t},\n\t'> ul > li > *:last-child': {\n\t\tmarginBottom: 'unset',\n\t},\n\t'> ol > li > *:first-child': {\n\t\tmarginTop: 'unset',\n\t},\n\t'> ol > li > *:last-child': {\n\t\tmarginBottom: 'unset',\n\t},\n}\n\nconst removeCodeBackticks = {\n\t'code::before': {\n\t\tcontent: 'none',\n\t},\n\t'code::after': {\n\t\tcontent: 'none',\n\t},\n}\n\nconst proseColors = {\n\t'*': {\n\t\tcolor: 'hsl(var(--foreground))',\n\t},\n}\n\nexport const extendedTheme = {\n\ttypography: {\n\t\tDEFAULT: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\tsm: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\tbase: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\tlg: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\txl: { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t\t'2xl': { css: [removeProseMargin, proseColors, removeCodeBackticks] },\n\t},\n\tcolors: {\n\t\tgray: {\n\t\t\t'50': '#fafafa',\n\t\t\t'100': '#f5f5f5',\n\t\t\t'200': '#e5e5e5',\n\t\t\t'300': '#d4d4d4',\n\t\t\t'400': '#a3a3a3',\n\t\t\t'500': '#737373',\n\t\t\t'600': '#525252',\n\t\t\t'700': '#404040',\n\t\t\t'800': '#262626',\n\t\t\t'900': '#171717',\n\t\t\t'950': '#0a0a0a',\n\t\t},\n\t\tborder: 'hsl(var(--border))',\n\t\tinput: 'hsl(var(--input))',\n\t\tring: 'hsl(var(--ring))',\n\t\tbackground: 'hsl(var(--background))',\n\t\thighlight: 'hsl(var(--highlight))',\n\t\tforeground: 'hsl(var(--foreground))',\n\t\t'foreground-destructive': 'hsl(var(--foreground-destructive))',\n\t\tscrollbar: 'var(--scrollbar)',\n\t\tprimary: {\n\t\t\tDEFAULT: 'hsl(var(--primary))',\n\t\t\tforeground: 'hsl(var(--primary-foreground))',\n\t\t},\n\t\tsecondary: {\n\t\t\tDEFAULT: 'hsl(var(--secondary))',\n\t\t\tforeground: 'hsl(var(--secondary-foreground))',\n\t\t},\n\t\tdestructive: {\n\t\t\tDEFAULT: 'hsl(var(--destructive))',\n\t\t\tforeground: 'hsl(var(--destructive-foreground))',\n\t\t},\n\t\tmuted: {\n\t\t\tDEFAULT: 'hsl(var(--muted))',\n\t\t\tforeground: 'hsl(var(--muted-foreground))',\n\t\t},\n\t\taccent: {\n\t\t\tDEFAULT: 'hsl(var(--accent))',\n\t\t\tforeground: 'hsl(var(--accent-foreground))',\n\t\t},\n\t\tpopover: {\n\t\t\tDEFAULT: 'hsl(var(--popover))',\n\t\t\tforeground: 'hsl(var(--popover-foreground))',\n\t\t},\n\t\tcard: {\n\t\t\tDEFAULT: 'hsl(var(--card))',\n\t\t\tforeground: 'hsl(var(--card-foreground))',\n\t\t},\n\t},\n\tborderRadius: {\n\t\tlg: `var(--radius)`,\n\t\tmd: `calc(var(--radius) - 2px)`,\n\t\tsm: 'calc(var(--radius) - 4px)',\n\t},\n\tfontSize: {\n\t\t// 1rem = 16px\n\t\t/** 80px size / 84px high / bold */\n\t\tmega: ['5rem', { lineHeight: '5.25rem', fontWeight: '700' }],\n\t\t/** 56px size / 62px high / bold */\n\t\th1: ['3.5rem', { lineHeight: '3.875rem', fontWeight: '700' }],\n\t\t/** 40px size / 48px high / bold */\n\t\th2: ['2.5rem', { lineHeight: '3rem', fontWeight: '700' }],\n\t\t/** 32px size / 36px high / bold */\n\t\th3: ['2rem', { lineHeight: '2.25rem', fontWeight: '700' }],\n\t\t/** 28px size / 36px high / bold */\n\t\th4: ['1.75rem', { lineHeight: '2.25rem', fontWeight: '700' }],\n\t\t/** 24px size / 32px high / bold */\n\t\th5: ['1.5rem', { lineHeight: '2rem', fontWeight: '700' }],\n\t\t/** 16px size / 20px high / bold */\n\t\th6: ['1rem', { lineHeight: '1.25rem', fontWeight: '700' }],\n\n\t\t/** 48px size / 52px high / normal */\n\t\t'body-5xl': ['3rem', { lineHeight: '3.25rem' }],\n\t\t/** 40px size / 44px high / normal */\n\t\t'body-4xl': ['2.5rem', { lineHeight: '2.75rem' }],\n\t\t/** 36px size / 40px high / normal */\n\t\t'body-3xl': ['2.25rem', { lineHeight: '2.5rem' }],\n\t\t/** 32px size / 36px high / normal */\n\t\t'body-2xl': ['2rem', { lineHeight: '2.25rem' }],\n\t\t/** 28px size / 36px high / normal */\n\t\t'body-xl': ['1.75rem', { lineHeight: '2.25rem' }],\n\t\t/** 24px size / 32px high / normal */\n\t\t'body-lg': ['1.5rem', { lineHeight: '2rem' }],\n\t\t/** 20px size / 28px high / normal */\n\t\t'body-md': ['1.25rem', { lineHeight: '1.75rem' }],\n\t\t/** 16px size / 20px high / normal */\n\t\t'body-sm': ['1rem', { lineHeight: '1.25rem' }],\n\t\t/** 14px size / 18px high / normal */\n\t\t'body-xs': ['0.875rem', { lineHeight: '1.125rem' }],\n\t\t/** 12px size / 16px high / normal */\n\t\t'body-2xs': ['0.75rem', { lineHeight: '1rem' }],\n\n\t\t/** 18px size / 24px high / semibold */\n\t\tcaption: ['1.125rem', { lineHeight: '1.5rem', fontWeight: '600' }],\n\t\t/** 12px size / 16px high / bold */\n\t\tbutton: ['0.75rem', { lineHeight: '1rem', fontWeight: '700' }],\n\t},\n\tkeyframes: {\n\t\t'accordion-down': {\n\t\t\tfrom: { height: '0' },\n\t\t\tto: { height: 'var(--radix-accordion-content-height)' },\n\t\t},\n\t\t'accordion-up': {\n\t\t\tfrom: { height: 'var(--radix-accordion-content-height)' },\n\t\t\tto: { height: '0' },\n\t\t},\n\t},\n\tanimation: {\n\t\t'accordion-down': 'accordion-down 0.2s ease-out',\n\t\t'accordion-up': 'accordion-up 0.2s ease-out',\n\t},\n} satisfies Config['theme']\n","import { type ExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport slugify from '@sindresorhus/slugify'\nimport { clsx, type ClassValue } from 'clsx'\nimport * as React from 'react'\nimport { useEffect, 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'\nimport { extendedTheme } from './extended-theme.ts'\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\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 left-0 top-1/2 -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\nfunction formatColors() {\n\tconst colors = []\n\tfor (const [key, color] of Object.entries(extendedTheme.colors)) {\n\t\tif (typeof color === 'string') {\n\t\t\tcolors.push(key)\n\t\t} else {\n\t\t\tconst colorGroup = Object.keys(color).map((subKey) =>\n\t\t\t\tsubKey === 'DEFAULT' ? '' : subKey,\n\t\t\t)\n\t\t\tcolors.push({ [key]: colorGroup })\n\t\t}\n\t}\n\treturn colors\n}\n\nconst customTwMerge = extendTailwindMerge({\n\textend: {\n\t\ttheme: {\n\t\t\tcolors: formatColors(),\n\t\t\tborderRadius: Object.keys(extendedTheme.borderRadius),\n\t\t},\n\t\tclassGroups: {\n\t\t\t'font-size': [{ text: Object.keys(extendedTheme.fontSize) }],\n\t\t\tanimate: [{ animate: Object.keys(extendedTheme.animation) }],\n\t\t},\n\t},\n})\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? undefined\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\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","// 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 } 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\nexport function GeneralErrorBoundary({\n\tdefaultStatusHandler = ({ error }) => (\n\t\t<p>\n\t\t\t{error.status} {error.data}\n\t\t</p>\n\t),\n\tstatusHandlers,\n\tunexpectedErrorHandler = (error) => <p>{getErrorMessage(error)}</p>,\n}: {\n\tdefaultStatusHandler?: StatusHandler\n\tstatusHandlers?: Record<number, StatusHandler>\n\tunexpectedErrorHandler?: (error: unknown) => React.ReactNode | null\n}) {\n\tconst error = useRouteError()\n\tconst params = useParams()\n\tconst isResponse = isRouteErrorResponse(error)\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\tif (typeof document !== 'undefined') {\n\t\tconsole.error(error)\n\t}\n\n\treturn (\n\t\t<div className=\"container flex items-center justify-center p-20 text-h2\">\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=\"fixed left-0 right-0 top-0 z-50 border-b border-destructive bg-destructive\">\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=\"container relative z-0 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=\"h-5 w-5 text-destructive-foreground\"\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-sm font-semibold text-destructive-foreground\">\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-xs text-destructive-foreground/80\">\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=\"flex items-center gap-2 text-xs text-destructive-foreground\">\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 { 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 left-0 top-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'h-full w-0 bg-highlight 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'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md 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',\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 { useRouteLoaderData } from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\n\n/**\n * @returns the request info from the root loader\n */\nexport function useRequestInfo() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\n\treturn data.requestInfo\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 './request-info.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-[10px] text-foreground-destructive\">\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\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\nexport function dataWithPE<Data>(\n\tformData: FormData,\n\t...args: Parameters<typeof data<Data>>\n) {\n\tensureProgressiveEnhancement(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.js'\nimport { useRequestInfo } from '#app/utils/request-info.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(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 './request-info.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, useRouteLoaderData } from 'react-router'\nimport { z } from 'zod'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { useIsOnline } from './online.ts'\nimport { useRequestInfo } from './request-info.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 = useRouteLoaderData('root') as RootLoaderData\n\treturn data?.preferences?.presence ?? null\n}\n\nexport function useOptionalWorkshopTitle() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\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 useUsersLocation() {\n\tconst workshopTitle = useOptionalWorkshopTitle()\n\tconst requestInfo = useRequestInfo()\n\tconst rawParams = useParams()\n\tconst paramsResult = ExerciseAppParamsSchema.safeParse(rawParams)\n\tconst params = paramsResult.success ? paramsResult.data : null\n\n\treturn {\n\t\tworkshopTitle,\n\t\torigin: requestInfo.origin,\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 {\n\t\tuserHasAccess = false,\n\t\tuserId,\n\t\tpresence,\n\t} = (useRouteLoaderData('root') as RootLoaderData) ?? {}\n\tconst [users, setUsers] = useState(presence?.users ?? [])\n\tconst usersLocation = useUsersLocation()\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\tlet message: Message | null = null\n\tif (user) {\n\t\tif (prefs?.optOut) {\n\t\t\tmessage = { type: 'remove-user', payload: { id: user.id } }\n\t\t} else {\n\t\t\tmessage = {\n\t\t\t\ttype: 'add-user',\n\t\t\t\tpayload: {\n\t\t\t\t\tid: user.id,\n\t\t\t\t\tname: user.name,\n\t\t\t\t\thasAccess: userHasAccess,\n\t\t\t\t\timageUrlSmall: user.imageUrlSmall,\n\t\t\t\t\timageUrlLarge: user.imageUrlLarge,\n\t\t\t\t\tlocation: usersLocation,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t} else if (userId?.id) {\n\t\tmessage = {\n\t\t\ttype: 'add-user',\n\t\t\tpayload: { id: userId.id, location: usersLocation },\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\nfunction scoreUsers(\n\tuser: { id?: string | null; location: User['location'] },\n\tusers: Array<User>,\n) {\n\tconst { location } = user\n\tconst scoredUsers = users.map((user) => {\n\t\tlet score = 0\n\t\tconst available = 5\n\t\tif (user.hasAccess) {\n\t\t\tscore += 1\n\t\t}\n\t\tif (location?.workshopTitle === user.location?.workshopTitle) {\n\t\t\tscore += 1\n\t\t\tif (\n\t\t\t\tlocation?.exercise?.exerciseNumber &&\n\t\t\t\tlocation.exercise.exerciseNumber ===\n\t\t\t\t\tuser.location?.exercise?.exerciseNumber\n\t\t\t) {\n\t\t\t\tscore += 1\n\t\t\t\tif (\n\t\t\t\t\tlocation.exercise.stepNumber &&\n\t\t\t\t\tlocation.exercise.stepNumber === user.location.exercise.stepNumber\n\t\t\t\t) {\n\t\t\t\t\tscore += 1\n\t\t\t\t\tif (\n\t\t\t\t\t\tlocation.exercise.type &&\n\t\t\t\t\t\tlocation.exercise.type === user.location.exercise.type\n\t\t\t\t\t) {\n\t\t\t\t\t\tscore += 1\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { user, score: Math.floor((score / available) * 10) / 10 }\n\t})\n\treturn scoredUsers.sort((a, b) => {\n\t\tif (a.user.id === user?.id) return -1\n\t\tif (b.user.id === user?.id) return 1\n\t\tif (a.score === b.score) return 0\n\t\treturn a.score > b.score ? -1 : 1\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 } = (useRouteLoaderData('root') as RootLoaderData) ?? {}\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 { createId as cuid } from '@paralleldrive/cuid2'\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\tgetPreferences,\n\treadOnboardingData,\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 { checkConnectionCached } from '@epic-web/workshop-utils/utils.server'\n\nimport {\n\tdata,\n\tredirect,\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 { 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 = ({ data }) => {\n\tif (!data) return []\n\n\treturn getSeoMetaTags({\n\t\tinstructor: data.instructor,\n\t\ttitle: data.workshopTitle,\n\t\tdescription: data.workshopSubtitle,\n\t\trequestInfo: data.requestInfo,\n\t})\n}\n\nexport type RootLoaderData = Route.ComponentProps['loaderData']\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\tonboardingVideo,\n\t} = workshopConfig\n\n\tconst onboarding = await readOnboardingData()\n\tif (\n\t\t!ENV.EPICSHOP_DEPLOYED &&\n\t\t!onboarding?.tourVideosWatched.includes(onboardingVideo)\n\t) {\n\t\tif (new URL(request.url).pathname !== '/onboarding') {\n\t\t\tthrow redirect('/onboarding')\n\t\t}\n\t}\n\tconst theme = getTheme(request)\n\tconst { confettiId, headers: confettiHeaders } = getConfetti(request)\n\tconst { toast, headers: toastHeaders } = await getToast(request)\n\tconst isOnlinePromise = checkConnectionCached({ 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})\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\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'antialiased h-screen-safe',\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</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=\"whitespace-pre-wrap break-all text-body-lg\">\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 { useRouteLoaderData } from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\n\nexport function useWorkshopConfig() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\n\tif (!data?.workshopConfig) {\n\t\tthrow new Error('useWorkshopConfig requires a workshopConfig.')\n\t}\n\treturn data.workshopConfig\n}\n","import { useTheme } from '#app/routes/theme/index.js'\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/request-info.js'\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 * 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'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\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'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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%] 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=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity data-[state=open]:bg-accent data-[state=open]:text-muted-foreground hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 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 font-semibold leading-none 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-sm text-muted-foreground', 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 { useRouteLoaderData } from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\n\nexport function useOptionalUser() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\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 = useRouteLoaderData('root') as RootLoaderData\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 = useRouteLoaderData('root') as RootLoaderData\n\treturn data?.userHasAccess ?? false\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\tuseRouteLoaderData,\n\ttype ActionFunctionArgs,\n} from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { createConfettiHeaders } from '#app/utils/confetti.server.ts'\nimport { combineHeaders, ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.js'\nimport { createToastHeaders } from '#app/utils/toast.server.ts'\n\nexport function useEpicProgress() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\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(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=\"absolute right-0 h-20 w-20 rounded-full bg-foreground/20\"\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'duration-100 group-hover:bg-background': !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.js'\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTrigger,\n} from '#app/components/ui/dialog.js'\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.js'\nimport { cn, getExercisePath, getExerciseStepPath } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { usePresence, type User } 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 locationLabel = getLocationLabel(user.location)\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 = user.location?.origin?.includes('localhost')\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>\n\t\t\t\t\t\t\t\t\t{imageUrl ? (\n\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\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\tclassName={cn(\n\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\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\tsrc={imageUrl}\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<div\n\t\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\t\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\t\tclassName={cn(\n\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\tscoreClassNames,\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<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t)}\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>\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{locationLabel\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{locationLabel?.line1 ? (\n\t\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line1}</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t{locationLabel?.line2 ? (\n\t\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line2}</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\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>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\ttabIndex={0}\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'flex items-center justify-center rounded-full border bg-accent text-xs text-accent-foreground',\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-ellipsis whitespace-nowrap text-center',\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\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 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-gradient-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=\"flex w-full flex-grow flex-col justify-between overflow-x-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar\"\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 whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap px-2 py-0.5 pr-3 outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"ml-4 mt-2 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'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"font-semibold leading-tight\"\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=\"ml-3 mt-0.5 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 whitespace-nowrap px-2 py-0.5 pr-3 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:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap px-2 py-0.5 pr-3 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:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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'relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap text-lg font-bold 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'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"flex-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 flex-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=\"flex-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=\"flex-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=\"flex flex-grow flex-col justify-between overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar\"\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 whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap px-2 py-0.5 pr-3 outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"ml-4 mt-2 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'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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=\"font-semibold leading-tight\"\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=\"ml-3 mt-0.5 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 whitespace-nowrap px-2 py-0.5 pr-3 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:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap px-2 py-0.5 pr-3 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:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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'relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 whitespace-nowrap text-lg font-bold 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'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background 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 flex-grow flex-col justify-center\">\n\t\t\t\t\t\t\t<div className=\"orientation-sideways w-full font-mono text-sm font-medium uppercase leading-none\">\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 flex-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=\"flex-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=\"flex-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 pl-3 pt-[15px]\">\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 flex-shrink-0 items-center justify-between overflow-hidden border-r sm:w-full sm:border-b sm:border-r-0',\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 whitespace-nowrap font-mono text-sm 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'\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 w-fit border-2 border-foreground bg-foreground\">\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 w-fit border-2 border-foreground bg-foreground\">\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","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.js'\nimport { useOptionalDiscordMember, useUser } from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { 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\n\treturn (\n\t\t<main className=\"container flex h-full w-full max-w-3xl flex-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=\"flex-shrink-0\" size=\"lg\" />\n\t\t\t)}\n\t\t\t<h1 className=\"mb-1 text-2xl\">Your Account</h1>\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=\"/onboarding\" className=\"underline\">\n\t\t\t\t\t\tReview onboarding\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\tconst url = new URL(request.headers.get('referer') ?? '')\n\tconst appName = url.pathname.split('/').pop()\n\treturn appName\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\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 flex-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\tuseRouteLoaderData,\n} from 'react-router'\nimport { z } from 'zod'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { useDebounce } from '#app/utils/misc.tsx'\nimport './mux-player.css'\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 data = useRouteLoaderData('root') as RootLoaderData\n\treturn data?.preferences?.player ?? null\n}\n\ntype MuxPlayerProps = React.ComponentProps<typeof RealMuxPlayer>\n\nconst ignoredInputs = [\n\t'INPUT',\n\t'SELECT',\n\t'BUTTON',\n\t'TEXTAREA',\n\t'MUX-PLAYER',\n\t'SUMMARY',\n]\n\nconst ignoredRoles = ['button', 'option', 'combobox', 'tab', 'tablist']\n\nfunction shouldIgnoreHotkey(el: unknown) {\n\tlet current = el\n\twhile (current) {\n\t\tif (!(current instanceof HTMLElement)) return false\n\n\t\tconst isIgnored =\n\t\t\tignoredInputs.includes(current.tagName) ||\n\t\t\tignoredRoles.includes(current.getAttribute('role') || '') ||\n\t\t\tcurrent.isContentEditable\n\t\tif (isIgnored) return true\n\t\tcurrent = current.parentElement\n\t}\n\n\treturn false\n}\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\tReact.useEffect(() => {\n\t\tfunction handleUserKeyPress(e: KeyboardEvent) {\n\t\t\tif (!muxPlayerRef.current) return\n\t\t\tconst activeElement = document.activeElement\n\n\t\t\tif (shouldIgnoreHotkey(activeElement)) return\n\t\t\tif (shouldIgnoreHotkey(e.target)) return\n\n\t\t\tif (e.key === ' ') {\n\t\t\t\te.preventDefault()\n\t\t\t\tif (muxPlayerRef.current.paused) {\n\t\t\t\t\t// Only attempt to play if metadata is loaded to avoid AbortError\n\t\t\t\t\tif (metadataLoaded) {\n\t\t\t\t\t\tvoid muxPlayerRef.current.play().catch(() => {})\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tmuxPlayerRef.current.pause()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (e.key === 'ArrowRight') {\n\t\t\t\te.preventDefault()\n\t\t\t\tmuxPlayerRef.current.currentTime =\n\t\t\t\t\tmuxPlayerRef.current.currentTime +\n\t\t\t\t\t(muxPlayerRef.current.forwardSeekOffset || 10)\n\t\t\t}\n\t\t\tif (e.key === 'ArrowLeft') {\n\t\t\t\te.preventDefault()\n\t\t\t\tmuxPlayerRef.current.currentTime =\n\t\t\t\t\tmuxPlayerRef.current.currentTime -\n\t\t\t\t\t(muxPlayerRef.current.forwardSeekOffset || 10)\n\t\t\t}\n\t\t\tif (e.key === 'f' && !e.metaKey && !e.ctrlKey) {\n\t\t\t\te.preventDefault()\n\t\t\t\tvoid (document.fullscreenElement\n\t\t\t\t\t? document.exitFullscreen()\n\t\t\t\t\t: muxPlayerRef.current.requestFullscreen())\n\t\t\t}\n\t\t}\n\t\twindow.document.addEventListener('keydown', handleUserKeyPress)\n\t\treturn () => {\n\t\t\twindow.document.removeEventListener('keydown', handleUserKeyPress)\n\t\t}\n\t}, [muxPlayerRef, metadataLoaded])\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, 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://twitter.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\tonLoadedMetadata={() => setMetadataLoaded(true)}\n\t\t\t\tminResolution={getMinResolutionValue(playerPreferences?.minResolution)}\n\t\t\t\tmaxResolution={getMaxResolutionValue(playerPreferences?.maxResolution)}\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 'EpicWeb.dev 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 'EpicWeb.dev Video'\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 flex-shrink-0 shadow-lg\">\n\t\t\t\t<div className=\"not-prose absolute inset-0 z-10 flex items-center justify-center p-8 text-foreground-destructive\">\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 flex-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({ url, title }: { url: string; title: string }) {\n\treturn (\n\t\t<a\n\t\t\thref={url}\n\t\t\ttarget=\"_blank\"\n\t\t\tclassName=\"flex items-center gap-1 text-base no-underline opacity-70 transition hover:underline hover:opacity-100\"\n\t\t\trel=\"noreferrer\"\n\t\t>\n\t\t\t<Icon className=\"flex-shrink-0\" name=\"Video\" size=\"lg\" />\n\t\t\t{title} <span aria-hidden>↗︎</span>\n\t\t</a>\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 = (\n\t\t<div>\n\t\t\t<VideoLink url={url} title={title} />\n\t\t</div>\n\t)\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/>\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}: {\n\turl: string\n\ttitle?: string\n\tmuxPlaybackId: string\n\ttranscript: string\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={timestampIndexStart}>{textBeforeTimestamp}</span>,\n\t\t)\n\t\ttranscriptElements.push(\n\t\t\t<button\n\t\t\t\tkey={timestamp}\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 url={urlString} title={title} />\n\t\t\t\t<details>\n\t\t\t\t\t<summary>Transcript</summary>\n\t\t\t\t\t<div className=\"whitespace-pre-line rounded-md bg-accent p-2 text-accent-foreground\">\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 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 (url.host === 'www.epicai.pro') {\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 { useRouteLoaderData } from 'react-router'\nimport { type RootLoaderData } from '#app/root.tsx'\n\nexport function useApps() {\n\tconst data = useRouteLoaderData('root') as RootLoaderData\n\tif (!data) {\n\t\tthrow new Error('useApps requires a data object from the root loader')\n\t}\n\treturn data.apps\n}\n","// copied (and barely modified) from create-react-app:\n// https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7/packages/react-dev-utils/launchEditor.js\n\nimport child_process from 'child_process'\nimport fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport { getRelativePath } from '@epic-web/workshop-utils/apps.server'\nimport fsExtra from 'fs-extra'\nimport shellQuote from 'shell-quote'\n\nfunction readablePath(filePath: string = '') {\n\tconst relative = getRelativePath(filePath)\n\tconst name = path.basename(relative)\n\tconst dir = path.dirname(relative)\n\treturn `'${name}' from:\\n'${dir}'`\n}\n\nfunction isTerminalEditor(editor: string) {\n\tswitch (editor) {\n\t\tcase 'vim':\n\t\tcase 'emacs':\n\t\tcase 'nano':\n\t\t\treturn true\n\t}\n\treturn false\n}\n\n// Map from full process name to binary that starts the process\n// We can't just re-use full process name, because it will spawn a new instance\n// of the app every time\nconst COMMON_EDITORS_OSX = {\n\t'/Applications/Atom.app/Contents/MacOS/Atom': 'atom',\n\t'/Applications/Atom Beta.app/Contents/MacOS/Atom Beta':\n\t\t'/Applications/Atom Beta.app/Contents/MacOS/Atom Beta',\n\t'/Applications/Brackets.app/Contents/MacOS/Brackets': 'brackets',\n\t'/Applications/Sublime Text.app/Contents/MacOS/Sublime Text':\n\t\t'/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl',\n\t'/Applications/Sublime Text Dev.app/Contents/MacOS/Sublime Text':\n\t\t'/Applications/Sublime Text Dev.app/Contents/SharedSupport/bin/subl',\n\t'/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2':\n\t\t'/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl',\n\t'/Applications/Cursor.app/Contents/MacOS/Cursor': 'cursor',\n\t'/Applications/Visual Studio Code.app/Contents/MacOS/Electron': 'code',\n\t'/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron':\n\t\t'code-insiders',\n\t'/Applications/VSCodium.app/Contents/MacOS/Electron': 'vscodium',\n\t'/Applications/AppCode.app/Contents/MacOS/appcode':\n\t\t'/Applications/AppCode.app/Contents/MacOS/appcode',\n\t'/Applications/CLion.app/Contents/MacOS/clion':\n\t\t'/Applications/CLion.app/Contents/MacOS/clion',\n\t'/Applications/IntelliJ IDEA.app/Contents/MacOS/idea':\n\t\t'/Applications/IntelliJ IDEA.app/Contents/MacOS/idea',\n\t'/Applications/PhpStorm.app/Contents/MacOS/phpstorm':\n\t\t'/Applications/PhpStorm.app/Contents/MacOS/phpstorm',\n\t'/Applications/PyCharm.app/Contents/MacOS/pycharm':\n\t\t'/Applications/PyCharm.app/Contents/MacOS/pycharm',\n\t'/Applications/PyCharm CE.app/Contents/MacOS/pycharm':\n\t\t'/Applications/PyCharm CE.app/Contents/MacOS/pycharm',\n\t'/Applications/RubyMine.app/Contents/MacOS/rubymine':\n\t\t'/Applications/RubyMine.app/Contents/MacOS/rubymine',\n\t'/Applications/WebStorm.app/Contents/MacOS/webstorm':\n\t\t'/Applications/WebStorm.app/Contents/MacOS/webstorm',\n\t'/Applications/MacVim.app/Contents/MacOS/MacVim': 'mvim',\n\t'/Applications/GoLand.app/Contents/MacOS/goland':\n\t\t'/Applications/GoLand.app/Contents/MacOS/goland',\n\t'/Applications/Rider.app/Contents/MacOS/rider':\n\t\t'/Applications/Rider.app/Contents/MacOS/rider',\n\t'/Applications/Zed/Zed.app/Contents/MacOS/zed': 'zed',\n} as const\n\nconst COMMON_EDITORS_LINUX = {\n\tatom: 'atom',\n\tBrackets: 'brackets',\n\tcursor: 'cursor',\n\tcode: 'code',\n\t'code-insiders': 'code-insiders',\n\tvscodium: 'vscodium',\n\temacs: 'emacs',\n\tgvim: 'gvim',\n\t'idea.sh': 'idea',\n\t'phpstorm.sh': 'phpstorm',\n\t'pycharm.sh': 'pycharm',\n\t'rubymine.sh': 'rubymine',\n\tsublime_text: 'sublime_text',\n\tvim: 'vim',\n\t'webstorm.sh': 'webstorm',\n\t'goland.sh': 'goland',\n\t'rider.sh': 'rider',\n\tzed: 'zed',\n}\n\nconst COMMON_EDITORS_WIN = [\n\t'Brackets.exe',\n\t'Cursor.exe',\n\t'Code.exe',\n\t'Code - Insiders.exe',\n\t'VSCodium.exe',\n\t'atom.exe',\n\t'sublime_text.exe',\n\t'notepad++.exe',\n\t'clion.exe',\n\t'clion64.exe',\n\t'idea.exe',\n\t'idea64.exe',\n\t'phpstorm.exe',\n\t'phpstorm64.exe',\n\t'pycharm.exe',\n\t'pycharm64.exe',\n\t'rubymine.exe',\n\t'rubymine64.exe',\n\t'webstorm.exe',\n\t'webstorm64.exe',\n\t'goland.exe',\n\t'goland64.exe',\n\t'rider.exe',\n\t'rider64.exe',\n\t'zed.exe',\n]\n\n// Transpiled version of: /^([A-Za-z]:[/\\\\])?[\\p{L}0-9/.\\-_\\\\]+$/u\n// Non-transpiled version requires support for Unicode property regex. Allows\n// alphanumeric characters, periods, dashes, slashes, and underscores.\nconst WINDOWS_FILE_NAME_WHITELIST =\n\t/^([A-Za-z]:[/\\\\])?(?:[\\x2D-9A-Z\\\\_a-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u08A0-\\u08B4\\u08B6-\\u08BD\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C60\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C88\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FEF\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7B9\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB65\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]|\\uD800[\\uDC00-\\uDC0B\\uDC0D-\\uDC26\\uDC28-\\uDC3A\\uDC3C\\uDC3D\\uDC3F-\\uDC4D\\uDC50-\\uDC5D\\uDC80-\\uDCFA\\uDE80-\\uDE9C\\uDEA0-\\uDED0\\uDF00-\\uDF1F\\uDF2D-\\uDF40\\uDF42-\\uDF49\\uDF50-\\uDF75\\uDF80-\\uDF9D\\uDFA0-\\uDFC3\\uDFC8-\\uDFCF]|\\uD801[\\uDC00-\\uDC9D\\uDCB0-\\uDCD3\\uDCD8-\\uDCFB\\uDD00-\\uDD27\\uDD30-\\uDD63\\uDE00-\\uDF36\\uDF40-\\uDF55\\uDF60-\\uDF67]|\\uD802[\\uDC00-\\uDC05\\uDC08\\uDC0A-\\uDC35\\uDC37\\uDC38\\uDC3C\\uDC3F-\\uDC55\\uDC60-\\uDC76\\uDC80-\\uDC9E\\uDCE0-\\uDCF2\\uDCF4\\uDCF5\\uDD00-\\uDD15\\uDD20-\\uDD39\\uDD80-\\uDDB7\\uDDBE\\uDDBF\\uDE00\\uDE10-\\uDE13\\uDE15-\\uDE17\\uDE19-\\uDE35\\uDE60-\\uDE7C\\uDE80-\\uDE9C\\uDEC0-\\uDEC7\\uDEC9-\\uDEE4\\uDF00-\\uDF35\\uDF40-\\uDF55\\uDF60-\\uDF72\\uDF80-\\uDF91]|\\uD803[\\uDC00-\\uDC48\\uDC80-\\uDCB2\\uDCC0-\\uDCF2\\uDD00-\\uDD23\\uDF00-\\uDF1C\\uDF27\\uDF30-\\uDF45]|\\uD804[\\uDC03-\\uDC37\\uDC83-\\uDCAF\\uDCD0-\\uDCE8\\uDD03-\\uDD26\\uDD44\\uDD50-\\uDD72\\uDD76\\uDD83-\\uDDB2\\uDDC1-\\uDDC4\\uDDDA\\uDDDC\\uDE00-\\uDE11\\uDE13-\\uDE2B\\uDE80-\\uDE86\\uDE88\\uDE8A-\\uDE8D\\uDE8F-\\uDE9D\\uDE9F-\\uDEA8\\uDEB0-\\uDEDE\\uDF05-\\uDF0C\\uDF0F\\uDF10\\uDF13-\\uDF28\\uDF2A-\\uDF30\\uDF32\\uDF33\\uDF35-\\uDF39\\uDF3D\\uDF50\\uDF5D-\\uDF61]|\\uD805[\\uDC00-\\uDC34\\uDC47-\\uDC4A\\uDC80-\\uDCAF\\uDCC4\\uDCC5\\uDCC7\\uDD80-\\uDDAE\\uDDD8-\\uDDDB\\uDE00-\\uDE2F\\uDE44\\uDE80-\\uDEAA\\uDF00-\\uDF1A]|\\uD806[\\uDC00-\\uDC2B\\uDCA0-\\uDCDF\\uDCFF\\uDE00\\uDE0B-\\uDE32\\uDE3A\\uDE50\\uDE5C-\\uDE83\\uDE86-\\uDE89\\uDE9D\\uDEC0-\\uDEF8]|\\uD807[\\uDC00-\\uDC08\\uDC0A-\\uDC2E\\uDC40\\uDC72-\\uDC8F\\uDD00-\\uDD06\\uDD08\\uDD09\\uDD0B-\\uDD30\\uDD46\\uDD60-\\uDD65\\uDD67\\uDD68\\uDD6A-\\uDD89\\uDD98\\uDEE0-\\uDEF2]|\\uD808[\\uDC00-\\uDF99]|\\uD809[\\uDC80-\\uDD43]|[\\uD80C\\uD81C-\\uD820\\uD840-\\uD868\\uD86A-\\uD86C\\uD86F-\\uD872\\uD874-\\uD879][\\uDC00-\\uDFFF]|\\uD80D[\\uDC00-\\uDC2E]|\\uD811[\\uDC00-\\uDE46]|\\uD81A[\\uDC00-\\uDE38\\uDE40-\\uDE5E\\uDED0-\\uDEED\\uDF00-\\uDF2F\\uDF40-\\uDF43\\uDF63-\\uDF77\\uDF7D-\\uDF8F]|\\uD81B[\\uDE40-\\uDE7F\\uDF00-\\uDF44\\uDF50\\uDF93-\\uDF9F\\uDFE0\\uDFE1]|\\uD821[\\uDC00-\\uDFF1]|\\uD822[\\uDC00-\\uDEF2]|\\uD82C[\\uDC00-\\uDD1E\\uDD70-\\uDEFB]|\\uD82F[\\uDC00-\\uDC6A\\uDC70-\\uDC7C\\uDC80-\\uDC88\\uDC90-\\uDC99]|\\uD835[\\uDC00-\\uDC54\\uDC56-\\uDC9C\\uDC9E\\uDC9F\\uDCA2\\uDCA5\\uDCA6\\uDCA9-\\uDCAC\\uDCAE-\\uDCB9\\uDCBB\\uDCBD-\\uDCC3\\uDCC5-\\uDD05\\uDD07-\\uDD0A\\uDD0D-\\uDD14\\uDD16-\\uDD1C\\uDD1E-\\uDD39\\uDD3B-\\uDD3E\\uDD40-\\uDD44\\uDD46\\uDD4A-\\uDD50\\uDD52-\\uDEA5\\uDEA8-\\uDEC0\\uDEC2-\\uDEDA\\uDEDC-\\uDEFA\\uDEFC-\\uDF14\\uDF16-\\uDF34\\uDF36-\\uDF4E\\uDF50-\\uDF6E\\uDF70-\\uDF88\\uDF8A-\\uDFA8\\uDFAA-\\uDFC2\\uDFC4-\\uDFCB]|\\uD83A[\\uDC00-\\uDCC4\\uDD00-\\uDD43]|\\uD83B[\\uDE00-\\uDE03\\uDE05-\\uDE1F\\uDE21\\uDE22\\uDE24\\uDE27\\uDE29-\\uDE32\\uDE34-\\uDE37\\uDE39\\uDE3B\\uDE42\\uDE47\\uDE49\\uDE4B\\uDE4D-\\uDE4F\\uDE51\\uDE52\\uDE54\\uDE57\\uDE59\\uDE5B\\uDE5D\\uDE5F\\uDE61\\uDE62\\uDE64\\uDE67-\\uDE6A\\uDE6C-\\uDE72\\uDE74-\\uDE77\\uDE79-\\uDE7C\\uDE7E\\uDE80-\\uDE89\\uDE8B-\\uDE9B\\uDEA1-\\uDEA3\\uDEA5-\\uDEA9\\uDEAB-\\uDEBB]|\\uD869[\\uDC00-\\uDED6\\uDF00-\\uDFFF]|\\uD86D[\\uDC00-\\uDF34\\uDF40-\\uDFFF]|\\uD86E[\\uDC00-\\uDC1D\\uDC20-\\uDFFF]|\\uD873[\\uDC00-\\uDEA1\\uDEB0-\\uDFFF]|\\uD87A[\\uDC00-\\uDFE0]|\\uD87E[\\uDC00-\\uDE1D])+$/\n\nfunction addWorkspaceToArgumentsIfExists(\n\targs: Array<string>,\n\tworkspace: string | null,\n) {\n\tif (workspace) {\n\t\targs.unshift(workspace)\n\t}\n\treturn args\n}\n\nfunction getArgumentsForLineNumber(\n\teditor: string,\n\tfileName: string,\n\tlineNumber: number,\n\tcolNumber: number | undefined,\n\tworkspace: string | null,\n) {\n\tconst editorBasename = path.basename(editor).replace(/\\.(exe|cmd|bat)$/i, '')\n\tswitch (editorBasename) {\n\t\tcase 'atom':\n\t\tcase 'Atom':\n\t\tcase 'Atom Beta':\n\t\tcase 'subl':\n\t\tcase 'sublime':\n\t\tcase 'sublime_text':\n\t\t\treturn [`${fileName}:${lineNumber}:${colNumber}`]\n\t\tcase 'wstorm':\n\t\tcase 'charm':\n\t\t\treturn [`${fileName}:${lineNumber}`]\n\t\tcase 'notepad++':\n\t\t\treturn [`-n${lineNumber}`, `-c${colNumber}`, fileName]\n\t\tcase 'vim':\n\t\tcase 'mvim':\n\t\tcase 'joe':\n\t\tcase 'gvim':\n\t\t\treturn [`+${lineNumber}`, fileName]\n\t\tcase 'emacs':\n\t\tcase 'emacsclient':\n\t\t\treturn [`+${lineNumber}:${colNumber}`, fileName]\n\t\tcase 'rmate':\n\t\tcase 'mate':\n\t\tcase 'mine':\n\t\t\treturn ['--line', lineNumber, fileName]\n\t\tcase 'cursor':\n\t\tcase 'code':\n\t\tcase 'Code':\n\t\tcase 'code-insiders':\n\t\tcase 'Code - Insiders':\n\t\tcase 'vscodium':\n\t\tcase 'VSCodium':\n\t\t\treturn addWorkspaceToArgumentsIfExists(\n\t\t\t\t['-g', `${fileName}:${lineNumber}:${colNumber}`],\n\t\t\t\tworkspace,\n\t\t\t)\n\t\tcase 'appcode':\n\t\tcase 'clion':\n\t\tcase 'clion64':\n\t\tcase 'idea':\n\t\tcase 'idea64':\n\t\tcase 'phpstorm':\n\t\tcase 'phpstorm64':\n\t\tcase 'pycharm':\n\t\tcase 'pycharm64':\n\t\tcase 'rubymine':\n\t\tcase 'rubymine64':\n\t\tcase 'webstorm':\n\t\tcase 'webstorm64':\n\t\tcase 'goland':\n\t\tcase 'goland64':\n\t\tcase 'rider':\n\t\tcase 'rider64':\n\t\t\treturn addWorkspaceToArgumentsIfExists(\n\t\t\t\t['--line', lineNumber.toString(), fileName],\n\t\t\t\tworkspace,\n\t\t\t)\n\t}\n\n\t// For all others, drop the lineNumber until we have\n\t// a mapping above, since providing the lineNumber incorrectly\n\t// can result in errors or confusing behavior.\n\treturn [fileName]\n}\n\nfunction guessEditor(): Array<string | null> {\n\t// Explicit config always wins\n\tif (process.env.EPICSHOP_EDITOR) {\n\t\treturn shellQuote.parse(process.env.EPICSHOP_EDITOR).map((a) => String(a))\n\t}\n\n\t// We can find out which editor is currently running by:\n\t// `ps x` on macOS and Linux\n\t// `Get-Process` on Windows\n\ttry {\n\t\tif (process.platform === 'darwin') {\n\t\t\tconst output = child_process.execSync('ps x').toString()\n\t\t\tconst processNames = Object.keys(COMMON_EDITORS_OSX) as Array<\n\t\t\t\tkeyof typeof COMMON_EDITORS_OSX\n\t\t\t>\n\t\t\tfor (let i = 0; i < processNames.length; i++) {\n\t\t\t\tconst processName = processNames[i]\n\t\t\t\tif (processName && output.includes(processName)) {\n\t\t\t\t\tconst editor = COMMON_EDITORS_OSX[processName]\n\t\t\t\t\treturn [editor]\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (process.platform === 'win32') {\n\t\t\t// Some processes need elevated rights to get its executable path.\n\t\t\t// Just filter them out upfront. This also saves 10-20ms on the command.\n\t\t\tconst output = child_process\n\t\t\t\t.execSync(\n\t\t\t\t\t'wmic process where \"executablepath is not null\" get executablepath',\n\t\t\t\t)\n\t\t\t\t.toString()\n\t\t\tconst runningProcesses = output.split('\\r\\n')\n\t\t\tfor (let i = 0; i < runningProcesses.length; i++) {\n\t\t\t\tconst processPath = runningProcesses[i]?.trim()\n\t\t\t\tif (!processPath) continue\n\t\t\t\tconst processName = path.basename(processPath)\n\t\t\t\tif (COMMON_EDITORS_WIN.includes(processName)) {\n\t\t\t\t\treturn [processPath]\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (process.platform === 'linux') {\n\t\t\t// --no-heading No header line\n\t\t\t// x List all processes owned by you\n\t\t\t// -o comm Need only names column\n\t\t\tconst output = child_process\n\t\t\t\t.execSync('ps x --no-heading -o comm --sort=comm')\n\t\t\t\t.toString()\n\t\t\tconst processNames = Object.keys(COMMON_EDITORS_LINUX)\n\t\t\tfor (let i = 0; i < processNames.length; i++) {\n\t\t\t\tconst processName = processNames[i]\n\t\t\t\tif (!processName) continue\n\t\t\t\tif (output.includes(processName)) {\n\t\t\t\t\t// @ts-expect-error 🤷♂️ it's fine\n\t\t\t\t\treturn [COMMON_EDITORS_LINUX[processName]]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore...\n\t}\n\n\t// Last resort, use old skool env vars\n\tif (process.env.VISUAL) {\n\t\treturn [process.env.VISUAL]\n\t} else if (process.env.EDITOR) {\n\t\treturn [process.env.EDITOR]\n\t}\n\n\treturn [null]\n}\n\nlet _childProcess: ReturnType<typeof child_process.spawn> | null = null\nexport type Result =\n\t| { status: 'success' }\n\t| { status: 'error'; message: string }\nexport async function launchEditor(\n\tpathList: string[] | string,\n\tlineNumber: number = 1,\n\tcolNumber: number = 1,\n): Promise<Result> {\n\t// Sanitize lineNumber to prevent malicious use on win32\n\t// via: https://github.com/nodejs/node/blob/c3bb4b1aa5e907d489619fb43d233c3336bfc03d/lib/child_process.js#L333\n\t// and it should be a positive integer\n\tif (lineNumber && !(Number.isInteger(lineNumber) && lineNumber > 0)) {\n\t\treturn { status: 'error', message: 'lineNumber must be a positive integer' }\n\t}\n\n\t// colNumber is optional, but should be a positive integer too\n\t// default is 1\n\tif (colNumber && !(Number.isInteger(colNumber) && colNumber > 0)) {\n\t\tcolNumber = 1\n\t}\n\n\tconst editorInfo = guessEditor()\n\tconst editor = editorInfo[0]\n\tlet args = editorInfo.slice(1).filter(Boolean)\n\n\tif (!editor) {\n\t\treturn { status: 'error', message: 'No editor found' }\n\t}\n\n\tif (editor.toLowerCase() === 'none') {\n\t\treturn { status: 'error', message: 'Editor set to \"none\"' }\n\t}\n\n\tif (typeof pathList === 'string') {\n\t\tpathList = [pathList]\n\t}\n\n\ttype accumulator = {\n\t\tfileList: string[]\n\t\terrorsList: string[]\n\t}\n\n\tconst initArgs: accumulator = { fileList: [], errorsList: [] }\n\n\tconst { fileList, errorsList } = pathList.reduce(\n\t\t(acc: accumulator, fileName: string) => {\n\t\t\tif (\n\t\t\t\tprocess.platform === 'linux' &&\n\t\t\t\tfileName.startsWith('/mnt/') &&\n\t\t\t\t/Microsoft/i.test(os.release())\n\t\t\t) {\n\t\t\t\t// Assume WSL / \"Bash on Ubuntu on Windows\" is being used, and\n\t\t\t\t// that the file exists on the Windows file system.\n\t\t\t\t// `os.release()` is \"4.4.0-43-Microsoft\" in the current release\n\t\t\t\t// build of WSL, see: https://github.com/Microsoft/BashOnWindows/issues/423#issuecomment-221627364\n\t\t\t\t// When a Windows editor is specified, interop functionality can\n\t\t\t\t// handle the path translation, but only if a relative path is used.\n\t\t\t\tfileName = path.relative('', fileName)\n\t\t\t}\n\n\t\t\tconst fileExists = fs.existsSync(fileName)\n\t\t\t// cmd.exe on Windows is vulnerable to RCE attacks given a file name of the\n\t\t\t// form \"C:\\Users\\myusername\\Downloads\\& curl 172.21.93.52\". Use a whitelist\n\t\t\t// to validate user-provided file names. This doesn't cover the entire range\n\t\t\t// of valid file names but should cover almost all of them in practice.\n\t\t\t// if the file exists, then we're good.\n\t\t\tif (\n\t\t\t\t!fileExists &&\n\t\t\t\tprocess.platform === 'win32' &&\n\t\t\t\t!WINDOWS_FILE_NAME_WHITELIST.test(fileName)\n\t\t\t) {\n\t\t\t\tacc.errorsList.push(fileName)\n\t\t\t} else {\n\t\t\t\tif (!fileExists) {\n\t\t\t\t\tfsExtra.ensureDirSync(path.dirname(fileName))\n\t\t\t\t\tfsExtra.writeFileSync(fileName, '', 'utf8')\n\t\t\t\t}\n\n\t\t\t\tacc.fileList.push(fileName.trim())\n\t\t\t}\n\t\t\treturn acc\n\t\t},\n\t\tinitArgs,\n\t)\n\n\t// TODO: figure out how to send error messages as JSX from here...\n\tfunction getErrorMessage() {\n\t\tlet message: string\n\t\tif (errorsList.length) {\n\t\t\tconst readableName =\n\t\t\t\terrorsList.length === 1 ? readablePath(errorsList[0]) : 'some files'\n\t\t\tmessage = `Could not open ${readableName} in the editor.\\n\\nWhen running on Windows, file names are checked against a whitelist to protect against remote code execution attacks.\\nFile names may consist only of alphanumeric characters (all languages), periods, dashes, slashes, and underscores. Maybe you have your files in a folder that includes a space in the pathname? Rename the folder to remove the space and try again.`\n\t\t} else {\n\t\t\tmessage = 'pathList must contain at least one valid file path'\n\t\t}\n\t\treturn {\n\t\t\tstatus: 'error',\n\t\t\tmessage,\n\t\t} as Result\n\t}\n\n\tconst workspace = null\n\tif (lineNumber && fileList.length === 1) {\n\t\tconst fileName = fileList[0]\n\t\tif (!fileName) {\n\t\t\treturn getErrorMessage()\n\t\t}\n\t\targs = args.concat(\n\t\t\tgetArgumentsForLineNumber(\n\t\t\t\teditor,\n\t\t\t\tfileName,\n\t\t\t\tlineNumber,\n\t\t\t\tcolNumber,\n\t\t\t\tworkspace,\n\t\t\t)\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.map(String),\n\t\t)\n\t} else {\n\t\tconst argList = fileList.filter(Boolean)\n\t\tif (!argList.length) {\n\t\t\treturn getErrorMessage()\n\t\t}\n\t\targs.push(...argList)\n\t}\n\n\tif (_childProcess && isTerminalEditor(editor)) {\n\t\t// There's an existing editor process already and it's attached\n\t\t// to the terminal, so go kill it. Otherwise two separate editor\n\t\t// instances attach to the stdin/stdout which gets confusing.\n\t\t_childProcess.kill('SIGKILL')\n\t}\n\n\treturn new Promise((res) => {\n\t\tif (process.platform === 'win32') {\n\t\t\t// On Windows, launch the editor in a shell because spawn can only\n\t\t\t// launch .exe files.\n\t\t\t_childProcess = child_process.spawn(\n\t\t\t\t'cmd.exe',\n\t\t\t\t['/C', editor].concat(args).filter(Boolean),\n\t\t\t\t{ stdio: ['inherit', 'inherit', 'pipe'] },\n\t\t\t)\n\t\t} else {\n\t\t\t_childProcess = child_process.spawn(editor, args, {\n\t\t\t\tstdio: ['inherit', 'inherit', 'pipe'],\n\t\t\t})\n\t\t}\n\t\t_childProcess.stderr?.on('data', (data: string | Uint8Array) => {\n\t\t\tconst message = String(data)\n\t\t\t// Filter out the specific error message for environment variable issues\n\t\t\tif (!message.includes('Node.js environment variables are disabled')) {\n\t\t\t\tprocess.stderr.write(data) // Only write non-filtered messages to stderr\n\t\t\t}\n\t\t})\n\t\t_childProcess.on('exit', async (errorCode) => {\n\t\t\t_childProcess = null\n\n\t\t\tif (errorCode) {\n\t\t\t\tconst readableName =\n\t\t\t\t\tfileList.length === 1 ? readablePath(fileList[0]) : 'some files'\n\t\t\t\treturn res({\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tmessage: `Could not open ${readableName} in the editor.\\n\\nThe editor process exited with an error code (${errorCode}).`,\n\t\t\t\t})\n\t\t\t} else if (errorsList.length) {\n\t\t\t\t// show error message even when the editor was opened successfully,\n\t\t\t\t// if some file path was not valid in windows\n\t\t\t\treturn res(getErrorMessage())\n\t\t\t} else {\n\t\t\t\treturn res({ status: 'success' })\n\t\t\t}\n\t\t})\n\n\t\t_childProcess.on('error', async (error: Error & { code?: string }) => {\n\t\t\tif (error.code === 'EBADF') {\n\t\t\t\treturn res({\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t'Unable to launch editor. This commonly happens when running in a containerized or server environment without terminal access.',\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn res({ status: 'error', message: error.message })\n\t\t})\n\t})\n}\n","import path from 'path'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport { clsx } from 'clsx'\nimport fsExtra from 'fs-extra'\nimport { useEffect } from 'react'\nimport { Link, useFetcher, type ActionFunctionArgs } from 'react-router'\nimport { z, type ZodTypeAny } from 'zod'\nimport { useApps } from '#app/components/apps'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { launchEditor } from '#app/utils/launch-editor.server.ts'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.js'\nimport { useRequestInfo } from '#app/utils/request-info'\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(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\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\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\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 type=\"hidden\" name=\"line\" value={typeof line === 'number' ? line : undefined} />\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={clsx(\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)}\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\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=\"launch_button !no-underline\"\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}/${appFile}`.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, useRef } from 'react'\n\nexport function Mermaid({\n\tcode,\n\tonSvg,\n}: {\n\tcode: string\n\tonSvg?: (svg: string) => void\n}) {\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('mermaid-svg', 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])\n\treturn <div ref={ref} />\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/index.js'\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 right-0 top-0 z-50 m-2 flex items-baseline justify-end gap-4 opacity-0 transition duration-300 ease-in-out focus-within:opacity-100 group-hover: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 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 {\n\tdata,\n\ttype HeadersFunction,\n\tLink,\n\tisRouteErrorResponse,\n\tuseRouteError,\n} from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.js'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\nimport { getSeoMetaTags } from '#app/utils/seo.js'\nimport { type Route } from './+types/$exerciseNumber.tsx'\n\nexport const meta: Route.MetaFunction = ({ data, matches }) => {\n\tconst number = data?.exercise.exerciseNumber.toString().padStart(2, '0')\n\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\n\tif (!data || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `📝 | ${number}. ${data.exercise.title} | ${rootData?.workshopTitle}`,\n\t\tdescription: `Introduction for ${number}. ${data.exercise.title}`,\n\t\togTitle: data.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 new Response('Not found', { 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}`,\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 flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 scrollbar-thin scrollbar-thumb-scrollbar 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)] font-extrabold leading-none\">\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-b-4 border-t 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=\"flex h-full items-center justify-center bg-foreground px-7 text-background\"\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\tconst error = useRouteError()\n\n\tif (typeof document !== 'undefined') {\n\t\tconsole.error(error)\n\t}\n\n\treturn isRouteErrorResponse(error) ? (\n\t\terror.status === 404 ? (\n\t\t\t<p>Sorry, we couldn't find that step.</p>\n\t\t) : (\n\t\t\t<p>\n\t\t\t\t{error.status} {error.data}\n\t\t\t</p>\n\t\t)\n\t) : (\n\t\t<p>{getErrorMessage(error)}</p>\n\t)\n}\n","import { invariantResponse } from '@epic-web/invariant'\nimport { getExercises } 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 {\n\tdata,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tOutlet,\n\tisRouteErrorResponse,\n\tuseRouteError,\n} from 'react-router'\nimport { getErrorMessage } from '#app/utils/misc.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('stepLoader')\n\tinvariantResponse(params.exerciseNumber, 'exerciseNumber is required')\n\tconst exercises = await getExercises({ request, timings })\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst exercise = exercises.find(\n\t\t(e) => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tif (!exercise) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\n\n\tconst result = data(\n\t\t{\n\t\t\texerciseNumber: exercise.exerciseNumber,\n\t\t\texerciseTitle: exercise.title,\n\t\t\ttitle: workshopTitle,\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},\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\treturn result\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 StepRoute() {\n\treturn <Outlet />\n}\n\nexport function ErrorBoundary() {\n\tconst error = useRouteError()\n\n\tif (typeof document !== 'undefined') {\n\t\tconsole.error(error)\n\t}\n\n\treturn isRouteErrorResponse(error) ? (\n\t\terror.status === 404 ? (\n\t\t\t<p>Sorry, we couldn't find that step.</p>\n\t\t) : (\n\t\t\t<p>\n\t\t\t\t{error.status} {error.data}\n\t\t\t</p>\n\t\t)\n\t) : (\n\t\t<p>{getErrorMessage(error)}</p>\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\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\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 { data, 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.js'\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\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\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 data({ status: 'error', error: message } as const, {\n\t\t\tstatus: 500,\n\t\t\theaders: await createToastHeaders({\n\t\t\t\ttype: 'error',\n\t\t\t\ttitle: 'Error',\n\t\t\t\tdescription:\n\t\t\t\t\t'There was an error setting the playground. Check the terminal for details.',\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(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'flex h-full w-full items-center justify-between text-left radix-placeholder:text-gray-500 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=\"w-80 flex-1 overflow-hidden text-ellipsis whitespace-nowrap scrollbar-thin scrollbar-thumb-scrollbar\">\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=\"relative flex cursor-pointer select-none items-center rounded px-10 py-2 leading-none opacity-80 radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100\"\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({ appName }: { appName: string }) {\n\tif (ENV.EPICSHOP_DEPLOYED) return null\n\treturn (\n\t\t<SetPlayground\n\t\t\tappName={appName}\n\t\t\ttooltipText=\"Playground is not set to the right app. Click to set Playground.\"\n\t\t>\n\t\t\t<span className=\"flex items-center justify-center gap-1 text-foreground-destructive hover:underline\">\n\t\t\t\t<Icon name=\"Unlinked\" className=\"animate-ping\" />{' '}\n\t\t\t\t<span className=\"uppercase\">Set to Playground</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/request-info.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 StepContext.Provider')\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 (\n\t\t<StepContext.Provider value={{ inBrowserBrowserRef }}>\n\t\t\t{children}\n\t\t</StepContext.Provider>\n\t)\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// @ts-expect-error 🤷♂️\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{/* @ts-expect-error 🤷♂️ */}\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// @ts-expect-error 🤷♂️\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\t{/* @ts-expect-error 🤷♂️ */}\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 z-10 select-none rounded bg-background px-9 py-8 text-foreground\"\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=\"mb-2 border-b border-b-gray-50 border-opacity-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\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\tLink,\n\tOutlet,\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.js'\nimport { type RootLoaderData } from '#app/root.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 { getSeoMetaTags } from '#app/utils/seo.js'\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'\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 = ({ data, matches, params }) => {\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\n\tif (!data || !rootData) return [{ title: '🦉 | Error' }]\n\tconst { emoji, stepNumber, title, exerciseNumber, exerciseTitle } =\n\t\tpageTitle(data)\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 { title: workshopTitle } = getWorkshopConfig()\n\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 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 (!problemApp && !solutionApp) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\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} 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 flex-grow flex-col\">\n\t\t\t<main\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName=\"flex 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-[var(--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 pl-10 pr-5 text-sm font-medium leading-tight\">\n\t\t\t\t\t\t<div className=\"flex h-14 items-center justify-between gap-x-2 overflow-x-auto whitespace-nowrap py-2\">\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\tdata.playground?.appName !== data.problem.name ? (\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 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</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 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 scrollbar-thin scrollbar-thumb-scrollbar 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\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\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-b-4 border-t 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}\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=\"hidden w-1 cursor-col-resize bg-border hover:bg-accent 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 />\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\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t\t503: () => (\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h1>Service Unavailable</h1>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\tSorry, we're having a temporary problem. Please try again later.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<button onClick={() => window.location.reload()}>Refresh</button>\n\t\t\t\t\t</div>\n\t\t\t\t),\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.js'\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(formData, { status: 'app-started' } 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(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(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(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 uppercase leading-none\"\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 {\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n\ttype ForwardedRef,\n} from 'react'\nimport { Form, useSearchParams, type NavigateFunction } from 'react-router'\nimport { z } from 'zod'\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/request-info.ts'\nimport { LinkButton } from './button.tsx'\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from './ui/tooltip.tsx'\n\nconst historyCallDataSchema = z.intersection(\n\tz.object({\n\t\ttype: z.literal('epicshop:history-call'),\n\t}),\n\tz.union([\n\t\tz.object({\n\t\t\tmethod: z.literal('pushState'),\n\t\t\targs: z.union([\n\t\t\t\tz.tuple([z.object({}).passthrough(), z.unknown()]),\n\t\t\t\tz.tuple([z.object({}).passthrough(), z.unknown(), z.string()]),\n\t\t\t]),\n\t\t}),\n\t\tz.object({\n\t\t\tmethod: z.literal('replaceState'),\n\t\t\targs: z.union([\n\t\t\t\tz.tuple([z.object({}).passthrough(), z.unknown()]),\n\t\t\t\tz.tuple([z.object({}).passthrough(), z.unknown(), z.string()]),\n\t\t\t]),\n\t\t}),\n\t\tz.object({\n\t\t\tmethod: z.literal('go'),\n\t\t\targs: z.tuple([z.number().optional()]),\n\t\t}),\n\t\tz.object({ method: z.literal('forward'), args: z.tuple([]) }),\n\t\tz.object({ method: z.literal('back'), args: z.tuple([]) }),\n\t\tz.object({\n\t\t\tmethod: z.literal('popstate'),\n\t\t\tpathname: z.string(),\n\t\t\tdelta: z.number(),\n\t\t}),\n\t]),\n)\n\nconst loadedSchema = z.object({\n\ttype: z.literal('epicshop:loaded'),\n\turl: z.string(),\n})\n\nconst messageSchema = z.union([historyCallDataSchema, loadedSchema])\n\nfunction getNewIndex(prevIndex: number, delta: number, max: number) {\n\t// keep the index bound between 0 and the history length\n\treturn Math.min(Math.max(prevIndex + delta, 0), max)\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}\n\nexport type InBrowserBrowserRef = {\n\thandleExtrnalNavigation: (pathname?: string) => void\n}\n\nexport const InBrowserBrowser = forwardRef<InBrowserBrowserRef, Props>(\n\tInBrowserBrowserImpl,\n)\n\nfunction InBrowserBrowserImpl(\n\t{ name, port, portIsAvailable, isRunning, baseUrl, id, initialRoute }: Props,\n\tref: ForwardedRef<InBrowserBrowserRef>,\n) {\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 <AppStarter name={name} />\n\t}\n}\ntype RealBrowserProps = {\n\tbaseUrl: string\n\tid: string\n\tname: string\n\tinitialRoute: string\n}\n\nconst InBrowserBrowserForRealz = forwardRef<\n\tInBrowserBrowserRef,\n\tRealBrowserProps\n>(InBrowserBrowserForRealzImpl)\n\n// we're doing this to ensure all of this complex stuff doesn't happen unless\n// the iframe is actually rendered.\nfunction InBrowserBrowserForRealzImpl(\n\t{ baseUrl, id, name, initialRoute }: RealBrowserProps,\n\tref: ForwardedRef<InBrowserBrowserRef>,\n) {\n\tconst theme = useTheme()\n\tconst [searchParams, setSearchParams] = useSearchParams()\n\tconst searchParamsPathname = searchParams.get('pathname') ?? initialRoute\n\tconst [iframeKeyNumber, setIframeKeyNumber] = useState(0)\n\tconst iframeKey = id + iframeKeyNumber\n\tconst lastDirectionRef = useRef<'forward' | 'back' | 'new'>('new')\n\tconst lastDirectionTimeout = useRef<ReturnType<typeof setTimeout> | null>(\n\t\tnull,\n\t)\n\tconst [iframeContext, setIFrameContext] = useState({\n\t\thistory: [searchParamsPathname],\n\t\tindex: 0,\n\t})\n\tconst [pathnameInputValue, setPathnameInputValue] =\n\t\tuseState(searchParamsPathname)\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\n\tconst appUrl = new URL(searchParamsPathname, baseUrl)\n\tconst currentAppUrl = useRef(appUrl)\n\tuseEffect(() => {\n\t\tcurrentAppUrl.current = appUrl\n\t})\n\n\t/** changing the iframeSrcUrl will trigger a reload of the iframe */\n\tconst [iframeSrcUrl, setIframeSrcUrl] = useState(appUrl)\n\n\tconst currentId = useRef(id)\n\t// if the id changes, then we're going to reload the iframe, but we want to\n\t// make sure to preserve the pathname so we set the src to the current pathname\n\t// this is one of the few side-effects in render that are \"ok\"\n\tif (currentId.current !== id) {\n\t\tcurrentId.current = id\n\t\tsetIframeSrcUrl(currentAppUrl.current)\n\t}\n\tuseEffect(() => {\n\t\tcurrentId.current = id\n\t})\n\n\tuseEffect(() => {\n\t\tfunction handleMessage(messageEvent: MessageEvent) {\n\t\t\tif (messageEvent.source !== iframeRef.current?.contentWindow) return\n\n\t\t\tconst result = messageSchema.safeParse(messageEvent.data, {\n\t\t\t\tpath: ['messageEvent', 'data'],\n\t\t\t})\n\t\t\tif (!result.success) return\n\t\t\tconst { data } = result\n\n\t\t\tif (data.type === 'epicshop:loaded') {\n\t\t\t\tsetIFrameContext((prevContext) => {\n\t\t\t\t\tconst newIndex = (i: number) =>\n\t\t\t\t\t\tgetNewIndex(prevContext.index, i, prevContext.history.length - 1)\n\t\t\t\t\tif (lastDirectionRef.current === 'back') {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(-1) }\n\t\t\t\t\t} else if (lastDirectionRef.current === 'forward') {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(1) }\n\t\t\t\t\t} else if (lastDirectionRef.current === 'new') {\n\t\t\t\t\t\tconst currentFullPath = prevContext.history[prevContext.index]\n\t\t\t\t\t\tconst newUrl = new URL(data.url)\n\t\t\t\t\t\tconst newFullPath = newUrl.pathname + newUrl.search\n\n\t\t\t\t\t\tif (currentFullPath === newFullPath) return prevContext\n\n\t\t\t\t\t\tconst newHistory = [\n\t\t\t\t\t\t\t...prevContext.history.slice(0, prevContext.index + 1),\n\t\t\t\t\t\t\tnewFullPath,\n\t\t\t\t\t\t]\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\thistory: newHistory,\n\t\t\t\t\t\t\tindex: newHistory.length - 1,\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Error('Unexpected lastDirectionRef value')\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst { method } = data\n\t\t\tsetIFrameContext((prevContext) => {\n\t\t\t\tconst newIndex = (i: number) =>\n\t\t\t\t\tgetNewIndex(prevContext.index, i, prevContext.history.length - 1)\n\t\t\t\tconst currentPathname = prevContext.history[prevContext.index]\n\t\t\t\tswitch (method) {\n\t\t\t\t\tcase 'popstate': {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(data.delta) }\n\t\t\t\t\t}\n\t\t\t\t\tcase 'forward': {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(1) }\n\t\t\t\t\t}\n\t\t\t\t\tcase 'back': {\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(-1) }\n\t\t\t\t\t}\n\t\t\t\t\tcase 'pushState': {\n\t\t\t\t\t\tconst pathname = data.args[2] ?? currentPathname\n\t\t\t\t\t\tconst newHistory = [\n\t\t\t\t\t\t\t...prevContext.history.slice(0, prevContext.index + 1),\n\t\t\t\t\t\t\tpathname,\n\t\t\t\t\t\t].filter(Boolean)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...prevContext,\n\t\t\t\t\t\t\thistory: newHistory,\n\t\t\t\t\t\t\tindex: newHistory.length - 1,\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'replaceState': {\n\t\t\t\t\t\tconst pathname = data.args[2] ?? currentPathname\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...prevContext,\n\t\t\t\t\t\t\thistory: [\n\t\t\t\t\t\t\t\t...prevContext.history.slice(0, prevContext.index),\n\t\t\t\t\t\t\t\tpathname,\n\t\t\t\t\t\t\t\t...prevContext.history.slice(prevContext.index + 1),\n\t\t\t\t\t\t\t].filter(Boolean),\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'go': {\n\t\t\t\t\t\tconst [delta = 0] = data.args\n\t\t\t\t\t\treturn { ...prevContext, index: newIndex(delta) }\n\t\t\t\t\t}\n\t\t\t\t}\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\t// setSearchParams is unstable\n\t// https://github.com/remix-run/react-router/issues/9991\n\tconst setSearchParamsLatestRef = useRef(setSearchParams)\n\tuseEffect(() => {\n\t\tsetSearchParamsLatestRef.current = setSearchParams\n\t}, [setSearchParams])\n\n\tconst iframePathname = iframeContext.history[iframeContext.index]\n\tuseEffect(() => {\n\t\tif (!iframePathname) return\n\n\t\tsetPathnameInputValue(iframePathname)\n\n\t\tconst newSearchParams = new URLSearchParams(window.location.search)\n\t\tif (iframePathname === '/') {\n\t\t\tnewSearchParams.delete('pathname')\n\t\t} else {\n\t\t\tnewSearchParams.set('pathname', iframePathname)\n\t\t}\n\t\tconst newSearch = newSearchParams.toString()\n\t\tif (`?${newSearch}` !== window.location.search) {\n\t\t\tsetSearchParamsLatestRef.current(newSearchParams, { replace: true })\n\t\t}\n\t}, [iframePathname])\n\n\tconst navigateChild: NavigateFunction = (...params) => {\n\t\tconst to = params[0]\n\t\tif (typeof to === 'number') {\n\t\t\t// this part feels very brittle to me...\n\t\t\tlastDirectionRef.current = to > 0 ? 'forward' : 'back'\n\t\t} else {\n\t\t\tlastDirectionRef.current = 'new'\n\t\t}\n\t\tif (lastDirectionTimeout.current) {\n\t\t\tclearTimeout(lastDirectionTimeout.current)\n\t\t}\n\t\tlastDirectionTimeout.current = setTimeout(() => {\n\t\t\tlastDirectionRef.current = 'new'\n\t\t}, 100)\n\t\tiframeRef.current?.contentWindow?.postMessage(\n\t\t\t{ type: 'epicshop:navigate-call', params },\n\t\t\t'*',\n\t\t)\n\t}\n\n\tfunction handleExtrnalNavigation(\n\t\tnewPathnameInputValue: string = pathnameInputValue,\n\t) {\n\t\tsetPathnameInputValue(newPathnameInputValue)\n\n\t\tconst currentPathname = iframeContext.history[iframeContext.index]\n\t\tvoid navigateChild(newPathnameInputValue, {\n\t\t\treplace: currentPathname === newPathnameInputValue,\n\t\t})\n\t}\n\n\tuseImperativeHandle(ref, () => ({ handleExtrnalNavigation }))\n\n\tconst atEndOfHistory =\n\t\tiframeContext.index === iframeContext.history.length - 1\n\tconst atStartOfHistory = iframeContext.index <= 0\n\tconst existingSearchParamHiddenInputs: Array<React.ReactElement> = []\n\tfor (const [key, value] of searchParams.entries()) {\n\t\tif (key === 'pathname') continue\n\n\t\texistingSearchParamHiddenInputs.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<TooltipProvider>\n\t\t\t<div className=\"flex h-full flex-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=\"hidden aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40 sm:flex\"\n\t\t\t\t\t\t\t\t\tdisabled={atStartOfHistory}\n\t\t\t\t\t\t\t\t\tonClick={() => navigateChild(-1)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"ArrowLeft\" 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>Go back</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\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=\"hidden aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40 sm:flex\"\n\t\t\t\t\t\t\t\t\tdisabled={atEndOfHistory}\n\t\t\t\t\t\t\t\t\tonClick={() => navigateChild(1)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"ArrowRight\" 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>Go forward</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\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\tsetIframeSrcUrl(appUrl)\n\t\t\t\t\t\t\t\t\t\tsetIframeKeyNumber(iframeKeyNumber + 1)\n\t\t\t\t\t\t\t\t\t\t// TODO: figure out how we can avoid having to do this...\n\t\t\t\t\t\t\t\t\t\t// I stayed up for hours one night trying and couldn't work out\n\t\t\t\t\t\t\t\t\t\t// why react router wouldn't update the UI when using back/forward\n\t\t\t\t\t\t\t\t\t\t// after a refresh.\n\t\t\t\t\t\t\t\t\t\tsetIFrameContext({\n\t\t\t\t\t\t\t\t\t\t\thistory: [appUrl.pathname],\n\t\t\t\t\t\t\t\t\t\t\tindex: 0,\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<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<Form\n\t\t\t\t\t\tmethod=\"get\"\n\t\t\t\t\t\treplace\n\t\t\t\t\t\tclassName=\"flex flex-1 gap-2\"\n\t\t\t\t\t\tonSubmit={() => handleExtrnalNavigation()}\n\t\t\t\t\t>\n\t\t\t\t\t\t{existingSearchParamHiddenInputs}\n\t\t\t\t\t\t<div className=\"flex flex-1 items-center border-x bg-background p-3 leading-none text-foreground\">\n\t\t\t\t\t\t\t<a href={appUrl.toString()} target=\"_blank\" rel=\"noreferrer\">\n\t\t\t\t\t\t\t\t{iframeSrcUrl.host}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\taria-label=\"pathname\"\n\t\t\t\t\t\t\t\tclassName=\"w-full flex-1 bg-background focus-visible:outline-none\"\n\t\t\t\t\t\t\t\tvalue={pathnameInputValue}\n\t\t\t\t\t\t\t\tname=\"pathname\"\n\t\t\t\t\t\t\t\tonChange={(e) => setPathnameInputValue(e.currentTarget.value)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{/* TODO: Reconsider if this is needed as browsers don't usually have a submit button in address bar */}\n\t\t\t\t\t\t{/* <button type=\"submit\">Go</button> */}\n\t\t\t\t\t</Form>\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={appUrl.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 flex-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 flex-grow bg-white\"\n\t\t\t\t\t\tstyle={{ colorScheme: theme }}\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 { Icon } from '#app/components/icons'\nimport {\n\tInBrowserBrowser,\n\ttype InBrowserBrowserRef,\n} from '#app/components/in-browser-browser'\nimport { Loading } from '#app/components/loading.js'\nimport { useTheme } from '#app/routes/theme/index.js'\nimport { cn, getBaseUrl } from '#app/utils/misc'\nimport { useRequestInfo } from '#app/utils/request-info'\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 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={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=\"relative h-full flex-grow overflow-y-auto scrollbar-thin scrollbar-thumb-scrollbar\">\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 bottom-5 right-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 flex-grow bg-white\"\n\t\t\t\t\tstyle={{ colorScheme: theme }}\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 flex-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 flex-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\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\tisAppRunning,\n\tisPortAvailable,\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","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.js'\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 max-w-none whitespace-pre-wrap dark:prose-invert prose-pre:m-0 prose-pre:mb-1 prose-pre:rounded-none',\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 flex w-full items-center justify-between border-b p-4 pr-3 font-mono text-sm font-medium leading-none hover:bg-foreground/20',\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=\"font-mono text-xs font-normal uppercase text-muted-foreground\">\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=\"transition group-radix-state-open:rotate-180\"\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 {\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 './apps.tsx'\nimport { DeferredEpicVideo } from './epic-video.tsx'\nimport { Icon } from './icons.tsx'\nimport { useRevalidationWS } from './revalidation-ws.tsx'\nimport { SimpleTooltip } from './ui/tooltip.tsx'\nimport { useUserHasAccess } from './user.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 Diff({\n\tdiff,\n\tallApps,\n}: {\n\tdiff: Promise<diffProp> | diffProp\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\tconst userHasAccess = useUserHasAccess()\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\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 the diff.\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 diff tab works.\n\t\t\t\t</p>\n\t\t\t\t<DeferredEpicVideo url=\"https://www.epicweb.dev/tips/epic-workshop-diff-tab-demo\" />\n\t\t\t</div>\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=\"p-6 text-foreground-destructive\">\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=\"flex h-full flex-1 items-center overflow-x-auto scrollbar-thin scrollbar-thumb-scrollbar\"\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=\"flex-grow overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar\">\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=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">\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=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">\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'flex h-full w-full max-w-[50%] items-center justify-between px-3 text-left radix-placeholder:text-gray-500 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<SelectValue\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'relative flex cursor-pointer select-none items-center rounded px-10 py-2 leading-none opacity-80 radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100',\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\nconst SelectValue: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => {\n\treturn (\n\t\t<Select.Value {...props} ref={forwardedRef}>\n\t\t\t{props.value}\n\t\t</Select.Value>\n\t)\n}\n","import {\n\tcachified,\n\tfsCache,\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.js'\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\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: fsCache,\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=\"flex-1 overflow-y-scroll bg-accent pb-4 scrollbar-thin scrollbar-thumb-scrollbar\">\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=\"flex h-full w-full flex-col items-center justify-center text-foreground-destructive\">\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=\"rounded-xl border bg-background 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=\"flex items-center justify-center gap-1 rounded-full bg-accent 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=\"flex-1 overflow-ellipsis text-muted-foreground\">\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.js'\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=\"animate-pulse text-foreground-destructive\"\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 flex-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 h-full flex-1 flex-grow items-center justify-center\">\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 { 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>\n\t\t\t\t\t<div className=\"text-foreground-secondary flex h-full items-center justify-center 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>\n\t\t\t\t\t\t<div className=\"text-foreground-secondary flex flex-wrap gap-1 text-center\">\n\t\t\t\t\t\t\tThis exercise has no application or other UI associated with it.{' '}\n\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\tNavigate to{' '}\n\t\t\t\t\t\t\t<SimpleTooltip content={playgroundAppInfo.fullPath}>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tvoid navigator.clipboard.writeText(\n\t\t\t\t\t\t\t\t\t\t\tplaygroundAppInfo.fullPath,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\tshowToast.success('Copied playground path to clipboard')\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\tthe playground directory\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</SimpleTooltip>{' '}\n\t\t\t\t\t\t\tin your editor and follow the exercise instructions to complete it.\n\t\t\t\t\t\t</div>\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.js'\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.js'\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=\"max-h-48 overflow-y-auto p-4 scrollbar-thin scrollbar-thumb-scrollbar\">\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=\"flex items-baseline gap-2 text-foreground-destructive\">\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=\"max-h-48 overflow-y-auto p-4 scrollbar-thin scrollbar-thumb-scrollbar\"\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/>\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} 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.js'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.js'\nimport { createToastHeaders } from '#app/utils/toast.server.js'\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\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\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\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(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(formData, { success: true })\n\t\t}\n\t\tcase 'clear': {\n\t\t\tclearTestProcessEntry(app)\n\t\t\treturn dataWithPE(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 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\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-y-auto\">\n\t\t\t<div className=\"flex h-12 w-full flex-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 flex-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 h-full 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 flex-1 overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar\">\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 flex-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 flex-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 flex-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 { useState } from 'react'\nimport { DeferredEpicVideo } from '#app/components/epic-video.js'\nimport { Icon } from '#app/components/icons'\nimport { InBrowserTestRunner } from '#app/components/in-browser-test-runner'\nimport { useUserHasAccess } from '#app/components/user.js'\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}: {\n\tappInfo: Pick<PlaygroundApp, 'appName' | 'name' | 'test'> | 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<TestUI playgroundAppInfo={playgroundAppInfo} />\n\t\t</PlaygroundWindow>\n\t)\n}\n\nexport function TestUI({\n\tplaygroundAppInfo,\n}: {\n\tplaygroundAppInfo: Pick<PlaygroundApp, 'name' | 'test'> | null\n}) {\n\tconst [inBrowserTestKey, setInBrowserTestKey] = useState(0)\n\tconst userHasAccess = useUserHasAccess()\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 w-full flex-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 uppercase leading-none\"\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 { compileMarkdownString } from '@epic-web/workshop-utils/compile-mdx.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { userHasAccessToWorkshop } 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 { useRef } from 'react'\nimport {\n\tLink,\n\tuseLoaderData,\n\tuseNavigate,\n\tuseSearchParams,\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\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 { useAltDown } from '#app/utils/misc.tsx'\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 } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exerciseStepTypeIndexLoader')\n\tconst userHasAccess = await userHasAccessToWorkshop({\n\t\trequest,\n\t\ttimings,\n\t})\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\tif (!userHasAccess) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: await compileMarkdownString(\n\t\t\t\t\t`<h1>Access Denied</h1><p>You must login or register for the workshop to view the diff</p>`,\n\t\t\t\t),\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\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} 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\tconst data = useLoaderData<typeof loader>()\n\tconst [searchParams] = useSearchParams()\n\n\tconst preview = searchParams.get('preview')\n\tconst inBrowserBrowserRef = useRef<InBrowserBrowserRef>(null)\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!data.playground ||\n\t\t\t\tdata.playground.test.type === 'none'\n\t\t\t)\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution') {\n\t\t\tif (data[tab]?.dev.type === 'none') return true\n\t\t\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\t\t\treturn data[tab]?.dev.type !== 'browser' && !data[tab]?.stackBlitzUrl\n\t\t\t}\n\t\t}\n\t\tif (tab === 'playground' && ENV.EPICSHOP_DEPLOYED) return true\n\t\treturn false\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: data.problem?.name ?? '',\n\t\tapp2: data.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-w-0 flex-1 flex-col overflow-y-auto 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=\"h-14 min-h-14 overflow-x-auto whitespace-nowrap border-b scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t{tabs.map((tab) => {\n\t\t\t\t\tconst hidden = shouldHideTab(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 relative h-full px-6 py-4 font-mono text-sm uppercase outline-none 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',\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{tab}\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-96 flex-grow flex-col overflow-y-auto\">\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"playground\"\n\t\t\t\t\tclassName=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\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={data.playground}\n\t\t\t\t\t\tproblemAppName={data.problem?.name}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t\tallApps={data.allApps}\n\t\t\t\t\t\tisUpToDate={data.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=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\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={data.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=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\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={data.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=\"flex w-full flex-grow items-start justify-center self-start overflow-hidden radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Tests\n\t\t\t\t\t\tappInfo={data.playground}\n\t\t\t\t\t\tproblemAppName={data.problem?.name}\n\t\t\t\t\t\tallApps={data.allApps}\n\t\t\t\t\t\tisUpToDate={data.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=\"diff\"\n\t\t\t\t\tclassName=\"flex h-full w-full flex-grow items-start justify-center self-start radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Diff diff={data.diff} allApps={data.allApps} />\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=\"flex h-full w-full flex-grow items-start justify-center self-start radix-state-inactive:hidden\"\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 {\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},\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 } = useLoaderData<typeof loader>()\n\n\treturn <TestUI key={appInfo.name} playgroundAppInfo={appInfo} />\n}\n","import {\n\tgetExerciseApp,\n\tisProblemApp,\n\tisSolutionApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { redirect, type LoaderFunctionArgs } from 'react-router'\n\nexport async function loader({ params }: LoaderFunctionArgs) {\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 new Response('Not found', { status: 404 })\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.js'\nimport { type RootLoaderData } from '#app/root.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 { getSeoMetaTags } from '#app/utils/seo.js'\nimport { type Route } from './+types/$exerciseNumber_.finished.tsx'\n\nexport const meta: Route.MetaFunction = ({ data, matches }) => {\n\tconst number = data?.exercise.exerciseNumber.toString().padStart(2, '0')\n\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\n\tif (!data || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🦉 | ${number}. ${data.exercise.title} | ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${number}. ${data.exercise.title}`,\n\t\togTitle: `Finished: ${data.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 flex-grow flex-col\">\n\t\t\t<main className=\"flex 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 pl-10 pr-5 text-sm font-medium leading-tight\">\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 h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 scrollbar-thin scrollbar-thumb-scrollbar 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-b-4 border-t 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 flex-shrink-0\">\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center text-body-md text-foreground-destructive\">\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:flex-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.js'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.js'\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 = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\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 flex-grow flex-col\">\n\t\t\t<main className=\"grid h-full flex-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 pl-10 pr-5 text-sm font-medium uppercase leading-none\">\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 h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 scrollbar-thin scrollbar-thumb-scrollbar 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-b-4 border-t 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 flex-shrink-0\">\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center text-foreground-destructive\">\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 flex-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\texercise,\n}: {\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>\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=\"flex flex-col divide-y divide-border dark:divide-border/50\">\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) => (\n\t\t\t\t<ExerciseListItem key={exercise.exerciseNumber} exercise={exercise} />\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 flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 scrollbar-thin scrollbar-thumb-scrollbar 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)] font-extrabold leading-none\">\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=\"pb-5 pt-10\">\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 * as client from 'openid-client'\nimport { z } from 'zod'\nimport { EVENTS } from './auth-events.ts'\nimport { getErrorMessage } from './misc.tsx'\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\tconst {\n\t\tproduct: { host },\n\t} = getWorkshopConfig()\n\tconst { ISSUER = `https://${host}/oauth` } = process.env\n\ttry {\n\t\tconst config = await client.discovery(new URL(ISSUER), 'EPICSHOP_APP')\n\t\tconst deviceResponse = await client.initiateDeviceAuthorization(config, {})\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\tthrow new Error('Device authorization timed out')\n\t\t}, deviceResponse.expires_in * 1000)\n\n\t\ttry {\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\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\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\tconst userinfoResult = UserInfoSchema.safeParse(userinfoRaw)\n\t\t\tif (!userinfoResult.success) {\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\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\n\t\t\tawait getUserInfo({ forceFresh: true })\n\n\t\t\tauthEmitter.emit(EVENTS.AUTH_RESOLVED)\n\t\t} catch (error) {\n\t\t\tclearTimeout(timeout)\n\t\t\tthrow error\n\t\t}\n\t} catch (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.js'\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 flex-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, useRouteLoaderData } 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 { type RootLoaderData } from '#app/root.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\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 data = useRouteLoaderData('root') as RootLoaderData\n\tconst playerPreferences = data?.preferences?.player\n\tconst fontSizePreference = data?.preferences?.fontSize\n\tconst presencePreferences = data?.preferences?.presence\n\tconst playgroundPreferences = data?.preferences?.playground\n\tconst exerciseWarningPreferences = data?.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 flex-grow flex-col gap-4 pb-24\">\n\t\t\t\t<h1 className=\"mb-4 text-h1\">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=\"mb-2 text-body-xl\">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=\"rounded-md border border-border bg-background px-2 py-1 text-foreground\"\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=\"rounded-md border border-border bg-background px-2 py-1 text-foreground\"\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=\"rounded-md border border-border bg-background px-2 py-1 text-foreground\"\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, Link, 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 flex-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=\"rounded-lg border border-destructive bg-destructive/10 p-4\">\n\t\t\t\t\t<h2 className=\"mb-2 text-lg font-semibold text-destructive\">\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-sm text-destructive\">\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=\"mt-2 text-sm text-destructive\">\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=\"rounded bg-background 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=\"mb-3 text-h2\">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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"mb-3 text-h2\">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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"rounded-lg border border-border bg-muted 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-sm text-muted-foreground\">\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=\"mb-3 text-h2\">Exceptions to the Rule</h2>\n\t\t\t\t\t\t<div className=\"rounded-lg border border-border bg-muted p-4\">\n\t\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\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=\"rounded bg-background 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=\"mt-2 space-y-1 text-sm text-muted-foreground\">\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=\"mb-3 text-h2\">Need a Refresher?</h2>\n\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t\t\tFor a complete overview of the typical workflow, check out the{' '}\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto=\"/onboarding\"\n\t\t\t\t\t\t\t\tclassName=\"text-primary underline hover:no-underline\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tonboarding page\n\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\tto review the expected workflow.\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=\"rounded-lg border border-destructive bg-destructive/10 p-4\">\n\t\t\t\t\t\t\t<h2 className=\"mb-2 text-lg font-semibold text-destructive\">\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=\"rounded border-border\"\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 { type RootLoaderData } from '#app/root.tsx'\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 = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\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=\"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.js'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst apps = await getApps()\n\treturn Response.json({ apps })\n}\n","import { getAllFileCacheEntries } from '@epic-web/workshop-utils/cache.server'\nimport { ensureUndeployed } from '#app/utils/misc.js'\n\nexport async function loader() {\n\tensureUndeployed()\n\tconst entries = await getAllFileCacheEntries()\n\treturn Response.json({ entries })\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 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 (!global.__inspector_open__) {\n\t\tglobal.__inspector_open__ = true\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 (global.__inspector_open__) {\n\t\tglobal.__inspector_open__ = false\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 { data, Form, Link, useNavigation } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport {\n\tuseEpicProgress,\n\ttype SerializedProgress,\n} from '#app/routes/progress.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { type Route } from './+types/index.tsx'\nimport {\n\tclearCaches,\n\tclearData,\n\tstartInspector,\n\tstopInspector,\n} from './admin-utils.server.tsx'\n\ndeclare global {\n\tvar __inspector_open__: boolean | undefined\n}\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\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: global.__inspector_open__,\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-blue-500',\n\t\tincomplete: 'bg-yellow-500',\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Progress</h2>\n\t\t\t\t{epicProgress ? (\n\t\t\t\t\t<ul className=\"flex max-h-72 flex-col gap-2 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t{epicProgress.sort(sortProgress).map((progress) => {\n\t\t\t\t\t\t\tconst status = progress.epicCompletedAt\n\t\t\t\t\t\t\t\t? 'completed'\n\t\t\t\t\t\t\t\t: 'incomplete'\n\t\t\t\t\t\t\tconst label = [\n\t\t\t\t\t\t\t\tprogress.epicLessonSlug,\n\t\t\t\t\t\t\t\tprogress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t? `(${progress.epicCompletedAt})`\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\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={progress.epicLessonSlug}\n\t\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-2\"\n\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\t\tclassName={`h-3 w-3 rounded-full ${progressStatus[status]}`}\n\t\t\t\t\t\t\t\t\t\ttitle={status}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t{progress.type === 'unknown' ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-red-500\">\n\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<Icon name=\"Close\" />\n\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</span>\n\t\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\t\t<Link to={linkProgress(progress)}>{label}</Link>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t<Link to={progress.epicLessonUrl}>\n\t\t\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\"></Icon>\n\t\t\t\t\t\t\t\t\t</Link>\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})}\n\t\t\t\t\t</ul>\n\t\t\t\t) : (\n\t\t\t\t\t<p>No progress data</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Commands</h2>\n\t\t\t\t<ul className=\"max-h-48 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t<button name=\"intent\" value=\"clear-caches\">\n\t\t\t\t\t\t\t\tClear local caches\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</Form>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t<button name=\"intent\" value=\"clear-data\">\n\t\t\t\t\t\t\t\tClear all local data (including auth data)\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</Form>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t{data.inspectorRunning ? (\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"stop-inspect\">\n\t\t\t\t\t\t\t\t\t{isStartingInspector\n\t\t\t\t\t\t\t\t\t\t? 'Stopping inspector...'\n\t\t\t\t\t\t\t\t\t\t: 'Stop inspector'}\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) : (\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"inspect\">\n\t\t\t\t\t\t\t\t\t{isStoppingInspector\n\t\t\t\t\t\t\t\t\t\t? 'Starting inspector...'\n\t\t\t\t\t\t\t\t\t\t: 'Start inspector'}\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)}\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Apps</h2>\n\t\t\t\t<ul className=\"max-h-48 list-none overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t{data.apps.map((app) => (\n\t\t\t\t\t\t<li key={app.name} className=\"flex items-center gap-2 py-1\">\n\t\t\t\t\t\t\t{data.processes[app.name] ? (\n\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<Pinger status=\"stopped\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{app.name}\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Processes</h2>\n\t\t\t\t<ul className=\"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t{Object.entries(data.processes).map(([key, process]) => (\n\t\t\t\t\t\t<li key={key}>\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t{key} - Port: {process.port} - PID {process.pid} -{' '}\n\t\t\t\t\t\t\t\t{process.color}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 className=\"text-lg font-bold\">Test Processes</h2>\n\t\t\t\t<ul className=\"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t{Object.entries(data.testProcesses).map(([key, process]) => (\n\t\t\t\t\t\t<li key={key}>\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t{key} - PID {process.pid} - Exit code: {process.exitCode}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\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-gray-500',\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\">\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\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\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\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<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{ENV.EPICSHOP_APP_VERSION ? (\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={`https://github.com/epicweb-dev/epicshop/releases/tag/v${ENV.EPICSHOP_APP_VERSION}`}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{ENV.EPICSHOP_APP_VERSION}\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 { 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\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('grid h-full grid-rows-[1fr,auto]', {\n\t\t\t\t'cursor-wait opacity-30': isNavigating,\n\t\t\t})}\n\t\t>\n\t\t\t<div className=\"overflow-y-auto\">\n\t\t\t\t<Diff diff={data.diff} allApps={data.allApps} />\n\t\t\t</div>\n\t\t\t<div className=\"flex h-16 items-center justify-end border-t\">\n\t\t\t\t<NavChevrons prev={data.prevLink} next={data.nextLink} />\n\t\t\t</div>\n\t\t</div>\n\t)\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 { 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.js'\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\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 { invariantResponse } from '@epic-web/invariant'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetAuthInfo,\n\tmarkOnboardingVideoWatched,\n} from '@epic-web/workshop-utils/db.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport {\n\tdata,\n\tredirect,\n\ttype ActionFunctionArgs,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tForm,\n\tuseLoaderData,\n} from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport {\n\tDeferredEpicVideo,\n\tEpicVideoInfoProvider,\n} from '#app/components/epic-video.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('onboarding')\n\n\tconst { onboardingVideo } = getWorkshopConfig()\n\tconst videoInfos = getEpicVideoInfos([onboardingVideo], { request, timings })\n\treturn data(\n\t\t{ onboardingVideo, videoInfos },\n\t\t{ headers: { 'Server-Timing': timings.toString() } },\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': loaderHeaders.get('Server-Timing') ?? '',\n\t}\n\treturn headers\n}\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tconst data = await request.formData()\n\tconst authInfo = await getAuthInfo()\n\tconst intent = data.get('intent')\n\tinvariantResponse(intent === 'complete', 'Invalid intent')\n\tconst { onboardingVideo } = getWorkshopConfig()\n\tawait markOnboardingVideoWatched(onboardingVideo)\n\n\tif (authInfo) throw redirect('/')\n\telse throw redirect('/login')\n}\n\nexport default function Onboarding() {\n\tconst data = useLoaderData<typeof loader>()\n\treturn (\n\t\t<main className=\"flex h-full w-full flex-col items-center justify-between gap-4\">\n\t\t\t<div className=\"container flex h-full w-full max-w-5xl flex-1 flex-col items-center gap-4 overflow-y-scroll py-12 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t<h1 className=\"text-5xl\">Onboarding</h1>\n\t\t\t\t<p className=\"text-xl\">Welcome to EpicWeb.dev!</p>\n\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\tBefore you get started, <strong>you must watch the tour video</strong>\n\t\t\t\t\t! You're going to be spending a lot of time in here, so it's important\n\t\t\t\t\tyou understand how to work effectively in this workshop\n\t\t\t\t</p>\n\t\t\t\t<div className=\"w-[780px] max-w-full\">\n\t\t\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={data.videoInfos}>\n\t\t\t\t\t\t<DeferredEpicVideo url={data.onboardingVideo} />\n\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<Form method=\"post\" className=\"pb-4\">\n\t\t\t\t<Button name=\"intent\" value=\"complete\" varient=\"primary\">\n\t\t\t\t\tI've watched it. Let's go!\n\t\t\t\t</Button>\n\t\t\t</Form>\n\t\t</main>\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","ConfettiShower","sizeClassName","childrenSizeClassName","AnchorOrLink","Heading","headers","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","href","target","className","duration","Infinity","label","onClick","submit","method","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","user","cuid","cookie","links","rel","tailwindStylesheetUrl","appStylesheetUrl","sizes","meta","getSeoMetaTags","instructor","workshopTitle","workshopSubtitle","timings","makeTimings","workshopConfig","getWorkshopConfig","subtitle","onboardingVideo","onboarding","readOnboardingData","ENV","EPICSHOP_DEPLOYED","tourVideosWatched","includes","URL","url","pathname","getTheme","confettiId","confettiHeaders","getConfetti","toastHeaders","getToast","isOnlinePromise","checkConnectionCached","asyncStuff","promiseHash","userId","getUserId","getPreferences","progress","getProgress","catch","e","console","emptyProgress","getUserInfo","userHasAccess","userHasAccessToWorkshop","apps","getApps","repoUpdates","checkForUpdatesCached","getUnmutedNotifications","exerciseChanges","checkForExerciseChanges","presentUsers","getPresentUsers","mutedNotifications","getMutedNotifications","remoteCommit","updatesAvailable","map","fullPath","relativePath","getEnv","protocol","hostname","port","origin","domain","getDomainUrl","getHints","path","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","fontSize","cn","exerciseWarning","dismissed","ExerciseWarningBanner","Outlet","Confetti","EpicToaster","UpdateToast","EpicProgress","_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","useRouteLoaderData","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","React","buttonRef","Boolean","startAnimation","setStartAnimation","useState","navigationLocationStateFrom","from","navigationLocationPathname","locationPathname","focus","key","latest","Promise","resolve","setTimeout","then","animationPromises","getAnimations","allSettled","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","locationLabel","getLocationLabel","imageUrl","imageUrlSmall","avatarUrl","hasAccess","local","doingLabel","Tooltip","TooltipTrigger","asChild","tabIndex","TooltipContent","line1","line2","useIsWide","makeMediaQueryStore","isWide","isHydrated","useHydrated","setMenuOpenedState","useRevalidationWS","watchPaths","setMenuOpened","document","NoUserBanner","MobileNavigation","onMenuOpenChange","Navigation","exercise","exercisePortion","s","join","host","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","open","initialOpenRef","menuButtonRef","path01Variants","d","closed","path02Variants","moving","path01Controls","path02Controls","toggleMenu","start","handleKeyUp","event","click","addEventListener","removeEventListener","height","viewBox","stroke","strokeWidth","y","handle","getSitemapEntries","logout","deleteCache","redirectWithToast","optOut","setPreferences","useConnectDiscordURL","Account","useUser","config","discordMember","useOptionalDiscordMember","connectDiscordURL","imageUrlLarge","Button","varient","index","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","Array","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","player","ignoredInputs","ignoredRoles","shouldIgnoreHotkey","el","HTMLElement","isIgnored","tagName","getAttribute","isContentEditable","parentElement","PlayerPreferencesSchema","json","flatten","useLatest","MuxPlayer","muxPlayerRef","props","playerPreferences","playerPreferencesFetcher","metadataLoaded","setMetadataLoaded","currentTimeSessionKey","playbackId","currentTime","setCurrentTime","playerPreferencesRef","stored","sessionStorage","getItem","parse","getTime","removeItem","handleUserKeyPress","activeElement","preventDefault","paused","play","pause","forwardSeekOffset","metaKey","ctrlKey","fullscreenElement","exitFullscreen","requestFullscreen","window","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","onLoadedMetadata","minResolution","getMinResolutionValue","maxResolution","getMaxResolutionValue","obj1","obj2","isArray","i","keys1","Object","keys","keys2","resolution","MinResolution","noLessThan480p","noLessThan540p","noLessThan720p","noLessThan1080p","noLessThan1440p","noLessThan2160p","MaxResolution","upTo720p","upTo1080p","upTo1440p","upTo2160p","getRelativePath","getErrorMessage","getFileDescriptorSchema","appFile","union","literal","LaunchSchema","intersection","line","coerce","column","syncTo","array","workshopFile","getAll","syncToIsProvided","values","some","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","FormData","githubPath","LaunchEditor","mdxComponents","matches","rootData","m","ogTitle","ogDescription","desc","readmeFilepath","getWorkshopRoot","dirName","firstStep","articleId","slugify","exerciseReadme","exerciseTitle","firstType","epicVideoInfosPromise","getEpicVideoInfos","instructionsEpicVideoEmbeds","h1","ExerciseNumberRoute","loaderData","firstStepNumber","String","instructionsCode","EpicVideoInfoProvider","Mdx","code","components","ElementScrollRestoration","elementQuery","useRouteError","isRouteErrorResponse","StepRoute","SetPlaygroundSchema","reset","nullable","redirectTo","converseApp","solutionName","problemName","setPlayground","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","withParam","splitCookieName","computeSplitPercent","input","defaultValue","isFinite","min","max","pageTitle","exerciseStepApp","emoji","cacheOptions","allAppsFull","problemApp","solutionApp","requireExerciseApp","getExerciseApp","reqUrl","pathnameParam","searchParams","delete","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","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","pointerEvents","forEach","handleMove","clientX","cleanup","relativeX","onMouseMove","buttons","onTouchMove","firstTouch","touches","body","cursor","userSelect","titleBits","StepMdx","TouchedFiles","diffFilesPromise","NavChevrons","prev","next","role","onMouseDown","onDoubleClick","onTouchStart","reload","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","ansi","useAnsiToHtml","lastMessage","useEventSource","parsed","TestRunner","onRun","AnimatedBars","StopTest","ClearTest","onClear","toHtml","stripCursorMovements","latestOnRun","latestOnClear","onStop","latestOnStop","app1Name","app2Name","app1","app2","getDiffProp","diffCode","compileMarkdownString","discordPostsPromise","fetchDiscordPosts","isUpToDate","tabs","isValidPreview","newSearchParams","set","useSearchParams","preview","navigate","useNavigate","shouldHideTab","tab","activeTab","altDiffUrl","handleDiffTabClick","shiftKey","Tabs","List","preventScrollReset","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","revalidator","useRevalidator","revalidate","ButtonLink","optOutPresence","persistPlayground","dismissExerciseWarning","persist","AccountSettings","fontSizePreference","presencePreferences","playgroundPreferences","exerciseWarningPreferences","isSubmitting","htmlFor","defaultChecked","disabled","Support","repoGroups","match","groups","repoUrl","repoIssuesUrl","org","repo","WorkspaceStructure","AdminLayout","getAllFileCacheEntries","processes","testProcesses","color","getProcesses","devProcesses","pid","inspectorRunning","global","__inspector_open__","clearData","clearCaches","startInspector","stopInspector","sortProgress","linkProgress","epicProgress","isStartingInspector","isStoppingInspector","progressStatus","completed","incomplete","epicLessonUrl","Pinger","colors","pinger","circle","starting","stopped","taken","commitInfo","latestVersion","getCommitInfo","getLatestWorkshopAppVersion","uptime","startDate","workshopCommit","dateFormatted","dayjs","date","format","dateFromNow","fromNow","latestWorkshopAppVersion","startTime","startTimeFormatted","startTimeFromNow","Version","githubRepo","hash","EPICSHOP_APP_VERSION","usingDefaultApp1","at","app1Index","prevApp1Index","prevApp2Index","nextApp1Index","nextApp2Index","prevApp1","prevApp2","nextApp1","nextApp2","prevSearchParams","nextSearchParams","prevLink","nextLink","DiffViewer","paramsWithForcedRefresh","isNavigating","WIDTH","HEIGHT","urlPathname","logo","element","OgLayout","productLogo","productDisplayName","display","flexDirection","justifyContent","alignItems","padding","textWrap","textAlign","renderHtml","renderToStaticMarkup","debug","ogImg","cachified","timingKey","cache","ogCache","ttl","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","backgroundColor","objectFit","gap","avatar","borderRadius","margin","fontWeight","videoInfos","authInfo","markOnboardingVideoWatched","Onboarding","DeferredEpicVideo","SENTRY_HOST","SENTRY_DSN","SENTRY_PROJECT_IDS","SENTRY_PROJECT_ID","envelope","piece","header","dsn","projectId","upstreamSentryURL","generateRobotsTxt","context","serverBuild","generateSitemap","routes","siteUrl"],"mappings":"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"}
|