From f4a063febd1c5bcd875e60ffce08ff36554ec602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 26 Jun 2026 00:13:41 +0200 Subject: [PATCH 01/13] Add ChatRoom-React experimental workload Exercises chat-room switching in a two-pane chat UI, so timeline teardown/rebuild cost can be profiled. Original React + Vite code with deterministic, server-free fixtures and no third-party assets. Experimental, so it is off by default and does not affect the official score. SwitchRooms uses flushSync so each programmatic click commits one room switch. --- suites-experimental/chat-room/.gitignore | 19 + suites-experimental/chat-room/README.md | 38 + suites-experimental/chat-room/index.html | 21 + .../chat-room/package-lock.json | 1255 +++++++++++++++++ suites-experimental/chat-room/package.json | 19 + suites-experimental/chat-room/src/App.jsx | 33 + .../chat-room/src/components/message.jsx | 18 + .../src/components/room-list-item.jsx | 16 + .../chat-room/src/components/room-list.jsx | 11 + .../chat-room/src/components/timeline.jsx | 11 + .../chat-room/src/data/rooms.js | 147 ++ suites-experimental/chat-room/src/main.jsx | 5 + suites-experimental/chat-room/src/styles.css | 158 +++ suites-experimental/chat-room/vite.config.js | 36 + suites-experimental/suites.mjs | 20 + 15 files changed, 1807 insertions(+) create mode 100644 suites-experimental/chat-room/.gitignore create mode 100644 suites-experimental/chat-room/README.md create mode 100644 suites-experimental/chat-room/index.html create mode 100644 suites-experimental/chat-room/package-lock.json create mode 100644 suites-experimental/chat-room/package.json create mode 100644 suites-experimental/chat-room/src/App.jsx create mode 100644 suites-experimental/chat-room/src/components/message.jsx create mode 100644 suites-experimental/chat-room/src/components/room-list-item.jsx create mode 100644 suites-experimental/chat-room/src/components/room-list.jsx create mode 100644 suites-experimental/chat-room/src/components/timeline.jsx create mode 100644 suites-experimental/chat-room/src/data/rooms.js create mode 100644 suites-experimental/chat-room/src/main.jsx create mode 100644 suites-experimental/chat-room/src/styles.css create mode 100644 suites-experimental/chat-room/vite.config.js diff --git a/suites-experimental/chat-room/.gitignore b/suites-experimental/chat-room/.gitignore new file mode 100644 index 000000000..994970872 --- /dev/null +++ b/suites-experimental/chat-room/.gitignore @@ -0,0 +1,19 @@ +node_modules + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +pnpm-debug.log* + +# dist-ssr / local +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.sw? diff --git a/suites-experimental/chat-room/README.md b/suites-experimental/chat-room/README.md new file mode 100644 index 000000000..a40e29cba --- /dev/null +++ b/suites-experimental/chat-room/README.md @@ -0,0 +1,38 @@ +## Description + +Chat applications are an extremely common class of web app, and switching +between rooms/channels is one of their most frequent and performance-sensitive +interactions: the previous conversation's timeline is torn down and a new, +often long, timeline of rich messages is rendered in its place. + +This workload is an original, self-contained React app that reproduces that +interaction. It is **not** derived from any existing chat product's source code +and ships no third-party assets, so it is free of licensing and trademark +concerns. + +## What are we testing + +- React reconciliation cost of repeatedly mounting/unmounting a large timeline +- DOM churn and layout when switching between rooms +- Flex/grid layout of a typical two-pane chat UI with many small components + (avatars, sender names, timestamps, message bodies) + +## How are we testing + +The app renders a sidebar of rooms and, for the selected room, a timeline of +messages. All content is generated deterministically at load time (no network, +no backend, no `Math.random`/`Date.now`), so every run renders identical data. + +The timed step (`SwitchRooms`) clicks through the rooms in the sidebar in turn. +Each room's timeline is keyed by room id, so a switch fully unmounts the old +timeline and mounts the new one. + +## Developer Documentation + +The app was created with Vite + React. It can be previewed during development +with `npm run dev`. To update the files run in the harness you have to run +`npm run build`, which regenerates the committed `dist/` directory. + +The built workload can be loaded within the harness at e.g. +`http://localhost:8080/?developerMode&suites=ChatRoom-React`, or directly at +`http://localhost:8080/experimental/chat-room/dist/index.html`. diff --git a/suites-experimental/chat-room/index.html b/suites-experimental/chat-room/index.html new file mode 100644 index 000000000..42ac7d1cd --- /dev/null +++ b/suites-experimental/chat-room/index.html @@ -0,0 +1,21 @@ + + + + + + ChatRoom + + + +
+ + + diff --git a/suites-experimental/chat-room/package-lock.json b/suites-experimental/chat-room/package-lock.json new file mode 100644 index 000000000..a8cfa5ec5 --- /dev/null +++ b/suites-experimental/chat-room/package-lock.json @@ -0,0 +1,1255 @@ +{ + "name": "chat-room", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "chat-room", + "version": "0.0.0", + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.0.0", + "vite": "^4.1.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.40", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz", + "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.378", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.378.tgz", + "integrity": "sha512-VinvOAuuPmdD1guEgGv5f2Qp7/vlfqOrUOMYNnOD4wj3pit8kRsQHzfIf6teyUGWo15Tg5+bOJaRunvyltpVWQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "4.5.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", + "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/suites-experimental/chat-room/package.json b/suites-experimental/chat-room/package.json new file mode 100644 index 000000000..406a041b5 --- /dev/null +++ b/suites-experimental/chat-room/package.json @@ -0,0 +1,19 @@ +{ + "name": "chat-room", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.0.0", + "vite": "^4.1.0" + } +} diff --git a/suites-experimental/chat-room/src/App.jsx b/suites-experimental/chat-room/src/App.jsx new file mode 100644 index 000000000..c35ad6422 --- /dev/null +++ b/suites-experimental/chat-room/src/App.jsx @@ -0,0 +1,33 @@ +import { useState } from "react"; +import { flushSync } from "react-dom"; +import { rooms } from "./data/rooms.js"; +import RoomList from "./components/room-list.jsx"; +import Timeline from "./components/timeline.jsx"; + +export default function App() { + const [selectedRoomId, setSelectedRoomId] = useState(rooms[0].id); + const selectedRoom = rooms.find((room) => room.id === selectedRoomId); + + // Commit each room switch synchronously. Without this, React 18 batches a + // burst of programmatic clicks into a single deferred render, so only the + // last switch would render. flushSync makes each click render one switch, + // matching how a real discrete user click behaves. + const handleSelect = (roomId) => flushSync(() => setSelectedRoomId(roomId)); + + return ( +
+ +
+
+

+ {selectedRoom.name} +

+

{selectedRoom.topic}

+
+ {/* Keyed by room id so switching rooms fully tears down the old + timeline and mounts the new one, which is the work we profile. */} + +
+
+ ); +} diff --git a/suites-experimental/chat-room/src/components/message.jsx b/suites-experimental/chat-room/src/components/message.jsx new file mode 100644 index 000000000..072788d34 --- /dev/null +++ b/suites-experimental/chat-room/src/components/message.jsx @@ -0,0 +1,18 @@ +import { AVATAR_COLORS } from "../data/rooms.js"; + +export default function Message({ message }) { + return ( +
  • + + {message.senderInitials} + +
    +
    + {message.sender} + {message.time} +
    +
    {message.body}
    +
    +
  • + ); +} diff --git a/suites-experimental/chat-room/src/components/room-list-item.jsx b/suites-experimental/chat-room/src/components/room-list-item.jsx new file mode 100644 index 000000000..81f8f149f --- /dev/null +++ b/suites-experimental/chat-room/src/components/room-list-item.jsx @@ -0,0 +1,16 @@ +import { AVATAR_COLORS } from "../data/rooms.js"; + +export default function RoomListItem({ index, room, selected, onSelect }) { + const className = selected ? "room-list-item room-list-item-selected" : "room-list-item"; + return ( + + ); +} diff --git a/suites-experimental/chat-room/src/components/room-list.jsx b/suites-experimental/chat-room/src/components/room-list.jsx new file mode 100644 index 000000000..733730808 --- /dev/null +++ b/suites-experimental/chat-room/src/components/room-list.jsx @@ -0,0 +1,11 @@ +import RoomListItem from "./room-list-item.jsx"; + +export default function RoomList({ rooms, selectedRoomId, onSelect }) { + return ( + + ); +} diff --git a/suites-experimental/chat-room/src/components/timeline.jsx b/suites-experimental/chat-room/src/components/timeline.jsx new file mode 100644 index 000000000..405c77e40 --- /dev/null +++ b/suites-experimental/chat-room/src/components/timeline.jsx @@ -0,0 +1,11 @@ +import Message from "./message.jsx"; + +export default function Timeline({ room }) { + return ( +
      + {room.messages.map((message) => + + )} +
    + ); +} diff --git a/suites-experimental/chat-room/src/data/rooms.js b/suites-experimental/chat-room/src/data/rooms.js new file mode 100644 index 000000000..84867c4e5 --- /dev/null +++ b/suites-experimental/chat-room/src/data/rooms.js @@ -0,0 +1,147 @@ +// Deterministic, server-free chat fixtures. +// +// Everything here is generated once at module load using a plain counter, with +// no Math.random() or Date.now(), so the workload renders identical content on +// every run. The data shape is the one a chat client works with -- rooms in a +// sidebar, a timeline of messages per room -- but the content is entirely +// original, with no third-party assets. + +const ROOM_COUNT = 40; +const MESSAGES_PER_ROOM = 150; + +const ROOM_NAMES = [ + "General", + "Random", + "Announcements", + "Engineering", + "Design", + "Product", + "Support", + "Off Topic", + "Releases", + "Incidents", + "Frontend", + "Backend", + "Infra", + "Mobile", + "Performance", + "Security", + "Docs", + "Hiring", + "Watercooler", + "Standup", +]; + +const SENDERS = ["Ada Lovelace", "Alan Turing", "Grace Hopper", "Linus Pauling", "Marie Curie", "Nikola Tesla", "Rosalind Franklin", "Carl Sagan", "Katherine Johnson", "Tim Berners-Lee"]; + +export const AVATAR_COLORS = ["#368bd6", "#ac3ba8", "#03b381", "#e64f7a", "#ff812d", "#2dc2c5", "#5c56f5", "#74d12c"]; + +const AVATAR_COLOR_COUNT = AVATAR_COLORS.length; + +const WORDS = [ + "the", + "benchmark", + "switching", + "between", + "rooms", + "should", + "feel", + "instant", + "even", + "when", + "the", + "timeline", + "is", + "long", + "and", + "full", + "of", + "rich", + "messages", + "with", + "avatars", + "and", + "timestamps", + "rendering", + "performance", + "matters", + "a", + "lot", + "here", + "lets", + "measure", + "it", + "carefully", + "and", + "compare", + "across", + "browsers", + "over", + "time", +]; + +function initials(name) { + return name + .split(" ") + .map((part) => part[0]) + .join("") + .slice(0, 2) + .toUpperCase(); +} + +// Build a message body of a deterministic, varied length from the word pool. +function buildBody(seed) { + const wordCount = 6 + (seed % 22); + const words = []; + for (let i = 0; i < wordCount; i++) + words.push(WORDS[(seed + i) % WORDS.length]); + const sentence = words.join(" "); + return `${sentence.charAt(0).toUpperCase() + sentence.slice(1)}.`; +} + +// Format a deterministic HH:MM timestamp without touching the real clock. +function buildTime(seed) { + const minutesInDay = seed % (24 * 60); + const hours = Math.floor(minutesInDay / 60); + const minutes = minutesInDay % 60; + const pad = (value) => String(value).padStart(2, "0"); + return `${pad(hours)}:${pad(minutes)}`; +} + +function buildMessages(roomIndex) { + const messages = []; + for (let i = 0; i < MESSAGES_PER_ROOM; i++) { + const seed = roomIndex * MESSAGES_PER_ROOM + i; + const sender = SENDERS[seed % SENDERS.length]; + messages.push({ + id: `room-${roomIndex}-msg-${i}`, + sender, + senderInitials: initials(sender), + colorIndex: seed % AVATAR_COLOR_COUNT, + time: buildTime(seed), + body: buildBody(seed), + }); + } + return messages; +} + +function buildRooms() { + const rooms = []; + for (let i = 0; i < ROOM_COUNT; i++) { + const baseName = ROOM_NAMES[i % ROOM_NAMES.length]; + const name = i < ROOM_NAMES.length ? baseName : `${baseName} ${Math.floor(i / ROOM_NAMES.length) + 1}`; + const messages = buildMessages(i); + rooms.push({ + id: `room-${i}`, + name, + colorIndex: i % AVATAR_COLOR_COUNT, + initials: initials(name), + topic: `Discussion about ${name.toLowerCase()}`, + lastMessage: messages[messages.length - 1].body, + messages, + }); + } + return rooms; +} + +export const rooms = buildRooms(); diff --git a/suites-experimental/chat-room/src/main.jsx b/suites-experimental/chat-room/src/main.jsx new file mode 100644 index 000000000..ac94db0e7 --- /dev/null +++ b/suites-experimental/chat-room/src/main.jsx @@ -0,0 +1,5 @@ +import { createRoot } from "react-dom/client"; +import App from "./App.jsx"; +import "./styles.css"; + +createRoot(document.getElementById("root")).render(); diff --git a/suites-experimental/chat-room/src/styles.css b/suites-experimental/chat-room/src/styles.css new file mode 100644 index 000000000..d8a1a07f6 --- /dev/null +++ b/suites-experimental/chat-room/src/styles.css @@ -0,0 +1,158 @@ +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + height: 100%; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + color: #17191c; + background-color: #f4f6fa; +} + +#root { + height: 100vh; +} + +.app { + display: grid; + grid-template-columns: 300px 1fr; + height: 100vh; + overflow: hidden; +} + +/* Avatars are CSS-drawn circles, so the workload ships no image assets. */ +.avatar { + display: inline-flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + width: 36px; + height: 36px; + border-radius: 50%; + color: #fff; + font-size: 13px; + font-weight: 600; + text-transform: uppercase; +} + +/* Room list (sidebar) */ +.room-list { + display: flex; + flex-direction: column; + overflow-y: auto; + border-right: 1px solid #e3e8ef; + background-color: #fff; +} + +.room-list-item { + display: flex; + align-items: center; + gap: 12px; + padding: 10px 14px; + border: 0; + border-bottom: 1px solid #f0f2f5; + background: transparent; + text-align: left; + cursor: pointer; + font: inherit; + color: inherit; +} + +.room-list-item:hover { + background-color: #f4f6fa; +} + +.room-list-item-selected { + background-color: #e8f0fe; +} + +.room-list-item-text { + display: flex; + flex-direction: column; + min-width: 0; +} + +.room-list-item-name { + font-weight: 600; + font-size: 15px; +} + +.room-list-item-preview { + font-size: 13px; + color: #737d8c; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Room (main panel) */ +.room { + display: flex; + flex-direction: column; + min-width: 0; + height: 100vh; +} + +.room-header { + padding: 14px 20px; + border-bottom: 1px solid #e3e8ef; + background-color: #fff; +} + +.room-header-name { + margin: 0; + font-size: 18px; +} + +.room-header-topic { + margin: 4px 0 0; + font-size: 13px; + color: #737d8c; +} + +/* Timeline */ +.timeline { + flex: 1 1 auto; + margin: 0; + padding: 16px 20px; + list-style: none; + overflow-y: auto; +} + +.timeline-message { + display: flex; + gap: 12px; + padding: 6px 0; +} + +.timeline-message-body { + min-width: 0; +} + +.timeline-message-meta { + display: flex; + align-items: baseline; + gap: 8px; +} + +.timeline-message-sender { + font-weight: 600; + font-size: 14px; +} + +.timeline-message-time { + font-size: 12px; + color: #939aa5; +} + +.timeline-message-text { + margin-top: 2px; + font-size: 14px; + line-height: 1.4; + color: #2c3038; +} diff --git a/suites-experimental/chat-room/vite.config.js b/suites-experimental/chat-room/vite.config.js new file mode 100644 index 000000000..8ed5b0ff2 --- /dev/null +++ b/suites-experimental/chat-room/vite.config.js @@ -0,0 +1,36 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import { generateResourcesFile } from "../../resources/shared/generate-resources.mjs"; + +// The suite entry declares a resources.txt, which tests/unittests/suites.mjs +// validates, so emit it once the bundle is on disk. +function resourcesManifest() { + return { + name: "chat-room-resources-manifest", + closeBundle() { + generateResourcesFile(resolve(__dirname, "dist")); + }, + }; +} + +export default defineConfig({ + // Since this will be loaded from the project root. + base: "./", + plugins: [react(), resourcesManifest()], + build: { + modulePreload: { polyfill: false }, + // React 19 ships its production build unminified and leaves minification + // to the bundler, so the workload has to minify to keep a payload size + // that matches what a real React app deploys, like the other suites do. + // The source map still points back at the unminified React sources, so + // the bundle stays readable while profiling. + minify: "esbuild", + sourcemap: true, + rollupOptions: { + input: { + index: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/suites-experimental/suites.mjs b/suites-experimental/suites.mjs index 2f740e4bd..1cf53d23b 100644 --- a/suites-experimental/suites.mjs +++ b/suites-experimental/suites.mjs @@ -292,4 +292,24 @@ export const ExperimentalSuites = freezeSuites([ }), ], }, + { + name: "ChatRoom-React", + url: "suites-experimental/chat-room/dist/index.html", + resources: "suites-experimental/chat-room/dist/resources.txt", + tags: ["chat-room", "experimental"], + async prepare(page) { + await page.waitForElement(".room-list-item"); + }, + tests: [ + new BenchmarkTestStep("SwitchRooms", (page) => { + const rooms = page.querySelectorAll(".room-list-item"); + const iterations = 20; + // Starts past room 0, which is already open: clicking it commits nothing. + for (let i = 1; i <= iterations; i++) { + rooms[i % rooms.length].click(); + page.layout(); + } + }), + ], + }, ]); From ce20ac1d34c8a417ed1b1c96a88304021206a176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 26 Jun 2026 01:04:20 +0200 Subject: [PATCH 02/13] Commit room switches through React's normal scheduler flushSync stopped React 18 batching a burst of programmatic clicks into one deferred render, but it is not what a real app does and it bypasses the concurrent scheduler this workload exists to exercise. The switch is a plain state update now, with the step yielding a task between clicks, which makes the suite async. The yield is a MessageChannel round-trip: an async step is awaited inside the measured window, so setTimeout(0)'s clamp would be reported as workload time, and a microtask would keep all 30 switches in one task. Driving 30 switches: microtask 329ms, flushSync 348ms, MessageChannel 397ms, setTimeout(0) 427ms. --- suites-experimental/chat-room/src/App.jsx | 10 ++++------ suites-experimental/suites.mjs | 23 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/suites-experimental/chat-room/src/App.jsx b/suites-experimental/chat-room/src/App.jsx index c35ad6422..e6c60efea 100644 --- a/suites-experimental/chat-room/src/App.jsx +++ b/suites-experimental/chat-room/src/App.jsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import { flushSync } from "react-dom"; import { rooms } from "./data/rooms.js"; import RoomList from "./components/room-list.jsx"; import Timeline from "./components/timeline.jsx"; @@ -8,11 +7,10 @@ export default function App() { const [selectedRoomId, setSelectedRoomId] = useState(rooms[0].id); const selectedRoom = rooms.find((room) => room.id === selectedRoomId); - // Commit each room switch synchronously. Without this, React 18 batches a - // burst of programmatic clicks into a single deferred render, so only the - // last switch would render. flushSync makes each click render one switch, - // matching how a real discrete user click behaves. - const handleSelect = (roomId) => flushSync(() => setSelectedRoomId(roomId)); + // A plain state update, so the switch commits through React's normal + // concurrent scheduler, the way a real discrete click does. The suite yields + // a task between clicks so each switch commits before the next. + const handleSelect = (roomId) => setSelectedRoomId(roomId); return (
    diff --git a/suites-experimental/suites.mjs b/suites-experimental/suites.mjs index 1cf53d23b..8371fc25c 100644 --- a/suites-experimental/suites.mjs +++ b/suites-experimental/suites.mjs @@ -3,6 +3,25 @@ import { getTodoText } from "../resources/shared/translations.mjs"; import { getNumberOfItemsToAdd } from "../resources/shared/todomvc-utils.mjs"; import { freezeSuites } from "../resources/suites-helper.mjs"; +// Yield a task so React's concurrent scheduler lands the pending update before +// the next interaction. A MessageChannel round-trip rather than setTimeout(0): +// an async step is awaited inside the measured window (see +// resources/shared/step-runner.mjs), so the timer clamp would be reported as +// workload time. +// +// Closed at both ends because an entangled port is a cycle collector root. +function yieldTask() { + return new Promise((resolve) => { + const channel = new MessageChannel(); + channel.port1.onmessage = () => { + channel.port1.close(); + channel.port2.close(); + resolve(); + }; + channel.port2.postMessage(0); + }); +} + export const ExperimentalSuites = freezeSuites([ { name: "TodoMVC-LocalStorage", @@ -297,16 +316,18 @@ export const ExperimentalSuites = freezeSuites([ url: "suites-experimental/chat-room/dist/index.html", resources: "suites-experimental/chat-room/dist/resources.txt", tags: ["chat-room", "experimental"], + type: "async", async prepare(page) { await page.waitForElement(".room-list-item"); }, tests: [ - new BenchmarkTestStep("SwitchRooms", (page) => { + new BenchmarkTestStep("SwitchRooms", async (page) => { const rooms = page.querySelectorAll(".room-list-item"); const iterations = 20; // Starts past room 0, which is already open: clicking it commits nothing. for (let i = 1; i <= iterations; i++) { rooms[i % rooms.length].click(); + await yieldTask(); page.layout(); } }), From 979c3857ed8810d3f573381574a65d784320dba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 26 Jun 2026 15:55:36 +0200 Subject: [PATCH 03/13] Include some emojis --- .../chat-room/src/components/message.jsx | 10 ++++ .../chat-room/src/data/rooms.js | 53 ++++++++++++++++++- suites-experimental/chat-room/src/styles.css | 22 ++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/suites-experimental/chat-room/src/components/message.jsx b/suites-experimental/chat-room/src/components/message.jsx index 072788d34..28a65409c 100644 --- a/suites-experimental/chat-room/src/components/message.jsx +++ b/suites-experimental/chat-room/src/components/message.jsx @@ -12,6 +12,16 @@ export default function Message({ message }) { {message.time}
    {message.body}
    + {message.reactions.length > 0 + &&
    + {message.reactions.map((reaction) => + + {reaction.emoji} + {reaction.count} + + )} +
    + } ); diff --git a/suites-experimental/chat-room/src/data/rooms.js b/suites-experimental/chat-room/src/data/rooms.js index 84867c4e5..ad9f1a5a5 100644 --- a/suites-experimental/chat-room/src/data/rooms.js +++ b/suites-experimental/chat-room/src/data/rooms.js @@ -80,6 +80,13 @@ const WORDS = [ "time", ]; +// Emoji are everywhere in a real chat. The pool mixes plain codepoints with +// variation selectors, skin tone modifiers and ZWJ sequences, so the workload +// exercises grapheme clustering as well as color-font rendering. +const INLINE_EMOJIS = ["😀", "😂", "🎉", "🔥", "❤️", "🙏", "👀", "🚀", "😅", "🤔", "💯", "✨", "🙌🏽", "👍🏻", "😍", "🥳", "😭", "🤯", "👏", "💪🏾", "🧠", "☕", "🐛", "📈", "👩‍💻", "🧑‍🚀", "👨‍👩‍👧‍👦", "🏳️‍🌈", "🤷‍♀️", "🙋‍♂️", "🫠", "🫶"]; + +const REACTION_EMOJIS = ["👍", "❤️", "😂", "🎉", "🔥", "✅", "👀", "🙏", "💯", "🚀", "😅", "🤯"]; + function initials(name) { return name .split(" ") @@ -89,14 +96,55 @@ function initials(name) { .toUpperCase(); } +// Pick a run of distinct-looking emoji, strided by the seed so neighbouring +// messages don't end up with the same run. +function pickEmojis(seed, count) { + const picked = []; + for (let i = 0; i < count; i++) + picked.push(INLINE_EMOJIS[(seed * 7 + i * 13) % INLINE_EMOJIS.length]); + return picked; +} + // Build a message body of a deterministic, varied length from the word pool. +// Most messages carry emoji: roughly one in eleven is emoji-only, and many of +// the rest get some sprinkled between the words and/or a run appended at the +// end. A decent share stays plain text so that path is still exercised too. function buildBody(seed) { + if (seed % 11 === 0) + return pickEmojis(seed, 2 + (seed % 4)).join(" "); + const wordCount = 6 + (seed % 22); + const sprinkle = seed % 5 < 2; const words = []; - for (let i = 0; i < wordCount; i++) + for (let i = 0; i < wordCount; i++) { words.push(WORDS[(seed + i) % WORDS.length]); + if (sprinkle && i > 0 && i < wordCount - 1 && (seed + i) % 7 === 0) + words.push(INLINE_EMOJIS[(seed + i) % INLINE_EMOJIS.length]); + } const sentence = words.join(" "); - return `${sentence.charAt(0).toUpperCase() + sentence.slice(1)}.`; + const text = `${sentence.charAt(0).toUpperCase() + sentence.slice(1)}.`; + if (seed % 4 === 0) + return `${text} ${pickEmojis(seed, 1 + (seed % 3)).join("")}`; + if (seed % 3 === 0) + return `${text} ${INLINE_EMOJIS[seed % INLINE_EMOJIS.length]}`; + return text; +} + +// Build a deterministic reactions row. Reaction pills are all over a busy chat, +// so roughly two messages in three have at least one and popular ones collect a +// whole row of them. +function buildReactions(seed) { + if (seed % 3 === 2) + return []; + const count = 1 + (seed % 4); + const reactions = []; + for (let i = 0; i < count; i++) { + reactions.push({ + emoji: REACTION_EMOJIS[(seed + i * 5) % REACTION_EMOJIS.length], + count: 1 + ((seed + i) % 12), + }); + } + return reactions; } // Format a deterministic HH:MM timestamp without touching the real clock. @@ -120,6 +168,7 @@ function buildMessages(roomIndex) { colorIndex: seed % AVATAR_COLOR_COUNT, time: buildTime(seed), body: buildBody(seed), + reactions: buildReactions(seed), }); } return messages; diff --git a/suites-experimental/chat-room/src/styles.css b/suites-experimental/chat-room/src/styles.css index d8a1a07f6..455c710e7 100644 --- a/suites-experimental/chat-room/src/styles.css +++ b/suites-experimental/chat-room/src/styles.css @@ -156,3 +156,25 @@ body { line-height: 1.4; color: #2c3038; } + +.timeline-message-reactions { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-top: 4px; +} + +.reaction { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 1px 8px; + border: 1px solid #e3e8ef; + border-radius: 12px; + background-color: #f4f6fa; + font-size: 12px; +} + +.reaction-count { + color: #737d8c; +} From 9dc97c96e0eb730d4e607879d8b7162a7b87eb60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 28 Jul 2026 14:12:07 +0200 Subject: [PATCH 04/13] Anchor the ChatRoom timeline to the newest message Chat clients open a room at its most recent message; the timeline mounted at offset 0. A layout effect now assigns scrollTop = scrollHeight after commit, so SwitchRooms measures mount plus the scroll to bottom. Not flex-direction: column-reverse, which inverts scrollTop semantics in ways browsers have disagreed on, and later steps drive scrollTop explicitly. --- .../chat-room/src/components/timeline.jsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/suites-experimental/chat-room/src/components/timeline.jsx b/suites-experimental/chat-room/src/components/timeline.jsx index 405c77e40..ecd194c42 100644 --- a/suites-experimental/chat-room/src/components/timeline.jsx +++ b/suites-experimental/chat-room/src/components/timeline.jsx @@ -1,8 +1,23 @@ +import { useLayoutEffect, useRef } from "react"; import Message from "./message.jsx"; export default function Timeline({ room }) { + const scrollerRef = useRef(null); + + // Chat clients open a room at its newest message. Reading scrollHeight + // forces layout and the assignment jumps without animation, which is the + // work a real client does on every room switch. + // + // Done by hand rather than with flex-direction: column-reverse, because + // column-reverse inverts scrollTop and later steps drive scrollTop + // explicitly. + useLayoutEffect(() => { + const scroller = scrollerRef.current; + scroller.scrollTop = scroller.scrollHeight; + }, [room.id]); + return ( -
      +
        {room.messages.map((message) => )} From 81ee62f403f255c5d0cd6606e042add0b69c13c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 28 Jul 2026 14:30:50 +0200 Subject: [PATCH 05/13] Give ChatRoom messages realistic content and make the timeline interactive Bodies were a single plain sentence, so rows were near-uniform in height and a windowing timeline built on that would inherit an unrealistically easy height model. They are now structured blocks -- paragraphs, code, blockquotes, lists, with inline code, links and @mention/#room pills -- giving 48 distinct row heights over 150 rows. Generation moves to a Math.imul integer hash so fields derive independently from the seed. Reaction pills, room pills and reply quotes become real controls, with state in components so the fixtures stay immutable across iterations. The reply jump assigns scrollTop from measured rects rather than scrollIntoView, keeping smooth scrolling out of a timed step. Also fixes senders never repeating, so grouping never triggered, and room pills slugifying 20 names against 40 rooms. SwitchRooms grows from ~245ms to ~450ms, the cost of mounting 150 rich rows. --- suites-experimental/chat-room/src/App.jsx | 2 +- suites-experimental/chat-room/src/actions.js | 12 + .../chat-room/src/components/message.jsx | 49 ++- .../chat-room/src/components/reaction.jsx | 15 + .../chat-room/src/components/rich-text.jsx | 74 +++++ .../chat-room/src/components/timeline.jsx | 39 ++- .../chat-room/src/data/rooms.js | 314 ++++++++++++++++-- suites-experimental/chat-room/src/styles.css | 155 +++++++++ 8 files changed, 605 insertions(+), 55 deletions(-) create mode 100644 suites-experimental/chat-room/src/actions.js create mode 100644 suites-experimental/chat-room/src/components/reaction.jsx create mode 100644 suites-experimental/chat-room/src/components/rich-text.jsx diff --git a/suites-experimental/chat-room/src/App.jsx b/suites-experimental/chat-room/src/App.jsx index e6c60efea..c804a7f50 100644 --- a/suites-experimental/chat-room/src/App.jsx +++ b/suites-experimental/chat-room/src/App.jsx @@ -24,7 +24,7 @@ export default function App() { {/* Keyed by room id so switching rooms fully tears down the old timeline and mounts the new one, which is the work we profile. */} - + ); diff --git a/suites-experimental/chat-room/src/actions.js b/suites-experimental/chat-room/src/actions.js new file mode 100644 index 000000000..28e6e24d6 --- /dev/null +++ b/suites-experimental/chat-room/src/actions.js @@ -0,0 +1,12 @@ +import { createContext, useContext } from "react"; + +// Timeline content is nested deep (Message -> RichText -> Span) and the +// innermost pills act on the app, so keep that out of the intermediate props. +export const ActionsContext = createContext({ + selectRoom: () => {}, + jumpToMessage: () => {}, +}); + +export function useActions() { + return useContext(ActionsContext); +} diff --git a/suites-experimental/chat-room/src/components/message.jsx b/suites-experimental/chat-room/src/components/message.jsx index 28a65409c..5f2d1885c 100644 --- a/suites-experimental/chat-room/src/components/message.jsx +++ b/suites-experimental/chat-room/src/components/message.jsx @@ -1,24 +1,47 @@ +import { useActions } from "../actions.js"; import { AVATAR_COLORS } from "../data/rooms.js"; +import Reaction from "./reaction.jsx"; +import RichText from "./rich-text.jsx"; + +// Consecutive messages from the same sender collapse into the previous one, the +// way a chat client renders a burst of them: no repeated avatar or name, just +// the body under a gutter that holds the timestamp on hover. +export default function Message({ message, highlighted }) { + const { jumpToMessage } = useActions(); + const classNames = ["timeline-message"]; + if (message.grouped) + classNames.push("timeline-message-grouped"); + if (highlighted) + classNames.push("timeline-message-highlighted"); -export default function Message({ message }) { return ( -
      1. - - {message.senderInitials} - +
      2. + {message.grouped + ? {message.time} + : + {message.senderInitials} + + }
        -
        - {message.sender} - {message.time} + {message.replyTo + && + } + {!message.grouped + &&
        + {message.sender} + {message.time} +
        + } +
        +
        -
        {message.body}
        {message.reactions.length > 0 &&
        {message.reactions.map((reaction) => - - {reaction.emoji} - {reaction.count} - + )}
        } diff --git a/suites-experimental/chat-room/src/components/reaction.jsx b/suites-experimental/chat-room/src/components/reaction.jsx new file mode 100644 index 000000000..6a54b7818 --- /dev/null +++ b/suites-experimental/chat-room/src/components/reaction.jsx @@ -0,0 +1,15 @@ +import { useState } from "react"; + +// The "mine" flag is local state, so the generated fixtures stay immutable and a +// room switch remounts back to the same counts instead of letting them drift +// upward across benchmark iterations. +export default function Reaction({ reaction }) { + const [mine, setMine] = useState(false); + const className = mine ? "reaction reaction-mine" : "reaction"; + return ( + + ); +} diff --git a/suites-experimental/chat-room/src/components/rich-text.jsx b/suites-experimental/chat-room/src/components/rich-text.jsx new file mode 100644 index 000000000..b6ae92efd --- /dev/null +++ b/suites-experimental/chat-room/src/components/rich-text.jsx @@ -0,0 +1,74 @@ +import { useActions } from "../actions.js"; + +// Renders the structured bodies from data/rooms.js the way a real client walks a +// parsed representation: a block switch outside, an inline span switch inside. + +function RoomPill({ span }) { + const { selectRoom } = useActions(); + return ( + + ); +} + +function Span({ span }) { + switch (span.type) { + case "code": + return {span.text}; + case "link": + // No navigation in a timed step, so the href is data only. + return ( + event.preventDefault()}> + {span.text} + + ); + case "mention": + return @{span.name}; + case "room": + return ; + default: + return span.text; + } +} + +function Spans({ spans }) { + return spans.map((span, index) => ); +} + +function Block({ block }) { + switch (block.type) { + case "code": + return ( +
        +                    {block.lines.join("\n")}
        +                
        + ); + case "quote": + return ( +
        + +
        + ); + case "list": + return ( +
          + {block.items.map((item, index) => +
        • + +
        • + )} +
        + ); + default: + return ( +

        + +

        + ); + } +} + +export default function RichText({ blocks }) { + return blocks.map((block, index) => ); +} diff --git a/suites-experimental/chat-room/src/components/timeline.jsx b/suites-experimental/chat-room/src/components/timeline.jsx index ecd194c42..438259431 100644 --- a/suites-experimental/chat-room/src/components/timeline.jsx +++ b/suites-experimental/chat-room/src/components/timeline.jsx @@ -1,8 +1,10 @@ -import { useLayoutEffect, useRef } from "react"; +import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; +import { ActionsContext } from "../actions.js"; import Message from "./message.jsx"; -export default function Timeline({ room }) { +export default function Timeline({ room, onSelectRoom }) { const scrollerRef = useRef(null); + const [highlightedId, setHighlightedId] = useState(null); // Chat clients open a room at its newest message. Reading scrollHeight // forces layout and the assignment jumps without animation, which is the @@ -16,11 +18,34 @@ export default function Timeline({ room }) { scroller.scrollTop = scroller.scrollHeight; }, [room.id]); + // Clicking a reply quote jumps to the message it quotes and leaves it + // highlighted. The offset is computed from rects and assigned to scrollTop + // directly: no smooth behavior and no scrollIntoView, so a timed step stays + // deterministic. The highlight holds until the next jump rather than + // clearing on a timer, for the same reason, and only changes background + // colour, so committing it asynchronously cannot move the offset computed + // here. + const jumpToMessage = useCallback((messageId) => { + const scroller = scrollerRef.current; + const row = scroller.querySelector(`[data-message-id="${messageId}"]`); + if (!row) + return; + setHighlightedId(messageId); + const rowRect = row.getBoundingClientRect(); + const scrollerRect = scroller.getBoundingClientRect(); + const centeringOffset = (scroller.clientHeight - rowRect.height) / 2; + scroller.scrollTop += rowRect.top - scrollerRect.top - centeringOffset; + }, []); + + const actions = useMemo(() => ({ selectRoom: onSelectRoom, jumpToMessage }), [onSelectRoom, jumpToMessage]); + return ( -
          - {room.messages.map((message) => - - )} -
        + +
          + {room.messages.map((message) => + + )} +
        +
        ); } diff --git a/suites-experimental/chat-room/src/data/rooms.js b/suites-experimental/chat-room/src/data/rooms.js index ad9f1a5a5..247da0acc 100644 --- a/suites-experimental/chat-room/src/data/rooms.js +++ b/suites-experimental/chat-room/src/data/rooms.js @@ -1,10 +1,12 @@ -// Deterministic, server-free chat fixtures. +// Deterministic, server-free chat fixtures. Generated once at module load from an +// integer hash, with no Math.random() or Date.now(), so every run renders identical +// content -- entirely original, with no third-party assets. // -// Everything here is generated once at module load using a plain counter, with -// no Math.random() or Date.now(), so the workload renders identical content on -// every run. The data shape is the one a chat client works with -- rooms in a -// sidebar, a timeline of messages per room -- but the content is entirely -// original, with no third-party assets. +// Message bodies are structured blocks rather than plain strings, the way a real +// client keeps them once markdown has been parsed: paragraphs, fenced code, +// blockquotes and bullet lists, with inline runs for code, links, @mentions and +// #room pills. The point is non-uniform row heights, which is what a windowing +// timeline has to cope with. const ROOM_COUNT = 40; const MESSAGES_PER_ROOM = 150; @@ -87,6 +89,79 @@ const INLINE_EMOJIS = ["😀", "😂", "🎉", "🔥", "❤️", "🙏", "👀", const REACTION_EMOJIS = ["👍", "❤️", "😂", "🎉", "🔥", "✅", "👀", "🙏", "💯", "🚀", "😅", "🤯"]; +// One handle per sender, so a mention always points at somebody in the room. +const MENTION_HANDLES = SENDERS.map((name) => name.split(" ")[0].toLowerCase()); + +const CODE_TOKENS = [ + "scrollTop", + "scrollHeight", + "flushSync", + "requestAnimationFrame", + "IntersectionObserver", + "overflow-anchor", + "content-visibility", + "useLayoutEffect", + "getBoundingClientRect", + "will-change", + "ResizeObserver", + "queueMicrotask", + "clientHeight", + "offsetHeight", +]; + +const LINK_LABELS = ["the trace", "last night's run", "this regression", "the profile", "the spec text", "my notes", "the dashboard", "that comparison"]; + +const LINK_PATHS = ["traces/2f9c", "runs/nightly", "profiles/hot-path", "spec/scroll-anchoring", "notes/timeline", "dashboards/perf", "reports/42", "compare/main"]; + +const QUOTE_LINES = [ + "can we get a number on how bad the jank is before we start moving code around", + "the window only recycles about twenty rows, so the mount cost should be flat", + "every row height changes when the panel opens, which invalidates the cache", + "please do not use smooth scrolling anywhere inside a timed step", + "prepending history without pinning the anchor makes the viewport jump", +]; + +const LIST_ITEMS = [ + "estimate the row height first, then correct after measuring", + "cache measured heights per message id", + "keep the mounted window small and bounded", + "assign scroll offsets explicitly instead of animating", + "recycle rows rather than remounting them", + "break the group when a reply quote is present", + "re-measure only the rows the resize actually touched", +]; + +const CODE_SNIPPETS = [ + { lang: "js", lines: ["const scroller = scrollerRef.current;", "scroller.scrollTop = scroller.scrollHeight;"] }, + { + lang: "js", + lines: ["requestAnimationFrame(() => {", " for (const row of mounted)", " heights.set(row.id, row.offsetHeight);", "});"], + }, + { lang: "css", lines: [".timeline {", " overflow-anchor: none;", " content-visibility: auto;", "}"] }, + { lang: "sh", lines: ["npm run build", "node debugging/e2e-chatroom.mjs --browser chrome"] }, + { lang: "json", lines: ["{", ' "iterationCount": 10,', ' "suites": ["ChatRoom-React"]', "}"] }, + { lang: "js", lines: ["for (const row of rows) {", " if (!heights.has(row.id))", " heights.set(row.id, estimate);", "}"] }, + { lang: "diff", lines: ['- scroller.scrollTo({ top, behavior: "smooth" });', "+ scroller.scrollTop = top;"] }, + { lang: "js", lines: ["export function anchorToBottom(node) {", " node.scrollTop = node.scrollHeight;", "}"] }, +]; + +// An integer hash rather than a PRNG, so every field can be derived independently +// from a message seed and still be stable across runs and across engines. +// Math.imul keeps the multiplies exactly 32-bit. +function hash(seed, salt) { + let h = Math.imul(seed + 1, 2654435761) ^ Math.imul(salt + 1, 40503); + h ^= h >>> 15; + h = Math.imul(h, 2246822519); + h ^= h >>> 13; + h = Math.imul(h, 3266489917); + h ^= h >>> 16; + return h >>> 0; +} + +function pick(list, seed, salt) { + return list[hash(seed, salt) % list.length]; +} + function initials(name) { return name .split(" ") @@ -96,8 +171,20 @@ function initials(name) { .toUpperCase(); } -// Pick a run of distinct-looking emoji, strided by the seed so neighbouring -// messages don't end up with the same run. +// Derived from the index alone, so a #room pill can be pointed at a real room +// while messages are still being generated. +function roomNameFor(index) { + const baseName = ROOM_NAMES[index % ROOM_NAMES.length]; + if (index < ROOM_NAMES.length) + return baseName; + return `${baseName} ${Math.floor(index / ROOM_NAMES.length) + 1}`; +} + +function roomSlugFor(index) { + return roomNameFor(index).toLowerCase().replace(/ /g, "-"); +} + +// Strided by the seed, so neighbouring messages don't get the same run. function pickEmojis(seed, count) { const picked = []; for (let i = 0; i < count; i++) @@ -105,29 +192,127 @@ function pickEmojis(seed, count) { return picked; } -// Build a message body of a deterministic, varied length from the word pool. -// Most messages carry emoji: roughly one in eleven is emoji-only, and many of -// the rest get some sprinkled between the words and/or a run appended at the -// end. A decent share stays plain text so that path is still exercised too. -function buildBody(seed) { - if (seed % 11 === 0) - return pickEmojis(seed, 2 + (seed % 4)).join(" "); +// Turn a token list into inline spans. Words get coalesced into text spans +// carrying the whitespace around their neighbours, which is what a markdown +// renderer ends up emitting. +function tokensToSpans(tokens) { + const spans = []; + let words = []; + let afterInline = false; + const flush = (trailingSpace) => { + if (!words.length) + return; + const leading = afterInline ? " " : ""; + const trailing = trailingSpace ? " " : ""; + spans.push({ type: "text", text: `${leading}${words.join(" ")}${trailing}` }); + words = []; + afterInline = false; + }; + for (const token of tokens) { + if (typeof token === "string") { + words.push(token); + continue; + } + flush(true); + spans.push(token); + afterInline = true; + } + flush(false); + return spans; +} - const wordCount = 6 + (seed % 22); - const sprinkle = seed % 5 < 2; - const words = []; +function buildInlineSpan(seed, index, roll) { + if (roll === 0) + return { type: "code", text: pick(CODE_TOKENS, seed, index + 11) }; + if (roll === 1) + return { type: "link", text: pick(LINK_LABELS, seed, index + 12), href: `https://example.com/${pick(LINK_PATHS, seed, index + 13)}` }; + if (roll === 2) + return { type: "mention", name: pick(MENTION_HANDLES, seed, index + 14) }; + const roomIndex = hash(seed, index + 15) % ROOM_COUNT; + return { type: "room", name: roomSlugFor(roomIndex), roomId: `room-${roomIndex}` }; +} + +// A sentence from the word pool, with inline code, links, mention and room pills +// spliced between words, plus the occasional emoji. +function buildParagraph(seed, salt) { + const wordCount = 6 + (hash(seed, salt) % 22); + const start = hash(seed, salt + 1) % WORDS.length; + const tokens = []; + let lastWasInline = false; for (let i = 0; i < wordCount; i++) { - words.push(WORDS[(seed + i) % WORDS.length]); - if (sprinkle && i > 0 && i < wordCount - 1 && (seed + i) % 7 === 0) - words.push(INLINE_EMOJIS[(seed + i) % INLINE_EMOJIS.length]); + tokens.push(WORDS[(start + i) % WORDS.length]); + const interior = i > 0 && i < wordCount - 1; + if (!interior || lastWasInline) { + lastWasInline = false; + continue; + } + const roll = hash(seed, salt * 31 + i) % 22; + if (roll < 4) { + tokens.push(buildInlineSpan(seed, i, roll)); + lastWasInline = true; + continue; + } + lastWasInline = false; + if (roll === 4) + tokens.push(INLINE_EMOJIS[hash(seed, salt + i) % INLINE_EMOJIS.length]); } - const sentence = words.join(" "); - const text = `${sentence.charAt(0).toUpperCase() + sentence.slice(1)}.`; - if (seed % 4 === 0) - return `${text} ${pickEmojis(seed, 1 + (seed % 3)).join("")}`; - if (seed % 3 === 0) - return `${text} ${INLINE_EMOJIS[seed % INLINE_EMOJIS.length]}`; - return text; + + const spans = tokensToSpans(tokens); + const first = spans[0]; + if (first.type === "text") + first.text = first.text.charAt(0).toUpperCase() + first.text.slice(1); + + // Terminal punctuation, and a trailing emoji run on some messages. + const tail = hash(seed, salt + 7) % 4 === 0 ? `. ${pickEmojis(seed, 1 + (hash(seed, salt + 8) % 3)).join("")}` : "."; + const last = spans[spans.length - 1]; + if (last.type === "text") + last.text += tail; + else + spans.push({ type: "text", text: tail }); + return spans; +} + +function buildCodeBlock(seed) { + const snippet = pick(CODE_SNIPPETS, seed, 401); + return { type: "code", lang: snippet.lang, lines: snippet.lines }; +} + +function buildList(seed) { + const count = 2 + (hash(seed, 402) % 3); + const items = []; + for (let i = 0; i < count; i++) { + const tokens = [pick(LIST_ITEMS, seed, 403 + i)]; + if (hash(seed, 413 + i) % 3 === 0) + tokens.push({ type: "code", text: pick(CODE_TOKENS, seed, 423 + i) }); + items.push(tokensToSpans(tokens)); + } + return { type: "list", items }; +} + +// Compose a message body out of blocks. The shape distribution is what drives +// the row height spread: emoji-only one-liners at one end, a paragraph plus a +// fenced code block at the other. +function buildBlocks(seed) { + const shape = hash(seed, 101) % 100; + + if (shape < 8) + return [{ type: "p", spans: [{ type: "text", text: pickEmojis(seed, 2 + (hash(seed, 102) % 4)).join(" ") }] }]; + + const blocks = [{ type: "p", spans: buildParagraph(seed, 1) }]; + + if (shape < 20) { + blocks.push(buildCodeBlock(seed)); + if (shape < 13) + blocks.push({ type: "p", spans: buildParagraph(seed, 2) }); + } else if (shape < 30) { + blocks.push(buildList(seed)); + } else if (shape < 38) { + blocks.push({ type: "quote", spans: [{ type: "text", text: pick(QUOTE_LINES, seed, 103) }] }); + blocks.push({ type: "p", spans: buildParagraph(seed, 3) }); + } else if (shape < 48) { + blocks.push({ type: "p", spans: buildParagraph(seed, 4) }); + } + return blocks; } // Build a deterministic reactions row. Reaction pills are all over a busy chat, @@ -156,18 +341,80 @@ function buildTime(seed) { return `${pad(hours)}:${pad(minutes)}`; } +function spansToText(spans) { + let text = ""; + for (const span of spans) { + if (span.type === "mention") + text += `@${span.name}`; + else if (span.type === "room") + text += `#${span.name}`; + else + text += span.text; + } + return text; +} + +// Flatten a body to plain text for the sidebar preview and reply excerpts. +function blocksToText(blocks) { + const parts = []; + for (const block of blocks) { + if (block.type === "code") + parts.push(block.lines.join(" ")); + else if (block.type === "list") + parts.push(block.items.map(spansToText).join(" ")); + else + parts.push(spansToText(block.spans)); + } + return parts.join(" ").replace(/\s+/g, " ").trim(); +} + +function excerpt(text, limit) { + return text.length <= limit ? text : `${text.slice(0, limit).trimEnd()}…`; +} + +// Real conversations arrive in bursts from the same person, which is what makes +// message grouping worth rendering. Emit runs of one to three messages per +// sender, always advancing to a different sender between runs. +function buildSenderSequence(roomIndex, count) { + const senders = []; + let index = hash(roomIndex, 301) % SENDERS.length; + while (senders.length < count) { + const runLength = 1 + (hash(roomIndex * 1000 + senders.length, 302) % 3); + for (let i = 0; i < runLength && senders.length < count; i++) + senders.push(SENDERS[index]); + index = (index + 1 + (hash(roomIndex * 1000 + senders.length, 303) % (SENDERS.length - 1))) % SENDERS.length; + } + return senders; +} + +const SENDER_COLOR_INDEX = new Map(SENDERS.map((name, index) => [name, index % AVATAR_COLOR_COUNT])); + function buildMessages(roomIndex) { + const senders = buildSenderSequence(roomIndex, MESSAGES_PER_ROOM); const messages = []; for (let i = 0; i < MESSAGES_PER_ROOM; i++) { const seed = roomIndex * MESSAGES_PER_ROOM + i; - const sender = SENDERS[seed % SENDERS.length]; + const sender = senders[i]; + const blocks = buildBlocks(seed); + + // Inline reply quotes embed a parent message in the child, and always + // break the sender group above them. + let replyTo = null; + if (i > 0 && hash(seed, 201) % 100 < 18) { + const parent = messages[Math.max(0, i - 1 - (hash(seed, 202) % 6))]; + replyTo = { id: parent.id, sender: parent.sender, excerpt: excerpt(parent.preview, 80) }; + } + messages.push({ id: `room-${roomIndex}-msg-${i}`, sender, senderInitials: initials(sender), - colorIndex: seed % AVATAR_COLOR_COUNT, + colorIndex: SENDER_COLOR_INDEX.get(sender), time: buildTime(seed), - body: buildBody(seed), + blocks, + preview: blocksToText(blocks), + replyTo, + grouped: i > 0 && senders[i - 1] === sender && !replyTo, reactions: buildReactions(seed), }); } @@ -177,8 +424,7 @@ function buildMessages(roomIndex) { function buildRooms() { const rooms = []; for (let i = 0; i < ROOM_COUNT; i++) { - const baseName = ROOM_NAMES[i % ROOM_NAMES.length]; - const name = i < ROOM_NAMES.length ? baseName : `${baseName} ${Math.floor(i / ROOM_NAMES.length) + 1}`; + const name = roomNameFor(i); const messages = buildMessages(i); rooms.push({ id: `room-${i}`, @@ -186,7 +432,7 @@ function buildRooms() { colorIndex: i % AVATAR_COLOR_COUNT, initials: initials(name), topic: `Discussion about ${name.toLowerCase()}`, - lastMessage: messages[messages.length - 1].body, + lastMessage: messages[messages.length - 1].preview, messages, }); } diff --git a/suites-experimental/chat-room/src/styles.css b/suites-experimental/chat-room/src/styles.css index 455c710e7..4a042ef92 100644 --- a/suites-experimental/chat-room/src/styles.css +++ b/suites-experimental/chat-room/src/styles.css @@ -130,8 +130,69 @@ body { padding: 6px 0; } +/* Grouped messages drop the avatar and name; the gutter keeps the body aligned + and carries the timestamp, revealed on hover the way real clients do. */ +.timeline-message-grouped { + padding: 1px 0; +} + +.timeline-message-gutter { + flex: 0 0 auto; + width: 36px; + font-size: 11px; + color: #939aa5; + text-align: right; + opacity: 0; +} + +.timeline-message-grouped:hover .timeline-message-gutter { + opacity: 1; +} + .timeline-message-body { min-width: 0; + flex: 1 1 auto; +} + +/* The jump target of a reply click. Background only: changing the box would + invalidate measured row heights. */ +.timeline-message-highlighted { + background-color: #fff6d8; +} + +/* Inline reply quote: a button, because clicking it jumps to the parent. */ +.timeline-message-reply { + display: flex; + gap: 6px; + align-items: baseline; + width: 100%; + margin-bottom: 2px; + padding: 0 0 0 8px; + border: 0; + border-left: 2px solid #d5dbe5; + background: transparent; + font: inherit; + font-size: 12px; + color: #737d8c; + text-align: left; + cursor: pointer; +} + +.timeline-message-reply:hover { + border-left-color: #9dc0f5; + color: #5a6472; +} + +.timeline-message-reply-sender { + flex: 0 0 auto; + font-weight: 600; + color: #5a6472; +} + +.timeline-message-reply-excerpt { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } .timeline-message-meta { @@ -157,6 +218,81 @@ body { color: #2c3038; } +/* Rich message content */ +.rich-paragraph { + margin: 0 0 4px; +} + +.rich-paragraph:last-child { + margin-bottom: 0; +} + +.rich-code { + padding: 1px 4px; + border: 1px solid #e3e8ef; + border-radius: 4px; + background-color: #f4f6fa; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: 0.9em; + color: #b4295c; +} + +.rich-code-block { + margin: 4px 0; + padding: 8px 10px; + overflow-x: auto; + border: 1px solid #e3e8ef; + border-radius: 6px; + background-color: #f8fafc; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: 12px; + line-height: 1.45; + white-space: pre; +} + +.rich-quote { + margin: 4px 0; + padding: 2px 0 2px 10px; + border-left: 3px solid #c8d1de; + color: #5a6472; +} + +.rich-list { + margin: 4px 0; + padding-left: 20px; +} + +.rich-link { + color: #2a6fd6; + text-decoration: underline; +} + +.rich-pill { + padding: 0 5px; + border: 0; + border-radius: 10px; + font: inherit; + font-weight: 500; + white-space: nowrap; +} + +.rich-pill-mention { + background-color: #e2ecfd; + color: #24509b; +} + +/* A #room pill is a button: clicking it switches to that room. */ +.rich-pill-room { + background-color: #e6f6ee; + color: #1c6e4c; + cursor: pointer; +} + +.rich-pill-room:hover { + background-color: #d3efe1; +} + +/* Reactions */ .timeline-message-reactions { display: flex; flex-wrap: wrap; @@ -164,6 +300,7 @@ body { margin-top: 4px; } +/* Reaction pills are real toggle buttons. */ .reaction { display: inline-flex; align-items: center; @@ -172,7 +309,25 @@ body { border: 1px solid #e3e8ef; border-radius: 12px; background-color: #f4f6fa; + font: inherit; font-size: 12px; + color: inherit; + cursor: pointer; +} + +.reaction:hover { + border-color: #c8d1de; + background-color: #eaeef5; +} + +.reaction-mine { + border-color: #9dc0f5; + background-color: #e2ecfd; +} + +.reaction-mine .reaction-count { + color: #24509b; + font-weight: 600; } .reaction-count { From da8ab2f664f2988f5647184483a256737f5e395a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 28 Jul 2026 15:40:09 +0200 Subject: [PATCH 06/13] Add a message composer to the ChatRoom workload The app was a read-only viewer. There is now a text input and a Send button below the timeline; sending appends to the end and scrolls to bottom. Sent messages live in Timeline state rather than the fixtures, so the generated data stays immutable and rooms do not grow across iterations. Timestamps continue from the room's last message rather than reading the clock. Enter is an explicit onKeyDown, since a dispatched keydown triggers no default action. No new step: SwitchRooms is unchanged, so this is app surface only. --- .../chat-room/src/components/composer.jsx | 41 ++++++++++++++++ .../chat-room/src/components/timeline.jsx | 22 +++++++-- .../chat-room/src/data/rooms.js | 38 +++++++++++++- suites-experimental/chat-room/src/styles.css | 49 +++++++++++++++++++ 4 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 suites-experimental/chat-room/src/components/composer.jsx diff --git a/suites-experimental/chat-room/src/components/composer.jsx b/suites-experimental/chat-room/src/components/composer.jsx new file mode 100644 index 000000000..c66972645 --- /dev/null +++ b/suites-experimental/chat-room/src/components/composer.jsx @@ -0,0 +1,41 @@ +import { useState } from "react"; + +// Enter is handled explicitly rather than through the form's implicit submission, +// because a dispatched keydown does not trigger default actions, and a timed step +// would have to drive this through the harness. +export default function Composer({ roomName, onSend }) { + const [draft, setDraft] = useState(""); + + const send = (event) => { + event.preventDefault(); + const text = draft.trim(); + if (!text) + return; + onSend(text); + setDraft(""); + }; + + const handleKeyDown = (event) => { + if (event.key === "Enter" && !event.shiftKey) + send(event); + }; + + return ( +
        + setDraft(event.target.value)} + onKeyDown={handleKeyDown} + /> + +
        + ); +} diff --git a/suites-experimental/chat-room/src/components/timeline.jsx b/suites-experimental/chat-room/src/components/timeline.jsx index 438259431..53c0b6d31 100644 --- a/suites-experimental/chat-room/src/components/timeline.jsx +++ b/suites-experimental/chat-room/src/components/timeline.jsx @@ -1,14 +1,22 @@ import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; import { ActionsContext } from "../actions.js"; +import { createOutgoingMessage } from "../data/rooms.js"; +import Composer from "./composer.jsx"; import Message from "./message.jsx"; export default function Timeline({ room, onSelectRoom }) { const scrollerRef = useRef(null); const [highlightedId, setHighlightedId] = useState(null); - // Chat clients open a room at its newest message. Reading scrollHeight - // forces layout and the assignment jumps without animation, which is the - // work a real client does on every room switch. + // Messages the local user sent, kept here rather than pushed into the + // fixtures, so the generated data stays immutable and a room switch (which + // remounts this component) restores the original timeline. Otherwise rooms + // would grow across repeated benchmark iterations. + const [sent, setSent] = useState([]); + + // Chat clients open a room at its newest message, and jump back to the + // bottom after sending. Reading scrollHeight forces layout and the + // assignment jumps without animation, which is the work a real client does. // // Done by hand rather than with flex-direction: column-reverse, because // column-reverse inverts scrollTop and later steps drive scrollTop @@ -16,7 +24,7 @@ export default function Timeline({ room, onSelectRoom }) { useLayoutEffect(() => { const scroller = scrollerRef.current; scroller.scrollTop = scroller.scrollHeight; - }, [room.id]); + }, [room.id, sent.length]); // Clicking a reply quote jumps to the message it quotes and leaves it // highlighted. The offset is computed from rects and assigned to scrollTop @@ -39,13 +47,19 @@ export default function Timeline({ room, onSelectRoom }) { const actions = useMemo(() => ({ selectRoom: onSelectRoom, jumpToMessage }), [onSelectRoom, jumpToMessage]); + const handleSend = useCallback((text) => setSent((previous) => [...previous, createOutgoingMessage(room, previous.length, text)]), [room]); + return (
          {room.messages.map((message) => )} + {sent.map((message) => + + )}
        +
        ); } diff --git a/suites-experimental/chat-room/src/data/rooms.js b/suites-experimental/chat-room/src/data/rooms.js index 247da0acc..a80acc766 100644 --- a/suites-experimental/chat-room/src/data/rooms.js +++ b/suites-experimental/chat-room/src/data/rooms.js @@ -333,14 +333,17 @@ function buildReactions(seed) { } // Format a deterministic HH:MM timestamp without touching the real clock. -function buildTime(seed) { - const minutesInDay = seed % (24 * 60); +function formatTime(minutesInDay) { const hours = Math.floor(minutesInDay / 60); const minutes = minutesInDay % 60; const pad = (value) => String(value).padStart(2, "0"); return `${pad(hours)}:${pad(minutes)}`; } +function buildTime(seed) { + return formatTime(seed % (24 * 60)); +} + function spansToText(spans) { let text = ""; for (const span of spans) { @@ -440,3 +443,34 @@ function buildRooms() { } export const rooms = buildRooms(); + +const LOCAL_USER_NAME = "You"; + +export const LOCAL_USER = { + name: LOCAL_USER_NAME, + initials: initials(LOCAL_USER_NAME), + colorIndex: SENDERS.length % AVATAR_COLOR_COUNT, +}; + +// Build a message the local user just sent, in the same shape as the generated +// fixtures so the timeline renders it through the same path. +// +// The timestamp continues from the room's last message instead of reading the +// clock, keeping the workload deterministic. Runs of outgoing messages group +// under the first one, the way a burst from one sender does anywhere else. +export function createOutgoingMessage(room, sequence, text) { + const previous = room.messages[room.messages.length - 1].time.split(":").map(Number); + const sentAt = (previous[0] * 60 + previous[1] + 1 + sequence) % (24 * 60); + return { + id: `${room.id}-sent-${sequence}`, + sender: LOCAL_USER.name, + senderInitials: LOCAL_USER.initials, + colorIndex: LOCAL_USER.colorIndex, + time: formatTime(sentAt), + blocks: [{ type: "p", spans: [{ type: "text", text }] }], + preview: text, + replyTo: null, + grouped: sequence > 0, + reactions: [], + }; +} diff --git a/suites-experimental/chat-room/src/styles.css b/suites-experimental/chat-room/src/styles.css index 4a042ef92..97b989a04 100644 --- a/suites-experimental/chat-room/src/styles.css +++ b/suites-experimental/chat-room/src/styles.css @@ -115,6 +115,55 @@ body { color: #737d8c; } +/* Composer. Sits below the timeline, so the scroller gives up the height it takes. */ +.composer { + display: flex; + flex: 0 0 auto; + gap: 8px; + padding: 12px 20px; + border-top: 1px solid #e3e8ef; + background-color: #fff; +} + +.composer-input { + flex: 1 1 auto; + min-width: 0; + padding: 8px 12px; + border: 1px solid #d5dbe5; + border-radius: 8px; + font: inherit; + font-size: 14px; + color: inherit; +} + +.composer-input:focus { + border-color: #9dc0f5; + outline: 2px solid #dce8fb; + outline-offset: -1px; +} + +.composer-send { + flex: 0 0 auto; + padding: 8px 16px; + border: 0; + border-radius: 8px; + background-color: #2a6fd6; + font: inherit; + font-size: 14px; + font-weight: 600; + color: #fff; + cursor: pointer; +} + +.composer-send:hover:enabled { + background-color: #245fb8; +} + +.composer-send:disabled { + background-color: #c8d1de; + cursor: default; +} + /* Timeline */ .timeline { flex: 1 1 auto; From 9e9ab122a2be1a253d03d38cb3fa37be2760c547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 28 Jul 2026 16:00:11 +0200 Subject: [PATCH 07/13] Add image attachments and link previews to ChatRoom messages Message bodies gain an image attachment and an unfurl card block, covering about 11% of messages. Artwork is SVG data URIs built from a palette and shape variant by a new graphics module, so the workload still ships no image assets. The URIs are memoized on a reduced palette/variant key -- with the raw hashes every message got a distinct gradient id, so the browser decoded 652 images instead of 127. Images carry explicit width and height, or a row would resize once the image decoded and invalidate the height cache. Also fixes bullet lists repeating a line about 13% of the time. Row heights now span 24px to 278px with 58 distinct values, up from 229px and 48. SwitchRooms grows from ~367ms to ~442ms. --- .../chat-room/src/components/rich-text.jsx | 16 ++++ .../chat-room/src/data/graphics.js | 66 ++++++++++++++++ .../chat-room/src/data/rooms.js | 76 ++++++++++++++++--- suites-experimental/chat-room/src/styles.css | 58 ++++++++++++++ 4 files changed, 204 insertions(+), 12 deletions(-) create mode 100644 suites-experimental/chat-room/src/data/graphics.js diff --git a/suites-experimental/chat-room/src/components/rich-text.jsx b/suites-experimental/chat-room/src/components/rich-text.jsx index b6ae92efd..e7ea69c8f 100644 --- a/suites-experimental/chat-room/src/components/rich-text.jsx +++ b/suites-experimental/chat-room/src/components/rich-text.jsx @@ -50,6 +50,22 @@ function Block({ block }) { ); + case "image": + // Intrinsic width/height so the row reserves its space before the + // image decodes. Without them the height would change after layout, + // invalidating the timeline's height cache. + return {block.alt}; + case "unfurl": + return ( + event.preventDefault()}> + + + {block.site} + {block.title} + {block.description} + + + ); case "list": return (
          diff --git a/suites-experimental/chat-room/src/data/graphics.js b/suites-experimental/chat-room/src/data/graphics.js new file mode 100644 index 000000000..bfe0659fe --- /dev/null +++ b/suites-experimental/chat-room/src/data/graphics.js @@ -0,0 +1,66 @@ +// Procedurally generated SVG artwork, so the workload ships no third-party image +// assets. Data URIs are memoized per variant rather than per message, so a few +// dozen images cover the corpus and the browser can reuse a decode. + +const SHAPE_VARIANTS = 4; + +const PALETTES = [ + ["#3b82f6", "#bfdbfe"], + ["#a855f7", "#f0d9ff"], + ["#10b981", "#b7f5da"], + ["#ef4444", "#ffd5d5"], + ["#f59e0b", "#ffeab0"], + ["#06b6d4", "#b8f2fb"], + ["#6366f1", "#d5daff"], + ["#84cc16", "#e3fab3"], +]; + +// Each variant arranges flat shapes over the gradient differently, so thumbnails +// read as distinct pictures without any of them being a photo. +function shapesFor(variant, width, height) { + const w = width; + const h = height; + switch (variant) { + case 0: + return ``; + case 1: + return ``; + case 2: { + const bars = [0.35, 0.62, 0.45, 0.8, 0.55]; + return bars + .map((value, index) => { + const barWidth = (w * 0.9) / bars.length - 6; + const x = w * 0.05 + index * ((w * 0.9) / bars.length); + return ``; + }) + .join(""); + } + default: + return ``; + } +} + +const cache = new Map(); + +export function generatedImage(paletteIndex, variant, width, height) { + // Callers pass raw hashes. Reduce them before they reach the cache key or the + // gradient id, or every message gets a distinct id and its own decode. + const palette = paletteIndex % PALETTES.length; + const shape = variant % SHAPE_VARIANTS; + + const key = `${palette}-${shape}-${width}x${height}`; + const cached = cache.get(key); + if (cached) + return cached; + + const [from, to] = PALETTES[palette]; + const gradientId = `g${palette}${shape}`; + const svg = `${shapesFor( + shape, + width, + height + )}`; + const src = `data:image/svg+xml,${encodeURIComponent(svg)}`; + cache.set(key, src); + return src; +} diff --git a/suites-experimental/chat-room/src/data/rooms.js b/suites-experimental/chat-room/src/data/rooms.js index a80acc766..0296b5f90 100644 --- a/suites-experimental/chat-room/src/data/rooms.js +++ b/suites-experimental/chat-room/src/data/rooms.js @@ -2,11 +2,10 @@ // integer hash, with no Math.random() or Date.now(), so every run renders identical // content -- entirely original, with no third-party assets. // -// Message bodies are structured blocks rather than plain strings, the way a real -// client keeps them once markdown has been parsed: paragraphs, fenced code, -// blockquotes and bullet lists, with inline runs for code, links, @mentions and -// #room pills. The point is non-uniform row heights, which is what a windowing -// timeline has to cope with. +// Bodies are structured blocks rather than plain strings, the way a client keeps +// them once markdown has been parsed. The point is non-uniform row heights. + +import { generatedImage } from "./graphics.js"; const ROOM_COUNT = 40; const MESSAGES_PER_ROOM = 150; @@ -113,6 +112,13 @@ const LINK_LABELS = ["the trace", "last night's run", "this regression", "the pr const LINK_PATHS = ["traces/2f9c", "runs/nightly", "profiles/hot-path", "spec/scroll-anchoring", "notes/timeline", "dashboards/perf", "reports/42", "compare/main"]; +const UNFURL_LINKS = [ + { site: "example.com", title: "Scroll anchoring, and why feeds jump", description: "How browsers pin a scroll position while content is inserted above the viewport, and where it gives up." }, + { site: "perf.example.com", title: "Nightly run 482 vs 481", description: "Geomean moved 1.8% on the chat suites. Row measurement dominates the profile." }, + { site: "docs.example.com", title: "Windowing a variable-height list", description: "Estimate, measure, cache, correct. The four steps every hand-rolled virtualizer ends up with." }, + { site: "bugs.example.com", title: "Timeline jumps when the panel opens", description: "Narrowing the scroller re-wraps every row, so the cached heights are all stale at once." }, +]; + const QUOTE_LINES = [ "can we get a number on how bad the jank is before we start moving code around", "the window only recycles about twenty rows, so the mount cost should be flat", @@ -279,9 +285,11 @@ function buildCodeBlock(seed) { function buildList(seed) { const count = 2 + (hash(seed, 402) % 3); + // Walk the pool from a seeded offset, so a list never repeats a line. + const start = hash(seed, 403) % LIST_ITEMS.length; const items = []; for (let i = 0; i < count; i++) { - const tokens = [pick(LIST_ITEMS, seed, 403 + i)]; + const tokens = [LIST_ITEMS[(start + i) % LIST_ITEMS.length]]; if (hash(seed, 413 + i) % 3 === 0) tokens.push({ type: "code", text: pick(CODE_TOKENS, seed, 423 + i) }); items.push(tokensToSpans(tokens)); @@ -289,9 +297,45 @@ function buildList(seed) { return { type: "list", items }; } -// Compose a message body out of blocks. The shape distribution is what drives -// the row height spread: emoji-only one-liners at one end, a paragraph plus a -// fenced code block at the other. +// A few different aspect ratios, so attachments widen the row height spread +// rather than all adding the same block. +const IMAGE_SIZES = [ + { width: 260, height: 146 }, + { width: 220, height: 165 }, + { width: 180, height: 180 }, +]; + +const IMAGE_ALTS = ["a flame chart of the room switch", "the timeline mid-scroll", "row heights before and after windowing", "a screenshot of the composer", "the scroll anchoring repro"]; + +function buildImage(seed) { + const size = IMAGE_SIZES[hash(seed, 501) % IMAGE_SIZES.length]; + return { + type: "image", + src: generatedImage(hash(seed, 502), hash(seed, 503), size.width, size.height), + width: size.width, + height: size.height, + alt: pick(IMAGE_ALTS, seed, 504), + }; +} + +// Link previews, the card a client renders after unfurling a URL. +function buildUnfurl(seed) { + const link = pick(UNFURL_LINKS, seed, 601); + return { + type: "unfurl", + href: `https://example.com/${pick(LINK_PATHS, seed, 602)}`, + site: link.site, + title: link.title, + description: link.description, + thumbSrc: generatedImage(hash(seed, 603), hash(seed, 604), 72, 72), + thumbWidth: 72, + thumbHeight: 72, + }; +} + +// The shape distribution is what drives the row height spread: emoji-only +// one-liners at one end, a paragraph plus an attachment or fenced code block at +// the other. function buildBlocks(seed) { const shape = hash(seed, 101) % 100; @@ -304,12 +348,16 @@ function buildBlocks(seed) { blocks.push(buildCodeBlock(seed)); if (shape < 13) blocks.push({ type: "p", spans: buildParagraph(seed, 2) }); - } else if (shape < 30) { + } else if (shape < 28) { blocks.push(buildList(seed)); - } else if (shape < 38) { + } else if (shape < 35) { blocks.push({ type: "quote", spans: [{ type: "text", text: pick(QUOTE_LINES, seed, 103) }] }); blocks.push({ type: "p", spans: buildParagraph(seed, 3) }); - } else if (shape < 48) { + } else if (shape < 41) { + blocks.push(buildImage(seed)); + } else if (shape < 46) { + blocks.push(buildUnfurl(seed)); + } else if (shape < 54) { blocks.push({ type: "p", spans: buildParagraph(seed, 4) }); } return blocks; @@ -365,6 +413,10 @@ function blocksToText(blocks) { parts.push(block.lines.join(" ")); else if (block.type === "list") parts.push(block.items.map(spansToText).join(" ")); + else if (block.type === "image") + parts.push(block.alt); + else if (block.type === "unfurl") + parts.push(`${block.title} ${block.site}`); else parts.push(spansToText(block.spans)); } diff --git a/suites-experimental/chat-room/src/styles.css b/suites-experimental/chat-room/src/styles.css index 97b989a04..48c4f85eb 100644 --- a/suites-experimental/chat-room/src/styles.css +++ b/suites-experimental/chat-room/src/styles.css @@ -299,6 +299,64 @@ body { white-space: pre; } +/* Attachments and link previews. The artwork is procedurally generated SVG. */ +.rich-image { + display: block; + max-width: 100%; + height: auto; + margin: 6px 0; + border: 1px solid #e3e8ef; + border-radius: 8px; +} + +.rich-unfurl { + display: flex; + gap: 10px; + max-width: 460px; + margin: 6px 0; + padding: 10px; + border: 1px solid #e3e8ef; + border-left: 3px solid #9dc0f5; + border-radius: 8px; + background-color: #fbfcfe; + color: inherit; + text-decoration: none; +} + +.rich-unfurl:hover { + background-color: #f4f8ff; +} + +.rich-unfurl-thumb { + flex: 0 0 auto; + border-radius: 6px; +} + +.rich-unfurl-body { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; +} + +.rich-unfurl-site { + font-size: 11px; + font-weight: 600; + color: #737d8c; + text-transform: uppercase; + letter-spacing: 0.02em; +} + +.rich-unfurl-title { + font-weight: 600; + color: #24509b; +} + +.rich-unfurl-description { + font-size: 13px; + color: #5a6472; +} + .rich-quote { margin: 4px 0; padding: 2px 0 2px 10px; From db04e9d2855498f067583659dccad215e38cddce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 28 Jul 2026 17:35:00 +0200 Subject: [PATCH 08/13] Virtualize the ChatRoom timeline and scale it to 1500 messages Speedometer has almost no scroll coverage: across the 32 default suites the only scrolling inside a timed step is a single scrollIntoView. A chat timeline is the natural vehicle for that, but only once it is windowed. Rooms grow from 150 to 1500 messages and the timeline mounts ~15 rows. The virtualizer is hand-rolled, since a generic one assumes a height it can know up front and a chat row's depends on how its text wraps. The new height model estimates, measures, caches and corrects, keeping prefix sums so an offset can be turned back into a row index without touching the DOM. Three constraints it has to respect -- the scroller's height lagging the model by a commit, the row estimate having to sit under the real mean, and overflow-anchor having to be off -- are documented at their sites. ScrollTimeline is the new step, driving explicit offsets back through history and then in long strides. SwitchRooms is unchanged but costs ~4.5x less. PageElement gains scrollTop/scrollHeight/clientHeight, since scrollIntoView cannot reach an unmounted row. --- resources/benchmark-runner.mjs | 20 ++ suites-experimental/chat-room/README.md | 29 ++- .../chat-room/src/components/message.jsx | 6 +- .../chat-room/src/components/timeline.jsx | 211 +++++++++++++++--- .../chat-room/src/data/rooms.js | 22 +- .../chat-room/src/row-heights.js | 105 +++++++++ suites-experimental/chat-room/src/styles.css | 8 +- suites-experimental/suites.mjs | 35 +++ 8 files changed, 387 insertions(+), 49 deletions(-) create mode 100644 suites-experimental/chat-room/src/row-heights.js diff --git a/resources/benchmark-runner.mjs b/resources/benchmark-runner.mjs index 257fca726..66ef39273 100644 --- a/resources/benchmark-runner.mjs +++ b/resources/benchmark-runner.mjs @@ -163,6 +163,26 @@ class PageElement { this.#node.scrollIntoView(options); } + /** + * Scroll geometry, for steps that drive a scroller to an explicit offset. + * Never animate a scroll inside a measured step: assign an offset instead. + */ + get scrollTop() { + return this.#node.scrollTop; + } + + set scrollTop(offset) { + this.#node.scrollTop = offset; + } + + get scrollHeight() { + return this.#node.scrollHeight; + } + + get clientHeight() { + return this.#node.clientHeight; + } + dispatchEvent(eventName, options = NATIVE_OPTIONS, eventType = Event) { if (eventName === "submit") // FIXME FireFox doesn't like `new Event('submit') diff --git a/suites-experimental/chat-room/README.md b/suites-experimental/chat-room/README.md index a40e29cba..358010526 100644 --- a/suites-experimental/chat-room/README.md +++ b/suites-experimental/chat-room/README.md @@ -5,8 +5,12 @@ between rooms/channels is one of their most frequent and performance-sensitive interactions: the previous conversation's timeline is torn down and a new, often long, timeline of rich messages is rendered in its place. -This workload is an original, self-contained React app that reproduces that -interaction. It is **not** derived from any existing chat product's source code +Reading back through a conversation is the other one, and on a room this long it +is not a plain scroll: the timeline is windowed, so every offset mounts rows +whose height is not known until they have been laid out. + +This workload is an original, self-contained React app that reproduces those +interactions. It is **not** derived from any existing chat product's source code and ships no third-party assets, so it is free of licensing and trademark concerns. @@ -14,18 +18,27 @@ concerns. - React reconciliation cost of repeatedly mounting/unmounting a large timeline - DOM churn and layout when switching between rooms +- Windowed scrolling that measures rows only after mounting them, and corrects + the scroll position against what they measured - Flex/grid layout of a typical two-pane chat UI with many small components (avatars, sender names, timestamps, message bodies) ## How are we testing -The app renders a sidebar of rooms and, for the selected room, a timeline of -messages. All content is generated deterministically at load time (no network, -no backend, no `Math.random`/`Date.now`), so every run renders identical data. +The app renders a sidebar of rooms and, for the selected room, a windowed +timeline of its 1500 messages. All content is generated deterministically at load +time (no network, no backend, no `Math.random`/`Date.now`), so every run renders +identical data. + +`ScrollTimeline` reads back through a room's history, first a viewport at a time +and then in the long strides that dragging the scrollbar produces. The two cover +opposite halves of the height model: the short steps land on rows that have +already been measured and are being recycled, the strides on rows that have only +ever been estimated. -The timed step (`SwitchRooms`) clicks through the rooms in the sidebar in turn. -Each room's timeline is keyed by room id, so a switch fully unmounts the old -timeline and mounts the new one. +`SwitchRooms` clicks through the rooms in the sidebar in turn. Each room's +timeline is keyed by room id, so a switch fully unmounts the old timeline and +mounts the new one. ## Developer Documentation diff --git a/suites-experimental/chat-room/src/components/message.jsx b/suites-experimental/chat-room/src/components/message.jsx index 5f2d1885c..7a38c6e29 100644 --- a/suites-experimental/chat-room/src/components/message.jsx +++ b/suites-experimental/chat-room/src/components/message.jsx @@ -6,7 +6,9 @@ import RichText from "./rich-text.jsx"; // Consecutive messages from the same sender collapse into the previous one, the // way a chat client renders a burst of them: no repeated avatar or name, just // the body under a gutter that holds the timestamp on hover. -export default function Message({ message, highlighted }) { +// The index is the row's position in the whole room, not in the mounted window, +// so the timeline can file the measured height against the right message. +export default function Message({ index, message, highlighted }) { const { jumpToMessage } = useActions(); const classNames = ["timeline-message"]; if (message.grouped) @@ -15,7 +17,7 @@ export default function Message({ message, highlighted }) { classNames.push("timeline-message-highlighted"); return ( -
        • +
        • {message.grouped ? {message.time} : diff --git a/suites-experimental/chat-room/src/components/timeline.jsx b/suites-experimental/chat-room/src/components/timeline.jsx index 53c0b6d31..35f8479c1 100644 --- a/suites-experimental/chat-room/src/components/timeline.jsx +++ b/suites-experimental/chat-room/src/components/timeline.jsx @@ -1,63 +1,208 @@ import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; import { ActionsContext } from "../actions.js"; import { createOutgoingMessage } from "../data/rooms.js"; +import { RowHeights } from "../row-heights.js"; import Composer from "./composer.jsx"; import Message from "./message.jsx"; +// Only the rows near the viewport are mounted; two spacers stand in for the rest. +// The scroller carries no vertical padding (see styles.css), so scrollTop maps one +// to one onto the height model's offsets. + +// Rows kept mounted either side of the visible range, so a small scroll reuses +// rows already in the DOM instead of replacing the whole window. +const OVERSCAN = 4; + +// Deliberately under the measured mean of ~111px: a room opens pinned to its +// newest message, and an estimate that ran high would shrink the measured total +// under the pin and drag the window backwards through history. +const ESTIMATED_ROW_HEIGHT = 100; + +// How close to the bottom still counts as following the conversation. +const PIN_THRESHOLD = 4; + export default function Timeline({ room, onSelectRoom }) { const scrollerRef = useRef(null); const [highlightedId, setHighlightedId] = useState(null); - // Messages the local user sent, kept here rather than pushed into the - // fixtures, so the generated data stays immutable and a room switch (which - // remounts this component) restores the original timeline. Otherwise rooms - // would grow across repeated benchmark iterations. + // Messages the local user sent, kept here rather than pushed into the fixtures, + // so a room switch remounts back to the original timeline instead of letting + // rooms grow across benchmark iterations. const [sent, setSent] = useState([]); - // Chat clients open a room at its newest message, and jump back to the - // bottom after sending. Reading scrollHeight forces layout and the - // assignment jumps without animation, which is the work a real client does. + const messages = useMemo(() => sent.length ? [...room.messages, ...sent] : room.messages, [room.messages, sent]); + + const heights = useMemo(() => new RowHeights(room.messages.length, ESTIMATED_ROW_HEIGHT), [room.messages]); + + // Only ever grows, and only at the end, so calling it here is idempotent: a + // re-render with the same messages changes nothing. + heights.grow(messages.length); + + const indexById = useMemo(() => new Map(messages.map((message, index) => [message.id, index])), [messages]); + + // The mounted range, end exclusive. Starts empty because the total height is + // still all estimates at that point: the mount effect below pins the scroller + // to the bottom first, and the window follows from that offset. + const [range, setRange] = useState({ start: 0, end: 0 }); + + // True while the timeline is following the conversation, the way a chat client + // keeps you at the newest message until you scroll away yourself. + const pinnedToBottom = useRef(true); + + // Set while a reply-quote jump is settling, because the target's offset is an + // estimate at the moment the jump is issued. + const jumpTarget = useRef(null); + + // The row under the top of the viewport, and how far into it, captured before + // measurements moved the offsets out from under it. + const anchor = useRef(null); + + // Bumped when a measurement changes a cached height, purely to get another + // render: the spacers are computed from the model during render, so nothing + // else tells React that it moved. + const [, recordMeasurements] = useState(0); + + const rangeFor = useCallback( + (scrollTop, viewportHeight) => { + const first = heights.indexAt(scrollTop); + const bottom = scrollTop + viewportHeight; + let last = first; + while (last + 1 < heights.count && heights.offsetAt(last + 1) < bottom) + last++; + return { + start: Math.max(0, first - OVERSCAN), + end: Math.min(heights.count, last + 1 + OVERSCAN), + }; + }, + [heights] + ); + + const centeredOffset = useCallback( + (index, viewportHeight) => { + const centered = heights.offsetAt(index) - (viewportHeight - heights.heightAt(index)) / 2; + return Math.max(0, Math.min(centered, heights.totalHeight - viewportHeight)); + }, + [heights] + ); + + // Comparing rather than assigning unconditionally lets React bail out when the + // window has not moved, which is the common case for a scroll inside the + // overscan and for the second pass of a correction. + const updateRange = useCallback((next) => { + setRange((previous) => previous.start === next.start && previous.end === next.end ? previous : next); + }, []); + + // Captured against the offsets the DOM was last laid out with. Restoring the + // pair after the offsets move is what keeps the content still. + const captureAnchor = useCallback( + (scrollTop) => { + const index = heights.indexAt(scrollTop); + return { index, offset: scrollTop - heights.offsetAt(index) }; + }, + [heights] + ); + + const handleScroll = useCallback(() => { + const scroller = scrollerRef.current; + pinnedToBottom.current = scroller.scrollHeight - (scroller.scrollTop + scroller.clientHeight) <= PIN_THRESHOLD; + updateRange(rangeFor(scroller.scrollTop, scroller.clientHeight)); + }, [rangeFor, updateRange]); + + // Measure what is mounted, then put the content back where it was. Runs after + // every commit, because a row's height can change without the window moving: + // that is what will make a narrower timeline re-measure in the thread-panel + // phase. // - // Done by hand rather than with flex-direction: column-reverse, because - // column-reverse inverts scrollTop and later steps drive scrollTop - // explicitly. + // Correcting the scroll position is the part that makes windowing honest. The + // rows that just mounted were laid out against estimates, so the offsets read + // before this pass are stale the moment a measurement lands, and without the + // correction the content under the viewport would jump. useLayoutEffect(() => { const scroller = scrollerRef.current; - scroller.scrollTop = scroller.scrollHeight; - }, [room.id, sent.length]); + const viewportHeight = scroller.clientHeight; + + const pending = anchor.current; + const captured = pending ?? captureAnchor(scroller.scrollTop); + + let changed = false; + for (const row of scroller.querySelectorAll(".timeline-message")) { + if (heights.measure(Number(row.dataset.index), row.getBoundingClientRect().height)) + changed = true; + } + + // The spacers were sized during render, from the heights these measurements + // just replaced, so the scroller is a commit behind the model. Take another + // render, or the offset gets clamped against a height about to change. + if (changed) { + anchor.current = captured; + recordMeasurements((passes) => passes + 1); + return; + } + + anchor.current = null; + if (jumpTarget.current !== null) { + scroller.scrollTop = centeredOffset(jumpTarget.current, viewportHeight); + jumpTarget.current = null; + } else if (pinnedToBottom.current) { + scroller.scrollTop = scroller.scrollHeight; + } else if (pending) { + scroller.scrollTop = heights.offsetAt(pending.index) + pending.offset; + } + + updateRange(rangeFor(scroller.scrollTop, viewportHeight)); + }); // Clicking a reply quote jumps to the message it quotes and leaves it - // highlighted. The offset is computed from rects and assigned to scrollTop - // directly: no smooth behavior and no scrollIntoView, so a timed step stays + // highlighted. The offset comes from the height model rather than the DOM, + // because the quoted message is usually not mounted: scrolling to an + // arbitrary row is the case a virtualizer has to answer without measuring. + // No smooth behavior and no scrollIntoView, so a timed step stays // deterministic. The highlight holds until the next jump rather than // clearing on a timer, for the same reason, and only changes background // colour, so committing it asynchronously cannot move the offset computed // here. - const jumpToMessage = useCallback((messageId) => { - const scroller = scrollerRef.current; - const row = scroller.querySelector(`[data-message-id="${messageId}"]`); - if (!row) - return; - setHighlightedId(messageId); - const rowRect = row.getBoundingClientRect(); - const scrollerRect = scroller.getBoundingClientRect(); - const centeringOffset = (scroller.clientHeight - rowRect.height) / 2; - scroller.scrollTop += rowRect.top - scrollerRect.top - centeringOffset; - }, []); + const jumpToMessage = useCallback( + (messageId) => { + const index = indexById.get(messageId); + if (index === undefined) + return; + const scroller = scrollerRef.current; + setHighlightedId(messageId); + pinnedToBottom.current = false; + jumpTarget.current = index; + scroller.scrollTop = centeredOffset(index, scroller.clientHeight); + updateRange(rangeFor(scroller.scrollTop, scroller.clientHeight)); + }, + [centeredOffset, indexById, rangeFor, updateRange] + ); const actions = useMemo(() => ({ selectRoom: onSelectRoom, jumpToMessage }), [onSelectRoom, jumpToMessage]); - const handleSend = useCallback((text) => setSent((previous) => [...previous, createOutgoingMessage(room, previous.length, text)]), [room]); + const handleSend = useCallback( + (text) => { + pinnedToBottom.current = true; + jumpTarget.current = null; + setSent((previous) => [...previous, createOutgoingMessage(room, previous.length, text)]); + }, + [room] + ); + + // Grouping is taken from the fixture rather than from the window, so a row + // renders the same whether or not the message above it happens to be mounted. + // Deriving it from the window would change a row's height as the window + // moved, which would invalidate the very cache being built here. + const rows = []; + for (let index = range.start; index < range.end; index++) { + const message = messages[index]; + rows.push(); + } return ( -
            - {room.messages.map((message) => - - )} - {sent.map((message) => - - )} +
              +
            diff --git a/suites-experimental/chat-room/src/data/rooms.js b/suites-experimental/chat-room/src/data/rooms.js index 0296b5f90..910b06851 100644 --- a/suites-experimental/chat-room/src/data/rooms.js +++ b/suites-experimental/chat-room/src/data/rooms.js @@ -8,7 +8,12 @@ import { generatedImage } from "./graphics.js"; const ROOM_COUNT = 40; -const MESSAGES_PER_ROOM = 150; + +// Real channels hold years of history, which is only feasible to render with a +// windowed timeline. Generation is eager at module load, so this number is a +// tradeoff against load time rather than against the measured steps: see the +// figure recorded in debugging/chat-room-realism-plan.md. +const MESSAGES_PER_ROOM = 1500; const ROOM_NAMES = [ "General", @@ -434,10 +439,13 @@ function buildSenderSequence(roomIndex, count) { const senders = []; let index = hash(roomIndex, 301) % SENDERS.length; while (senders.length < count) { - const runLength = 1 + (hash(roomIndex * 1000 + senders.length, 302) % 3); + // Same construction as a message seed, so one room's run lengths stay + // independent of every other room's. + const seed = roomIndex * count + senders.length; + const runLength = 1 + (hash(seed, 302) % 3); for (let i = 0; i < runLength && senders.length < count; i++) senders.push(SENDERS[index]); - index = (index + 1 + (hash(roomIndex * 1000 + senders.length, 303) % (SENDERS.length - 1))) % SENDERS.length; + index = (index + 1 + (hash(roomIndex * count + senders.length, 303) % (SENDERS.length - 1))) % SENDERS.length; } return senders; } @@ -454,9 +462,15 @@ function buildMessages(roomIndex) { // Inline reply quotes embed a parent message in the child, and always // break the sender group above them. + // + // Most answer something just said, but one in four pulls a message back + // out of the history. Those are the interesting ones for a windowed + // timeline: the quoted message is nowhere in the DOM, so clicking the + // quote has to scroll to a row whose height has never been measured. let replyTo = null; if (i > 0 && hash(seed, 201) % 100 < 18) { - const parent = messages[Math.max(0, i - 1 - (hash(seed, 202) % 6))]; + const distance = hash(seed, 203) % 4 === 0 ? 1 + (hash(seed, 204) % Math.min(i, 400)) : 1 + (hash(seed, 202) % 6); + const parent = messages[Math.max(0, i - distance)]; replyTo = { id: parent.id, sender: parent.sender, excerpt: excerpt(parent.preview, 80) }; } diff --git a/suites-experimental/chat-room/src/row-heights.js b/suites-experimental/chat-room/src/row-heights.js new file mode 100644 index 000000000..45f40be43 --- /dev/null +++ b/suites-experimental/chat-room/src/row-heights.js @@ -0,0 +1,105 @@ +// The height model behind the windowed timeline: estimate, measure, cache, +// correct. Offsets are prefix sums over a mix of measured and estimated heights, +// rebuilt from the earliest row that changed, which is what turns a scroll offset +// back into a row index without touching the DOM. +// +// Hand-rolled because a chat row's height depends on how its text wraps, which a +// generic virtualizer expects to know up front. + +// A negative height means "not measured yet". 0 is reachable -- a conditionally +// collapsed row measures 0px -- and has to stay measured, or it would be +// re-measured on every pass forever. +const UNMEASURED = -1; + +export class RowHeights { + #estimate; + #count; + #heights; + #offsets; + + // Index of the earliest row whose offset needs recomputing. Offsets at or + // below it are still valid, because changing row i only moves the rows after + // it. #count + 1 means everything is up to date. + #dirtyFrom; + + constructor(count, estimate) { + this.#estimate = estimate; + this.#count = count; + this.#heights = new Float64Array(count).fill(UNMEASURED); + this.#offsets = new Float64Array(count + 1); + this.#dirtyFrom = 0; + } + + get count() { + return this.#count; + } + + // A room only ever grows at the end, when the local user sends a message, so + // every measured height and every offset up to the old end survives. + grow(count) { + if (count <= this.#count) + return; + + const heights = new Float64Array(count); + heights.set(this.#heights); + heights.fill(UNMEASURED, this.#count); + const offsets = new Float64Array(count + 1); + offsets.set(this.#offsets); + + this.#dirtyFrom = Math.min(this.#dirtyFrom, this.#count); + this.#heights = heights; + this.#offsets = offsets; + this.#count = count; + } + + heightAt(index) { + const height = this.#heights[index]; + return height === UNMEASURED ? this.#estimate : height; + } + + // Returns whether the cached height moved, so a caller that read offsets + // before the pass knows they are now stale. + measure(index, height) { + if (this.#heights[index] === height) + return false; + this.#heights[index] = height; + if (index < this.#dirtyFrom) + this.#dirtyFrom = index; + return true; + } + + offsetAt(index) { + this.#recomputeOffsets(); + return this.#offsets[index]; + } + + get totalHeight() { + this.#recomputeOffsets(); + return this.#offsets[this.#count]; + } + + // The row containing a content offset, clamped at both ends. + indexAt(offset) { + this.#recomputeOffsets(); + const offsets = this.#offsets; + let low = 0; + let high = this.#count - 1; + while (low < high) { + const middle = (low + high + 1) >> 1; + if (offsets[middle] <= offset) + low = middle; + else + high = middle - 1; + } + return Math.max(0, low); + } + + #recomputeOffsets() { + if (this.#dirtyFrom > this.#count) + return; + const offsets = this.#offsets; + for (let i = this.#dirtyFrom; i < this.#count; i++) + offsets[i + 1] = offsets[i] + this.heightAt(i); + this.#dirtyFrom = this.#count + 1; + } +} diff --git a/suites-experimental/chat-room/src/styles.css b/suites-experimental/chat-room/src/styles.css index 48c4f85eb..8183fce40 100644 --- a/suites-experimental/chat-room/src/styles.css +++ b/suites-experimental/chat-room/src/styles.css @@ -164,13 +164,17 @@ body { cursor: default; } -/* Timeline */ +/* Timeline. No vertical padding, so scrollTop maps one to one onto the height + model's row offsets. overflow-anchor is off because the timeline corrects its own + scroll position after measuring, and the browser would apply a second correction + for the same content change. */ .timeline { flex: 1 1 auto; margin: 0; - padding: 16px 20px; + padding: 0 20px; list-style: none; overflow-y: auto; + overflow-anchor: none; } .timeline-message { diff --git a/suites-experimental/suites.mjs b/suites-experimental/suites.mjs index 8371fc25c..2012df5f0 100644 --- a/suites-experimental/suites.mjs +++ b/suites-experimental/suites.mjs @@ -321,6 +321,41 @@ export const ExperimentalSuites = freezeSuites([ await page.waitForElement(".room-list-item"); }, tests: [ + // Each offset mounts a fresh set of rows, measures them, and corrects + // the scroll position against what they measured. The scroll event is + // dispatched by hand because waiting for the browser's would put a + // frame inside the measured window. + new BenchmarkTestStep("ScrollTimeline", async (page) => { + const timeline = page.querySelector("#timeline"); + const viewportHeight = timeline.clientHeight; + + const scrollTo = async (offset) => { + timeline.scrollTop = offset; + timeline.dispatchEvent("scroll"); + await yieldTask(); + page.layout(); + }; + + // A viewport at a time, from the newest message: the windows + // overlap, so rows are recycled and measured heights reused. + // Relative to the current offset rather than to scrollHeight, + // because the total height moves as rows are measured. + const pages = 10; + for (let i = 0; i < pages; i++) + await scrollTo(timeline.scrollTop - viewportHeight); + + // Then cover the whole room in long strides, the way dragging the + // scrollbar does. Every stride lands on rows that have never been + // measured, so the window is replaced outright and the correction + // runs against estimates. + const strides = 10; + for (let i = strides - 1; i >= 0; i--) + await scrollTo(((timeline.scrollHeight - viewportHeight) * i) / (strides - 1)); + + // Back to the newest message, which is where a chat client leaves + // you and where the next step expects to start. + await scrollTo(timeline.scrollHeight); + }), new BenchmarkTestStep("SwitchRooms", async (page) => { const rooms = page.querySelectorAll(".room-list-item"); const iterations = 20; From e2caf618b3c701c69106a87b1f0b9351fbb4a07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 28 Jul 2026 18:39:07 +0200 Subject: [PATCH 09/13] Load ChatRoom history in pages, anchored against the prepend Preserving the scroll position while content is inserted above the viewport is the chat and feed pattern nothing else in Speedometer exercises, and the one real clients visibly get wrong. A room now opens on the newest 300 of its 1500 messages and fetches 120 more whenever a scroll lands within a viewport of the top. The height model grows at the front as well as the end: a row keeps its index when older history arrives, so measured heights stay valid and only the offsets shift, uniformly, which makes the correction exact. Anchored by hand rather than with the browser's scroll anchoring, which would apply a second correction for the same insertion. LoadOlderMessages is the new step; ScrollTimeline stops one stride short of the top so the two stay independent. Following a reply quote can now load history too. --- suites-experimental/chat-room/README.md | 14 +++-- .../chat-room/src/components/timeline.jsx | 51 ++++++++++++++----- .../chat-room/src/row-heights.js | 39 ++++++++++---- suites-experimental/suites.mjs | 27 +++++++--- 4 files changed, 99 insertions(+), 32 deletions(-) diff --git a/suites-experimental/chat-room/README.md b/suites-experimental/chat-room/README.md index 358010526..55ca743af 100644 --- a/suites-experimental/chat-room/README.md +++ b/suites-experimental/chat-room/README.md @@ -20,15 +20,17 @@ concerns. - DOM churn and layout when switching between rooms - Windowed scrolling that measures rows only after mounting them, and corrects the scroll position against what they measured +- Anchoring the viewport when a page of older messages is inserted above it - Flex/grid layout of a typical two-pane chat UI with many small components (avatars, sender names, timestamps, message bodies) ## How are we testing The app renders a sidebar of rooms and, for the selected room, a windowed -timeline of its 1500 messages. All content is generated deterministically at load -time (no network, no backend, no `Math.random`/`Date.now`), so every run renders -identical data. +timeline of its 1500 messages. A room opens on its newest page and loads older +ones as the reader goes back, the way a real client does. All content is +generated deterministically at load time (no network, no backend, no +`Math.random`/`Date.now`), so every run renders identical data. `ScrollTimeline` reads back through a room's history, first a viewport at a time and then in the long strides that dragging the scrollbar produces. The two cover @@ -40,6 +42,12 @@ ever been estimated. timeline is keyed by room id, so a switch fully unmounts the old timeline and mounts the new one. +`LoadOlderMessages` reads back past the start of the loaded history, which +fetches the next page and inserts it above the viewport. The timeline anchors +itself, correcting its own offset once the new rows have been measured, so +`overflow-anchor` is off and the work is the workload's own rather than the +browser's. + ## Developer Documentation The app was created with Vite + React. It can be previewed during development diff --git a/suites-experimental/chat-room/src/components/timeline.jsx b/suites-experimental/chat-room/src/components/timeline.jsx index 35f8479c1..94588d4cf 100644 --- a/suites-experimental/chat-room/src/components/timeline.jsx +++ b/suites-experimental/chat-room/src/components/timeline.jsx @@ -21,6 +21,11 @@ const ESTIMATED_ROW_HEIGHT = 100; // How close to the bottom still counts as following the conversation. const PIN_THRESHOLD = 4; +// A room opens on its newest page and fetches older ones as the reader goes back, +// the way a real client does, which is what inserts content *above* the viewport. +const INITIAL_PAGE = 300; +const OLDER_PAGE = 120; + export default function Timeline({ room, onSelectRoom }) { const scrollerRef = useRef(null); const [highlightedId, setHighlightedId] = useState(null); @@ -32,11 +37,17 @@ export default function Timeline({ room, onSelectRoom }) { const messages = useMemo(() => sent.length ? [...room.messages, ...sent] : room.messages, [room.messages, sent]); - const heights = useMemo(() => new RowHeights(room.messages.length, ESTIMATED_ROW_HEIGHT), [room.messages]); + // How far back the room has been loaded. Rows before this exist in the fixture + // but are not in the timeline yet. + const initialFirst = Math.max(0, room.messages.length - INITIAL_PAGE); + const [firstLoaded, setFirstLoaded] = useState(initialFirst); + + const heights = useMemo(() => new RowHeights(room.messages.length, initialFirst, ESTIMATED_ROW_HEIGHT), [room.messages, initialFirst]); - // Only ever grows, and only at the end, so calling it here is idempotent: a - // re-render with the same messages changes nothing. + // The model only grows -- at the end when the local user sends, at the front + // when older history loads -- so calling these during render is idempotent. heights.grow(messages.length); + heights.extendTo(firstLoaded); const indexById = useMemo(() => new Map(messages.map((message, index) => [message.id, index])), [messages]); @@ -70,7 +81,7 @@ export default function Timeline({ room, onSelectRoom }) { while (last + 1 < heights.count && heights.offsetAt(last + 1) < bottom) last++; return { - start: Math.max(0, first - OVERSCAN), + start: Math.max(heights.first, first - OVERSCAN), end: Math.min(heights.count, last + 1 + OVERSCAN), }; }, @@ -105,17 +116,22 @@ export default function Timeline({ room, onSelectRoom }) { const handleScroll = useCallback(() => { const scroller = scrollerRef.current; pinnedToBottom.current = scroller.scrollHeight - (scroller.scrollTop + scroller.clientHeight) <= PIN_THRESHOLD; + + // Prefetch the next page a viewport before the top, the way a real client + // does. The anchor has to be taken before the model learns about the new + // rows. No in-flight guard: the rows land synchronously, a page below the top. + if (heights.first > 0 && scroller.scrollTop < scroller.clientHeight) { + anchor.current = captureAnchor(scroller.scrollTop); + setFirstLoaded(Math.max(0, heights.first - OLDER_PAGE)); + return; + } + updateRange(rangeFor(scroller.scrollTop, scroller.clientHeight)); - }, [rangeFor, updateRange]); + }, [captureAnchor, heights, rangeFor, updateRange]); // Measure what is mounted, then put the content back where it was. Runs after - // every commit, because a row's height can change without the window moving: - // that is what will make a narrower timeline re-measure in the thread-panel - // phase. - // - // Correcting the scroll position is the part that makes windowing honest. The - // rows that just mounted were laid out against estimates, so the offsets read - // before this pass are stale the moment a measurement lands, and without the + // every commit, because a row's height can change without the window moving. + // The rows that just mounted were laid out against estimates, so without the // correction the content under the viewport would jump. useLayoutEffect(() => { const scroller = scrollerRef.current; @@ -170,10 +186,19 @@ export default function Timeline({ room, onSelectRoom }) { setHighlightedId(messageId); pinnedToBottom.current = false; jumpTarget.current = index; + + // A quote can point further back than the room has been loaded, so the + // history in between has to come in before there is an offset to + // scroll to, the way following a permalink loads its context. + if (index < heights.first) { + heights.extendTo(Math.max(0, index - OVERSCAN)); + setFirstLoaded(heights.first); + } + scroller.scrollTop = centeredOffset(index, scroller.clientHeight); updateRange(rangeFor(scroller.scrollTop, scroller.clientHeight)); }, - [centeredOffset, indexById, rangeFor, updateRange] + [centeredOffset, heights, indexById, rangeFor, updateRange] ); const actions = useMemo(() => ({ selectRoom: onSelectRoom, jumpToMessage }), [onSelectRoom, jumpToMessage]); diff --git a/suites-experimental/chat-room/src/row-heights.js b/suites-experimental/chat-room/src/row-heights.js index 45f40be43..78b4b6117 100644 --- a/suites-experimental/chat-room/src/row-heights.js +++ b/suites-experimental/chat-room/src/row-heights.js @@ -17,25 +17,43 @@ export class RowHeights { #heights; #offsets; - // Index of the earliest row whose offset needs recomputing. Offsets at or - // below it are still valid, because changing row i only moves the rows after - // it. #count + 1 means everything is up to date. + // The oldest loaded row. The model covers [#first, #count); older rows + // contribute no height because they are not in the timeline yet. + #first; + + // Earliest row whose offset needs recomputing: changing row i only moves the + // rows after it. #count + 1 means everything is up to date. #dirtyFrom; - constructor(count, estimate) { + constructor(count, first, estimate) { this.#estimate = estimate; this.#count = count; + this.#first = first; this.#heights = new Float64Array(count).fill(UNMEASURED); this.#offsets = new Float64Array(count + 1); - this.#dirtyFrom = 0; + this.#dirtyFrom = first; } get count() { return this.#count; } - // A room only ever grows at the end, when the local user sends a message, so - // every measured height and every offset up to the old end survives. + get first() { + return this.#first; + } + + // Load older history. Measured heights stay valid because a row keeps its + // index: the offsets all shift by the height of the rows that were added, + // which is what lets the scroll position be corrected exactly. + extendTo(first) { + if (first >= this.#first) + return; + this.#first = first; + this.#dirtyFrom = first; + } + + // A room only ever grows at the end, when the local user sends, so every + // measured height and every offset up to the old end survives. grow(count) { if (count <= this.#count) return; @@ -82,7 +100,7 @@ export class RowHeights { indexAt(offset) { this.#recomputeOffsets(); const offsets = this.#offsets; - let low = 0; + let low = this.#first; let high = this.#count - 1; while (low < high) { const middle = (low + high + 1) >> 1; @@ -91,13 +109,16 @@ export class RowHeights { else high = middle - 1; } - return Math.max(0, low); + return Math.max(this.#first, low); } #recomputeOffsets() { if (this.#dirtyFrom > this.#count) return; const offsets = this.#offsets; + // Offsets run from the oldest loaded row, which is the origin the + // scroller's own coordinates line up with. + offsets[this.#first] = 0; for (let i = this.#dirtyFrom; i < this.#count; i++) offsets[i + 1] = offsets[i] + this.heightAt(i); this.#dirtyFrom = this.#count + 1; diff --git a/suites-experimental/suites.mjs b/suites-experimental/suites.mjs index 2012df5f0..7f84a9732 100644 --- a/suites-experimental/suites.mjs +++ b/suites-experimental/suites.mjs @@ -344,16 +344,15 @@ export const ExperimentalSuites = freezeSuites([ for (let i = 0; i < pages; i++) await scrollTo(timeline.scrollTop - viewportHeight); - // Then cover the whole room in long strides, the way dragging the - // scrollbar does. Every stride lands on rows that have never been - // measured, so the window is replaced outright and the correction - // runs against estimates. + // Then long strides, the way dragging the scrollbar does: every + // stride lands on rows that have only ever been estimated, so the + // window is replaced outright. Stops one stride short of the top, + // so it does not trip the prefetch LoadOlderMessages measures. const strides = 10; - for (let i = strides - 1; i >= 0; i--) + for (let i = strides - 1; i >= 1; i--) await scrollTo(((timeline.scrollHeight - viewportHeight) * i) / (strides - 1)); - // Back to the newest message, which is where a chat client leaves - // you and where the next step expects to start. + // Back to the newest message, where the next step expects to start. await scrollTo(timeline.scrollHeight); }), new BenchmarkTestStep("SwitchRooms", async (page) => { @@ -366,6 +365,20 @@ export const ExperimentalSuites = freezeSuites([ page.layout(); } }), + // Reading past the start of the loaded history inserts a page *above* + // the viewport, the case browsers ship scroll anchoring for. The + // timeline anchors by hand instead, so overflow-anchor is off. Each + // iteration also crosses the page the previous one prepended. + new BenchmarkTestStep("LoadOlderMessages", async (page) => { + const timeline = page.querySelector("#timeline"); + const pages = 5; + for (let i = 0; i < pages; i++) { + timeline.scrollTop = 0; + timeline.dispatchEvent("scroll"); + await yieldTask(); + page.layout(); + } + }), ], }, ]); From 4fa7cb723fab3ad7a8daeb0bb439f12184444061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 28 Jul 2026 19:33:01 +0200 Subject: [PATCH 10/13] Share ChatRoom fixture data instead of building it per message A profile shows a ~14ms nursery collection landing inside a timed step in three of the thirty measured windows, and those three are the slowest iteration of their step. The fixture build is not itself measured, but it pushes ~117MB of permanently-live data through the nursery per iteration, and a minor GC costs what it has to promote. The fixture now shares what it can: bodies come from a pool of 2048 rather than one per message, reaction rows collapse to the nine distinct values they always had, and timestamps and initials stop being rebuilt 60,000 times. The pool is drawn from the same seed space, so the spread of row heights is unchanged. The per-message preview string is gone; nothing rendered it. Building the fixtures drops from 197ms to 31ms and retains 14MB instead of 117MB, taking the unmeasured prepare phase from 335ms to 48ms per iteration. --- .../chat-room/src/data/rooms.js | 96 ++++++++++++------- 1 file changed, 64 insertions(+), 32 deletions(-) diff --git a/suites-experimental/chat-room/src/data/rooms.js b/suites-experimental/chat-room/src/data/rooms.js index 910b06851..ffeda2d6b 100644 --- a/suites-experimental/chat-room/src/data/rooms.js +++ b/suites-experimental/chat-room/src/data/rooms.js @@ -368,9 +368,18 @@ function buildBlocks(seed) { return blocks; } -// Build a deterministic reactions row. Reaction pills are all over a busy chat, -// so roughly two messages in three have at least one and popular ones collect a -// whole row of them. +// Bodies are shared rather than generated one per message: a body is immutable and +// only read during render, so two messages can point at the same one. Generating +// 60,000 instead dominated this module's load time. Pool size trades load time +// against how often two rows on screen show the same body. +const BODY_POOL_SIZE = 2048; + +const BODY_POOL = []; +for (let i = 0; i < BODY_POOL_SIZE; i++) + BODY_POOL.push(buildBlocks(i)); + +// Reaction pills are all over a busy chat, so roughly two messages in three have +// at least one and popular ones collect a whole row. function buildReactions(seed) { if (seed % 3 === 2) return []; @@ -385,6 +394,15 @@ function buildReactions(seed) { return reactions; } +// Every term above reduces modulo 3, 4 or 12, and REACTION_EMOJIS has twelve +// entries, so a row repeats every twelve seeds and nine distinct rows cover the +// whole corpus. Anyone changing REACTION_EMOJIS has to revisit this cycle. +const REACTION_CYCLE = 12; + +const REACTION_POOL = []; +for (let i = 0; i < REACTION_CYCLE; i++) + REACTION_POOL.push(buildReactions(i)); + // Format a deterministic HH:MM timestamp without touching the real clock. function formatTime(minutesInDay) { const hours = Math.floor(minutesInDay / 60); @@ -393,9 +411,13 @@ function formatTime(minutesInDay) { return `${pad(hours)}:${pad(minutes)}`; } -function buildTime(seed) { - return formatTime(seed % (24 * 60)); -} +// Every timestamp is one of the minutes in a day, so the 1440 strings are built +// once and shared rather than formatted per message. +const MINUTES_IN_DAY = 24 * 60; + +const TIME_STRINGS = []; +for (let minutes = 0; minutes < MINUTES_IN_DAY; minutes++) + TIME_STRINGS.push(formatTime(minutes)); function spansToText(spans) { let text = ""; @@ -432,9 +454,24 @@ function excerpt(text, limit) { return text.length <= limit ? text : `${text.slice(0, limit).trimEnd()}…`; } +const REPLY_EXCERPT_LIMIT = 80; + +// Bodies are shared, so the flattened form is cached against the body rather than +// recomputed and stored for every message that might be quoted. +const BODY_EXCERPTS = new Map(); + +function bodyExcerpt(blocks) { + let text = BODY_EXCERPTS.get(blocks); + if (text === undefined) { + text = excerpt(blocksToText(blocks), REPLY_EXCERPT_LIMIT); + BODY_EXCERPTS.set(blocks, text); + } + return text; +} + // Real conversations arrive in bursts from the same person, which is what makes -// message grouping worth rendering. Emit runs of one to three messages per -// sender, always advancing to a different sender between runs. +// message grouping worth rendering. Runs of one to three, always advancing to a +// different sender between runs. function buildSenderSequence(roomIndex, count) { const senders = []; let index = hash(roomIndex, 301) % SENDERS.length; @@ -452,39 +489,38 @@ function buildSenderSequence(roomIndex, count) { const SENDER_COLOR_INDEX = new Map(SENDERS.map((name, index) => [name, index % AVATAR_COLOR_COUNT])); +// Ten senders, so the initials are derived once rather than per message. +const SENDER_INITIALS = new Map(SENDERS.map((name) => [name, initials(name)])); + function buildMessages(roomIndex) { const senders = buildSenderSequence(roomIndex, MESSAGES_PER_ROOM); const messages = []; for (let i = 0; i < MESSAGES_PER_ROOM; i++) { const seed = roomIndex * MESSAGES_PER_ROOM + i; const sender = senders[i]; - const blocks = buildBlocks(seed); - - // Inline reply quotes embed a parent message in the child, and always - // break the sender group above them. - // - // Most answer something just said, but one in four pulls a message back - // out of the history. Those are the interesting ones for a windowed - // timeline: the quoted message is nowhere in the DOM, so clicking the - // quote has to scroll to a row whose height has never been measured. + const blocks = BODY_POOL[hash(seed, 105) % BODY_POOL_SIZE]; + + // A reply quote embeds its parent in the child and breaks the sender group. + // Most answer something just said, but one in four reaches back into the + // history, where the quoted row is nowhere in the DOM and clicking the quote + // has to scroll to a height that has never been measured. let replyTo = null; if (i > 0 && hash(seed, 201) % 100 < 18) { const distance = hash(seed, 203) % 4 === 0 ? 1 + (hash(seed, 204) % Math.min(i, 400)) : 1 + (hash(seed, 202) % 6); const parent = messages[Math.max(0, i - distance)]; - replyTo = { id: parent.id, sender: parent.sender, excerpt: excerpt(parent.preview, 80) }; + replyTo = { id: parent.id, sender: parent.sender, excerpt: bodyExcerpt(parent.blocks) }; } messages.push({ id: `room-${roomIndex}-msg-${i}`, sender, - senderInitials: initials(sender), + senderInitials: SENDER_INITIALS.get(sender), colorIndex: SENDER_COLOR_INDEX.get(sender), - time: buildTime(seed), + time: TIME_STRINGS[seed % MINUTES_IN_DAY], blocks, - preview: blocksToText(blocks), replyTo, grouped: i > 0 && senders[i - 1] === sender && !replyTo, - reactions: buildReactions(seed), + reactions: REACTION_POOL[seed % REACTION_CYCLE], }); } return messages; @@ -501,7 +537,7 @@ function buildRooms() { colorIndex: i % AVATAR_COLOR_COUNT, initials: initials(name), topic: `Discussion about ${name.toLowerCase()}`, - lastMessage: messages[messages.length - 1].preview, + lastMessage: blocksToText(messages[messages.length - 1].blocks), messages, }); } @@ -518,23 +554,19 @@ export const LOCAL_USER = { colorIndex: SENDERS.length % AVATAR_COLOR_COUNT, }; -// Build a message the local user just sent, in the same shape as the generated -// fixtures so the timeline renders it through the same path. -// -// The timestamp continues from the room's last message instead of reading the -// clock, keeping the workload deterministic. Runs of outgoing messages group -// under the first one, the way a burst from one sender does anywhere else. +// Same shape as the generated fixtures, so the timeline renders it through the same +// path. The timestamp continues from the room's last message instead of reading the +// clock, keeping the workload deterministic. export function createOutgoingMessage(room, sequence, text) { const previous = room.messages[room.messages.length - 1].time.split(":").map(Number); - const sentAt = (previous[0] * 60 + previous[1] + 1 + sequence) % (24 * 60); + const sentAt = (previous[0] * 60 + previous[1] + 1 + sequence) % MINUTES_IN_DAY; return { id: `${room.id}-sent-${sequence}`, sender: LOCAL_USER.name, senderInitials: LOCAL_USER.initials, colorIndex: LOCAL_USER.colorIndex, - time: formatTime(sentAt), + time: TIME_STRINGS[sentAt], blocks: [{ type: "p", spans: [{ type: "text", text }] }], - preview: text, replyTo: null, grouped: sequence > 0, reactions: [], From 6d33daf409fe5b8ce8a50d37ba9a108ce6410dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 28 Jul 2026 19:36:12 +0200 Subject: [PATCH 11/13] Build the ChatRoom message index on demand Turning a message id back into a row index is only needed when a reply quote is clicked, and neither a scroll nor a room switch clicks one. Building it during render rebuilt a map over the room's whole history on every switch, inside the timed step, where the profile puts it at 8.8% of SwitchRooms -- the largest single piece of the app's own JavaScript in the run. With the fixture sharing beneath it, this takes the content process from 1.04GB of net allocation to 459MB, minor collections from 77 to 16, and the ones inside a timed step from 14.1ms to 7.2ms on average. What is left is React's own reconciliation filling the nursery, which is the work the steps exist to measure. --- .../chat-room/src/components/timeline.jsx | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/suites-experimental/chat-room/src/components/timeline.jsx b/suites-experimental/chat-room/src/components/timeline.jsx index 94588d4cf..761fb49c5 100644 --- a/suites-experimental/chat-room/src/components/timeline.jsx +++ b/suites-experimental/chat-room/src/components/timeline.jsx @@ -49,11 +49,20 @@ export default function Timeline({ room, onSelectRoom }) { heights.grow(messages.length); heights.extendTo(firstLoaded); - const indexById = useMemo(() => new Map(messages.map((message, index) => [message.id, index])), [messages]); - - // The mounted range, end exclusive. Starts empty because the total height is - // still all estimates at that point: the mount effect below pins the scroller - // to the bottom first, and the window follows from that offset. + // Only a reply-quote click turns an id back into a row, so the index is built + // on first use. Building it during render meant rebuilding a map over the + // room's whole history inside every room switch. + const indexById = useMemo(() => { + let byId = null; + return (id) => { + if (byId === null) + byId = new Map(messages.map((message, index) => [message.id, index])); + return byId.get(id); + }; + }, [messages]); + + // The mounted range, end exclusive. Starts empty because the mount effect below + // pins the scroller to the bottom first, and the window follows from there. const [range, setRange] = useState({ start: 0, end: 0 }); // True while the timeline is following the conversation, the way a chat client @@ -168,18 +177,13 @@ export default function Timeline({ room, onSelectRoom }) { updateRange(rangeFor(scroller.scrollTop, viewportHeight)); }); - // Clicking a reply quote jumps to the message it quotes and leaves it - // highlighted. The offset comes from the height model rather than the DOM, - // because the quoted message is usually not mounted: scrolling to an - // arbitrary row is the case a virtualizer has to answer without measuring. - // No smooth behavior and no scrollIntoView, so a timed step stays - // deterministic. The highlight holds until the next jump rather than - // clearing on a timer, for the same reason, and only changes background - // colour, so committing it asynchronously cannot move the offset computed - // here. + // Jump to the quoted message and leave it highlighted. The offset comes from the + // height model, because the quoted row is usually not mounted. No smooth + // behavior, no scrollIntoView, and the highlight holds until the next jump + // rather than clearing on a timer, so a timed step stays deterministic. const jumpToMessage = useCallback( (messageId) => { - const index = indexById.get(messageId); + const index = indexById(messageId); if (index === undefined) return; const scroller = scrollerRef.current; From ebcf263005eba3fb0e78be083bcb8b15a6915443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 11 Aug 2026 15:24:26 +0200 Subject: [PATCH 12/13] Draw date separators and an unread divider in the ChatRoom timeline Per-render chrome that chat clients carry and this workload had none of: a labelled rule where the conversation crosses a day, and a marker above the first message the reader has not seen. Neither is a row of its own -- a row here is one message, and the height cache, spacers and offset search are all indexed by message index -- so both are drawn inside the row they belong to, keyed off the message array rather than the mounted window. Day lengths now vary between 8 and 56 messages. At a fixed size the boundary always landed just above the newest page, so no room opened with a separator in view; twenty of the forty now do. Cost is noise: 100.65ms -> 105.00ms over ten Firefox iterations against a +/-20ms spread. --- .../chat-room/src/components/message.jsx | 74 +++++++++++-------- .../chat-room/src/components/timeline.jsx | 16 ++-- .../chat-room/src/data/rooms.js | 67 +++++++++++++++-- suites-experimental/chat-room/src/styles.css | 55 +++++++++++++- 4 files changed, 170 insertions(+), 42 deletions(-) diff --git a/suites-experimental/chat-room/src/components/message.jsx b/suites-experimental/chat-room/src/components/message.jsx index 7a38c6e29..06fdf3b60 100644 --- a/suites-experimental/chat-room/src/components/message.jsx +++ b/suites-experimental/chat-room/src/components/message.jsx @@ -3,12 +3,16 @@ import { AVATAR_COLORS } from "../data/rooms.js"; import Reaction from "./reaction.jsx"; import RichText from "./rich-text.jsx"; -// Consecutive messages from the same sender collapse into the previous one, the -// way a chat client renders a burst of them: no repeated avatar or name, just -// the body under a gutter that holds the timestamp on hover. +// Consecutive messages from the same sender collapse into the one above, the way +// a chat client renders a burst: no repeated avatar or name, and the gutter +// carries the timestamp on hover. // The index is the row's position in the whole room, not in the mounted window, // so the timeline can file the measured height against the right message. -export default function Message({ index, message, highlighted }) { +// +// The date separator and the unread divider are drawn inside the row they belong +// to rather than as rows of their own, because the height cache, the spacers and +// the offset search are all indexed by message. +export default function Message({ index, message, highlighted, dateLabel, unreadBelow }) { const { jumpToMessage } = useActions(); const classNames = ["timeline-message"]; if (message.grouped) @@ -18,35 +22,47 @@ export default function Message({ index, message, highlighted }) { return (
          1. - {message.grouped - ? {message.time} - : - {message.senderInitials} - + {dateLabel !== null + &&
            + {dateLabel} +
            + } + {unreadBelow + &&
            + New +
            } -
            - {message.replyTo - && +
            + {message.grouped + ? {message.time} + : + {message.senderInitials} + } - {!message.grouped - &&
            - {message.sender} - {message.time} +
            + {message.replyTo + && + } + {!message.grouped + &&
            + {message.sender} + {message.time} +
            + } +
            +
            - } -
            - + {message.reactions.length > 0 + &&
            + {message.reactions.map((reaction) => + + )} +
            + }
            - {message.reactions.length > 0 - &&
            - {message.reactions.map((reaction) => - - )} -
            - }
          2. ); diff --git a/suites-experimental/chat-room/src/components/timeline.jsx b/suites-experimental/chat-room/src/components/timeline.jsx index 761fb49c5..8c646ac7e 100644 --- a/suites-experimental/chat-room/src/components/timeline.jsx +++ b/suites-experimental/chat-room/src/components/timeline.jsx @@ -1,6 +1,6 @@ import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; import { ActionsContext } from "../actions.js"; -import { createOutgoingMessage } from "../data/rooms.js"; +import { createOutgoingMessage, dateLabelFor } from "../data/rooms.js"; import { RowHeights } from "../row-heights.js"; import Composer from "./composer.jsx"; import Message from "./message.jsx"; @@ -216,14 +216,18 @@ export default function Timeline({ room, onSelectRoom }) { [room] ); - // Grouping is taken from the fixture rather than from the window, so a row - // renders the same whether or not the message above it happens to be mounted. - // Deriving it from the window would change a row's height as the window - // moved, which would invalidate the very cache being built here. + // Grouping and the date separator come from the message array rather than from + // the window: a row that changed height as the window moved would invalidate + // the very height cache being built here. + const lastDayIndex = messages[messages.length - 1].dayIndex; const rows = []; for (let index = range.start; index < range.end; index++) { const message = messages[index]; - rows.push(); + // messages[index - 1] is always there: the fixture holds the whole room + // even when only the newest page is in the timeline. + const previous = index > 0 ? messages[index - 1] : null; + const startsDay = previous === null || previous.dayIndex !== message.dayIndex; + rows.push(); } return ( diff --git a/suites-experimental/chat-room/src/data/rooms.js b/suites-experimental/chat-room/src/data/rooms.js index ffeda2d6b..b7dd89d4f 100644 --- a/suites-experimental/chat-room/src/data/rooms.js +++ b/suites-experimental/chat-room/src/data/rooms.js @@ -9,12 +9,16 @@ import { generatedImage } from "./graphics.js"; const ROOM_COUNT = 40; -// Real channels hold years of history, which is only feasible to render with a -// windowed timeline. Generation is eager at module load, so this number is a -// tradeoff against load time rather than against the measured steps: see the -// figure recorded in debugging/chat-room-realism-plan.md. +// Real channels hold years of history. Generation is eager at module load, so this +// trades against load time rather than against the measured steps. const MESSAGES_PER_ROOM = 1500; +// How many messages land on one day, as a range because a real channel does not turn +// over the same number every day. The run lengths set how often a row carries a date +// separator, and how short the newest day is decides whether a room opens on one. +const MIN_MESSAGES_PER_DAY = 8; +const MAX_MESSAGES_PER_DAY = 56; + const ROOM_NAMES = [ "General", "Random", @@ -419,6 +423,27 @@ const TIME_STRINGS = []; for (let minutes = 0; minutes < MINUTES_IN_DAY; minutes++) TIME_STRINGS.push(formatTime(minutes)); +const WEEKDAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; + +const MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + +// A synthetic calendar rather than the real one, so the workload stays +// deterministic. Sized for the shortest day a room can have, so no two days in one +// room ever share a label. +const DATE_LABELS = []; +for (let day = 0; day < Math.ceil(MESSAGES_PER_ROOM / MIN_MESSAGES_PER_DAY) + 1; day++) + DATE_LABELS.push(`${WEEKDAYS[day % WEEKDAYS.length]}, ${1 + (day % 28)} ${MONTHS[Math.floor(day / 28) % MONTHS.length]}`); + +// Real clients name the last two days rather than dating them, which is a branch +// per separator and a different string length where a room opens. +export function dateLabelFor(dayIndex, lastDayIndex) { + if (dayIndex === lastDayIndex) + return "Today"; + if (dayIndex === lastDayIndex - 1) + return "Yesterday"; + return DATE_LABELS[dayIndex % DATE_LABELS.length]; +} + function spansToText(spans) { let text = ""; for (const span of spans) { @@ -492,8 +517,25 @@ const SENDER_COLOR_INDEX = new Map(SENDERS.map((name, index) => [name, index % A // Ten senders, so the initials are derived once rather than per message. const SENDER_INITIALS = new Map(SENDERS.map((name) => [name, initials(name)])); +// Which day each message falls on, as runs of varying length. Same construction as +// the sender sequence, and precomputed so a row's day never depends on what is +// mounted. +function buildDaySequence(roomIndex, count) { + const days = []; + let day = 0; + while (days.length < count) { + const span = MAX_MESSAGES_PER_DAY - MIN_MESSAGES_PER_DAY + 1; + const length = MIN_MESSAGES_PER_DAY + (hash(roomIndex * count + day, 901) % span); + for (let i = 0; i < length && days.length < count; i++) + days.push(day); + day++; + } + return days; +} + function buildMessages(roomIndex) { const senders = buildSenderSequence(roomIndex, MESSAGES_PER_ROOM); + const days = buildDaySequence(roomIndex, MESSAGES_PER_ROOM); const messages = []; for (let i = 0; i < MESSAGES_PER_ROOM; i++) { const seed = roomIndex * MESSAGES_PER_ROOM + i; @@ -517,6 +559,9 @@ function buildMessages(roomIndex) { senderInitials: SENDER_INITIALS.get(sender), colorIndex: SENDER_COLOR_INDEX.get(sender), time: TIME_STRINGS[seed % MINUTES_IN_DAY], + // The timeline compares this against the row above to decide whether to + // draw a date separator. + dayIndex: days[i], blocks, replyTo, grouped: i > 0 && senders[i - 1] === sender && !replyTo, @@ -526,6 +571,11 @@ function buildMessages(roomIndex) { return messages; } +// How far back the unread divider sits when the room opens. At least one message +// back, so it is always a row that exists, and never further than a viewport, so +// every room switch lays one out -- which is also the common case in a real client. +const UNREAD_DEPTH = 12; + function buildRooms() { const rooms = []; for (let i = 0; i < ROOM_COUNT; i++) { @@ -538,6 +588,9 @@ function buildRooms() { initials: initials(name), topic: `Discussion about ${name.toLowerCase()}`, lastMessage: blocksToText(messages[messages.length - 1].blocks), + // The last message this user has read. The row after it carries the + // unread divider. + readUpToIndex: Math.max(0, messages.length - 1 - (1 + (hash(i, 701) % (UNREAD_DEPTH - 1)))), messages, }); } @@ -558,7 +611,8 @@ export const LOCAL_USER = { // path. The timestamp continues from the room's last message instead of reading the // clock, keeping the workload deterministic. export function createOutgoingMessage(room, sequence, text) { - const previous = room.messages[room.messages.length - 1].time.split(":").map(Number); + const newest = room.messages[room.messages.length - 1]; + const previous = newest.time.split(":").map(Number); const sentAt = (previous[0] * 60 + previous[1] + 1 + sequence) % MINUTES_IN_DAY; return { id: `${room.id}-sent-${sequence}`, @@ -566,6 +620,9 @@ export function createOutgoingMessage(room, sequence, text) { senderInitials: LOCAL_USER.initials, colorIndex: LOCAL_USER.colorIndex, time: TIME_STRINGS[sentAt], + // Same day as the message it follows, so sending does not put a date + // separator in the middle of the burst. + dayIndex: newest.dayIndex, blocks: [{ type: "p", spans: [{ type: "text", text }] }], replyTo: null, grouped: sequence > 0, diff --git a/suites-experimental/chat-room/src/styles.css b/suites-experimental/chat-room/src/styles.css index 8183fce40..590d7ba3c 100644 --- a/suites-experimental/chat-room/src/styles.css +++ b/suites-experimental/chat-room/src/styles.css @@ -177,14 +177,18 @@ body { overflow-anchor: none; } +/* A row is a column: the separators stack above the message's own flex row. */ .timeline-message { + padding: 6px 0; +} + +.timeline-message-row { display: flex; gap: 12px; - padding: 6px 0; } /* Grouped messages drop the avatar and name; the gutter keeps the body aligned - and carries the timestamp, revealed on hover the way real clients do. */ + and carries the timestamp on hover, the way real clients do. */ .timeline-message-grouped { padding: 1px 0; } @@ -202,6 +206,53 @@ body { opacity: 1; } +/* Date separator: a centred label between two rules, drawn with pseudo-element + borders so it costs a real layout box either side. */ +.timeline-date-separator { + display: flex; + align-items: center; + gap: 8px; + margin: 10px 0 6px; +} + +.timeline-date-separator::before, +.timeline-date-separator::after { + content: ""; + flex: 1 1 auto; + border-top: 1px solid #e3e6ea; +} + +.timeline-date-separator-label { + flex: 0 0 auto; + padding: 2px 10px; + border: 1px solid #e3e6ea; + border-radius: 10px; + background-color: #fff; + color: #6b7280; + font-size: 11px; + font-weight: 600; +} + +/* The unread divider sits above the first message the reader has not seen. */ +.timeline-unread-divider { + display: flex; + align-items: center; + gap: 8px; + margin: 8px 0 4px; + border-top: 1px solid #e2564a; +} + +.timeline-unread-divider-label { + margin-left: auto; + padding: 1px 8px; + border-radius: 0 0 8px 8px; + background-color: #e2564a; + color: #fff; + font-size: 10px; + font-weight: 700; + text-transform: uppercase; +} + .timeline-message-body { min-width: 0; flex: 1 1 auto; From a9fd215f07ff3785e91ebaf3de6f8a5ba7386a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 11 Aug 2026 15:34:04 +0200 Subject: [PATCH 13/13] Build the ChatRoom workload Output of `npm run build` in suites-experimental/chat-room. Build artifacts only, so it can be dropped and regenerated whenever the source commits below it change. --- .../chat-room/dist/assets/index-158fa97f.css | 1 + .../chat-room/dist/assets/index-381effb6.js | 51 +++++++++++++++++++ .../dist/assets/index-381effb6.js.map | 1 + suites-experimental/chat-room/dist/index.html | 23 +++++++++ .../chat-room/dist/resources.txt | 4 ++ 5 files changed, 80 insertions(+) create mode 100644 suites-experimental/chat-room/dist/assets/index-158fa97f.css create mode 100644 suites-experimental/chat-room/dist/assets/index-381effb6.js create mode 100644 suites-experimental/chat-room/dist/assets/index-381effb6.js.map create mode 100644 suites-experimental/chat-room/dist/index.html create mode 100644 suites-experimental/chat-room/dist/resources.txt diff --git a/suites-experimental/chat-room/dist/assets/index-158fa97f.css b/suites-experimental/chat-room/dist/assets/index-158fa97f.css new file mode 100644 index 000000000..138f1781e --- /dev/null +++ b/suites-experimental/chat-room/dist/assets/index-158fa97f.css @@ -0,0 +1 @@ +*{box-sizing:border-box}html,body{margin:0;height:100%}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;color:#17191c;background-color:#f4f6fa}#root{height:100vh}.app{display:grid;grid-template-columns:300px 1fr;height:100vh;overflow:hidden}.avatar{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:36px;height:36px;border-radius:50%;color:#fff;font-size:13px;font-weight:600;text-transform:uppercase}.room-list{display:flex;flex-direction:column;overflow-y:auto;border-right:1px solid #e3e8ef;background-color:#fff}.room-list-item{display:flex;align-items:center;gap:12px;padding:10px 14px;border:0;border-bottom:1px solid #f0f2f5;background:transparent;text-align:left;cursor:pointer;font:inherit;color:inherit}.room-list-item:hover{background-color:#f4f6fa}.room-list-item-selected{background-color:#e8f0fe}.room-list-item-text{display:flex;flex-direction:column;min-width:0}.room-list-item-name{font-weight:600;font-size:15px}.room-list-item-preview{font-size:13px;color:#737d8c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.room{display:flex;flex-direction:column;min-width:0;height:100vh}.room-header{padding:14px 20px;border-bottom:1px solid #e3e8ef;background-color:#fff}.room-header-name{margin:0;font-size:18px}.room-header-topic{margin:4px 0 0;font-size:13px;color:#737d8c}.composer{display:flex;flex:0 0 auto;gap:8px;padding:12px 20px;border-top:1px solid #e3e8ef;background-color:#fff}.composer-input{flex:1 1 auto;min-width:0;padding:8px 12px;border:1px solid #d5dbe5;border-radius:8px;font:inherit;font-size:14px;color:inherit}.composer-input:focus{border-color:#9dc0f5;outline:2px solid #dce8fb;outline-offset:-1px}.composer-send{flex:0 0 auto;padding:8px 16px;border:0;border-radius:8px;background-color:#2a6fd6;font:inherit;font-size:14px;font-weight:600;color:#fff;cursor:pointer}.composer-send:hover:enabled{background-color:#245fb8}.composer-send:disabled{background-color:#c8d1de;cursor:default}.timeline{flex:1 1 auto;margin:0;padding:0 20px;list-style:none;overflow-y:auto;overflow-anchor:none}.timeline-message{padding:6px 0}.timeline-message-row{display:flex;gap:12px}.timeline-message-grouped{padding:1px 0}.timeline-message-gutter{flex:0 0 auto;width:36px;font-size:11px;color:#939aa5;text-align:right;opacity:0}.timeline-message-grouped:hover .timeline-message-gutter{opacity:1}.timeline-date-separator{display:flex;align-items:center;gap:8px;margin:10px 0 6px}.timeline-date-separator:before,.timeline-date-separator:after{content:"";flex:1 1 auto;border-top:1px solid #e3e6ea}.timeline-date-separator-label{flex:0 0 auto;padding:2px 10px;border:1px solid #e3e6ea;border-radius:10px;background-color:#fff;color:#6b7280;font-size:11px;font-weight:600}.timeline-unread-divider{display:flex;align-items:center;gap:8px;margin:8px 0 4px;border-top:1px solid #e2564a}.timeline-unread-divider-label{margin-left:auto;padding:1px 8px;border-radius:0 0 8px 8px;background-color:#e2564a;color:#fff;font-size:10px;font-weight:700;text-transform:uppercase}.timeline-message-body{min-width:0;flex:1 1 auto}.timeline-message-highlighted{background-color:#fff6d8}.timeline-message-reply{display:flex;gap:6px;align-items:baseline;width:100%;margin-bottom:2px;padding:0 0 0 8px;border:0;border-left:2px solid #d5dbe5;background:transparent;font:inherit;font-size:12px;color:#737d8c;text-align:left;cursor:pointer}.timeline-message-reply:hover{border-left-color:#9dc0f5;color:#5a6472}.timeline-message-reply-sender{flex:0 0 auto;font-weight:600;color:#5a6472}.timeline-message-reply-excerpt{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.timeline-message-meta{display:flex;align-items:baseline;gap:8px}.timeline-message-sender{font-weight:600;font-size:14px}.timeline-message-time{font-size:12px;color:#939aa5}.timeline-message-text{margin-top:2px;font-size:14px;line-height:1.4;color:#2c3038}.rich-paragraph{margin:0 0 4px}.rich-paragraph:last-child{margin-bottom:0}.rich-code{padding:1px 4px;border:1px solid #e3e8ef;border-radius:4px;background-color:#f4f6fa;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.9em;color:#b4295c}.rich-code-block{margin:4px 0;padding:8px 10px;overflow-x:auto;border:1px solid #e3e8ef;border-radius:6px;background-color:#f8fafc;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;line-height:1.45;white-space:pre}.rich-image{display:block;max-width:100%;height:auto;margin:6px 0;border:1px solid #e3e8ef;border-radius:8px}.rich-unfurl{display:flex;gap:10px;max-width:460px;margin:6px 0;padding:10px;border:1px solid #e3e8ef;border-left:3px solid #9dc0f5;border-radius:8px;background-color:#fbfcfe;color:inherit;text-decoration:none}.rich-unfurl:hover{background-color:#f4f8ff}.rich-unfurl-thumb{flex:0 0 auto;border-radius:6px}.rich-unfurl-body{display:flex;flex-direction:column;gap:2px;min-width:0}.rich-unfurl-site{font-size:11px;font-weight:600;color:#737d8c;text-transform:uppercase;letter-spacing:.02em}.rich-unfurl-title{font-weight:600;color:#24509b}.rich-unfurl-description{font-size:13px;color:#5a6472}.rich-quote{margin:4px 0;padding:2px 0 2px 10px;border-left:3px solid #c8d1de;color:#5a6472}.rich-list{margin:4px 0;padding-left:20px}.rich-link{color:#2a6fd6;text-decoration:underline}.rich-pill{padding:0 5px;border:0;border-radius:10px;font:inherit;font-weight:500;white-space:nowrap}.rich-pill-mention{background-color:#e2ecfd;color:#24509b}.rich-pill-room{background-color:#e6f6ee;color:#1c6e4c;cursor:pointer}.rich-pill-room:hover{background-color:#d3efe1}.timeline-message-reactions{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}.reaction{display:inline-flex;align-items:center;gap:4px;padding:1px 8px;border:1px solid #e3e8ef;border-radius:12px;background-color:#f4f6fa;font:inherit;font-size:12px;color:inherit;cursor:pointer}.reaction:hover{border-color:#c8d1de;background-color:#eaeef5}.reaction-mine{border-color:#9dc0f5;background-color:#e2ecfd}.reaction-mine .reaction-count{color:#24509b;font-weight:600}.reaction-count{color:#737d8c} diff --git a/suites-experimental/chat-room/dist/assets/index-381effb6.js b/suites-experimental/chat-room/dist/assets/index-381effb6.js new file mode 100644 index 000000000..3fa91cf9a --- /dev/null +++ b/suites-experimental/chat-room/dist/assets/index-381effb6.js @@ -0,0 +1,51 @@ +var ei=(l,t,a)=>{if(!t.has(l))throw TypeError("Cannot "+a)};var L=(l,t,a)=>(ei(l,t,"read from private field"),a?a.call(l):t.get(l)),Yt=(l,t,a)=>{if(t.has(l))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(l):t.set(l,a)},zl=(l,t,a,u)=>(ei(l,t,"write to private field"),u?u.call(l,a):t.set(l,a),a);var Me=(l,t,a)=>(ei(l,t,"access private method"),a);var Y0={exports:{}},qn={};/** + * @license React + * react-jsx-runtime.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var lm=Symbol.for("react.transitional.element"),tm=Symbol.for("react.fragment");function q0(l,t,a){var u=null;if(a!==void 0&&(u=""+a),t.key!==void 0&&(u=""+t.key),"key"in t){a={};for(var e in t)e!=="key"&&(a[e]=t[e])}else a=t;return t=a.ref,{$$typeof:lm,type:l,key:u,ref:t!==void 0?t:null,props:a}}qn.Fragment=tm;qn.jsx=q0;qn.jsxs=q0;Y0.exports=qn;var E=Y0.exports,G0={exports:{}},Gn={},X0={exports:{}},Q0={};/** + * @license React + * scheduler.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */(function(l){function t(b,D){var U=b.length;b.push(D);l:for(;0>>1,vl=b[il];if(0>>1;ile(ui,U))mae(_e,ui)?(b[il]=_e,b[ma]=U,il=ma):(b[il]=ui,b[ze]=U,il=ze);else if(mae(_e,U))b[il]=_e,b[ma]=U,il=ma;else break l}}return D}function e(b,D){var U=b.sortIndex-D.sortIndex;return U!==0?U:b.id-D.id}if(l.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var n=performance;l.unstable_now=function(){return n.now()}}else{var i=Date,c=i.now();l.unstable_now=function(){return i.now()-c}}var f=[],h=[],g=1,y=null,m=3,v=!1,p=!1,z=!1,j=!1,o=typeof setTimeout=="function"?setTimeout:null,s=typeof clearTimeout=="function"?clearTimeout:null,d=typeof setImmediate<"u"?setImmediate:null;function r(b){for(var D=a(h);D!==null;){if(D.callback===null)u(h);else if(D.startTime<=b)u(h),D.sortIndex=D.expirationTime,t(f,D);else break;D=a(h)}}function A(b){if(z=!1,r(b),!p)if(a(f)!==null)p=!0,N||(N=!0,et());else{var D=a(h);D!==null&&ul(A,D.startTime-b)}}var N=!1,T=-1,O=5,C=-1;function x(){return j?!0:!(l.unstable_now()-Cb&&x());){var il=y.callback;if(typeof il=="function"){y.callback=null,m=y.priorityLevel;var vl=il(y.expirationTime<=b);if(b=l.unstable_now(),typeof vl=="function"){y.callback=vl,r(b),D=!0;break t}y===a(f)&&u(f),r(b)}else u(f);y=a(f)}if(y!==null)D=!0;else{var Ae=a(h);Ae!==null&&ul(A,Ae.startTime-b),D=!1}}break l}finally{y=null,m=U,v=!1}D=void 0}}finally{D?et():N=!1}}}var et;if(typeof d=="function")et=function(){d(Dl)};else if(typeof MessageChannel<"u"){var _=new MessageChannel,X=_.port2;_.port1.onmessage=Dl,et=function(){X.postMessage(null)}}else et=function(){o(Dl,0)};function ul(b,D){T=o(function(){b(l.unstable_now())},D)}l.unstable_IdlePriority=5,l.unstable_ImmediatePriority=1,l.unstable_LowPriority=4,l.unstable_NormalPriority=3,l.unstable_Profiling=null,l.unstable_UserBlockingPriority=2,l.unstable_cancelCallback=function(b){b.callback=null},l.unstable_forceFrameRate=function(b){0>b||125il?(b.sortIndex=U,t(h,b),a(f)===null&&b===a(h)&&(z?(s(T),T=-1):z=!0,ul(A,U-il))):(b.sortIndex=vl,t(f,b),p||v||(p=!0,N||(N=!0,et()))),b},l.unstable_shouldYield=x,l.unstable_wrapCallback=function(b){var D=m;return function(){var U=m;m=D;try{return b.apply(this,arguments)}finally{m=U}}}})(Q0);X0.exports=Q0;var am=X0.exports,Z0={exports:{}},H={};/** + * @license React + * react.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var wc=Symbol.for("react.transitional.element"),um=Symbol.for("react.portal"),em=Symbol.for("react.fragment"),nm=Symbol.for("react.strict_mode"),im=Symbol.for("react.profiler"),cm=Symbol.for("react.consumer"),fm=Symbol.for("react.context"),sm=Symbol.for("react.forward_ref"),om=Symbol.for("react.suspense"),hm=Symbol.for("react.memo"),L0=Symbol.for("react.lazy"),mm=Symbol.for("react.activity"),ls=Symbol.iterator;function dm(l){return l===null||typeof l!="object"?null:(l=ls&&l[ls]||l["@@iterator"],typeof l=="function"?l:null)}var V0={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},K0=Object.assign,J0={};function vu(l,t,a){this.props=l,this.context=t,this.refs=J0,this.updater=a||V0}vu.prototype.isReactComponent={};vu.prototype.setState=function(l,t){if(typeof l!="object"&&typeof l!="function"&&l!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,l,t,"setState")};vu.prototype.forceUpdate=function(l){this.updater.enqueueForceUpdate(this,l,"forceUpdate")};function w0(){}w0.prototype=vu.prototype;function $c(l,t,a){this.props=l,this.context=t,this.refs=J0,this.updater=a||V0}var Wc=$c.prototype=new w0;Wc.constructor=$c;K0(Wc,vu.prototype);Wc.isPureReactComponent=!0;var ts=Array.isArray;function Wi(){}var ll={H:null,A:null,T:null,S:null},$0=Object.prototype.hasOwnProperty;function Fc(l,t,a){var u=a.ref;return{$$typeof:wc,type:l,key:t,ref:u!==void 0?u:null,props:a}}function ym(l,t){return Fc(l.type,t,l.props)}function kc(l){return typeof l=="object"&&l!==null&&l.$$typeof===wc}function vm(l){var t={"=":"=0",":":"=2"};return"$"+l.replace(/[=:]/g,function(a){return t[a]})}var as=/\/+/g;function ni(l,t){return typeof l=="object"&&l!==null&&l.key!=null?vm(""+l.key):t.toString(36)}function gm(l){switch(l.status){case"fulfilled":return l.value;case"rejected":throw l.reason;default:switch(typeof l.status=="string"?l.then(Wi,Wi):(l.status="pending",l.then(function(t){l.status==="pending"&&(l.status="fulfilled",l.value=t)},function(t){l.status==="pending"&&(l.status="rejected",l.reason=t)})),l.status){case"fulfilled":return l.value;case"rejected":throw l.reason}}throw l}function xa(l,t,a,u,e){var n=typeof l;(n==="undefined"||n==="boolean")&&(l=null);var i=!1;if(l===null)i=!0;else switch(n){case"bigint":case"string":case"number":i=!0;break;case"object":switch(l.$$typeof){case wc:case um:i=!0;break;case L0:return i=l._init,xa(i(l._payload),t,a,u,e)}}if(i)return e=e(l),i=u===""?"."+ni(l,0):u,ts(e)?(a="",i!=null&&(a=i.replace(as,"$&/")+"/"),xa(e,t,a,"",function(h){return h})):e!=null&&(kc(e)&&(e=ym(e,a+(e.key==null||l&&l.key===e.key?"":(""+e.key).replace(as,"$&/")+"/")+i)),t.push(e)),1;i=0;var c=u===""?".":u+":";if(ts(l))for(var f=0;f"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(k0)}catch(l){console.error(l)}}k0(),W0.exports=Ol;var Em=W0.exports;/** + * @license React + * react-dom-client.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var yl=am,I0=J,Am=Em;function S(l){var t="https://react.dev/errors/"+l;if(1Ga||(l.current=tc[Ga],tc[Ga]=null,Ga--)}function k(l,t){Ga++,tc[Ga]=l.current,l.current=t}var yt=vt(null),Fu=vt(null),kt=vt(null),fn=vt(null);function sn(l,t){switch(k(kt,t),k(Fu,l),k(yt,null),t.nodeType){case 9:case 11:l=(l=t.documentElement)&&(l=l.namespaceURI)?h0(l):0;break;default:if(l=t.tagName,t=t.namespaceURI)t=h0(t),l=_1(t,l);else switch(l){case"svg":l=1;break;case"math":l=2;break;default:l=0}}Sl(yt),k(yt,l)}function eu(){Sl(yt),Sl(Fu),Sl(kt)}function ac(l){l.memoizedState!==null&&k(fn,l);var t=yt.current,a=_1(t,l.type);t!==a&&(k(Fu,l),k(yt,a))}function on(l){Fu.current===l&&(Sl(yt),Sl(Fu)),fn.current===l&&(Sl(fn),ce._currentValue=Sa)}var ii,is;function ya(l){if(ii===void 0)try{throw Error()}catch(a){var t=a.stack.trim().match(/\n( *(at )?)/);ii=t&&t[1]||"",is=-1)":-1e||f[u]!==h[e]){var g=` +`+f[u].replace(" at new "," at ");return l.displayName&&g.includes("")&&(g=g.replace("",l.displayName)),g}while(1<=u&&0<=e);break}}}finally{ci=!1,Error.prepareStackTrace=a}return(a=l?l.displayName||l.name:"")?ya(a):""}function Dm(l,t){switch(l.tag){case 26:case 27:case 5:return ya(l.type);case 16:return ya("Lazy");case 13:return l.child!==t&&t!==null?ya("Suspense Fallback"):ya("Suspense");case 19:return ya("SuspenseList");case 0:case 15:return fi(l.type,!1);case 11:return fi(l.type.render,!1);case 1:return fi(l.type,!0);case 31:return ya("Activity");default:return""}}function cs(l){try{var t="",a=null;do t+=Dm(l,a),a=l,l=l.return;while(l);return t}catch(u){return` +Error generating stack: `+u.message+` +`+u.stack}}var uc=Object.prototype.hasOwnProperty,lf=yl.unstable_scheduleCallback,si=yl.unstable_cancelCallback,Nm=yl.unstable_shouldYield,Um=yl.unstable_requestPaint,Ql=yl.unstable_now,Hm=yl.unstable_getCurrentPriorityLevel,no=yl.unstable_ImmediatePriority,io=yl.unstable_UserBlockingPriority,hn=yl.unstable_NormalPriority,Rm=yl.unstable_LowPriority,co=yl.unstable_IdlePriority,Cm=yl.log,jm=yl.unstable_setDisableYieldValue,me=null,Zl=null;function Kt(l){if(typeof Cm=="function"&&jm(l),Zl&&typeof Zl.setStrictMode=="function")try{Zl.setStrictMode(me,l)}catch{}}var Ll=Math.clz32?Math.clz32:Ym,xm=Math.log,Bm=Math.LN2;function Ym(l){return l>>>=0,l===0?32:31-(xm(l)/Bm|0)|0}var Ne=256,Ue=262144,He=4194304;function va(l){var t=l&42;if(t!==0)return t;switch(l&-l){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return l&261888;case 262144:case 524288:case 1048576:case 2097152:return l&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return l&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return l}}function Qn(l,t,a){var u=l.pendingLanes;if(u===0)return 0;var e=0,n=l.suspendedLanes,i=l.pingedLanes;l=l.warmLanes;var c=u&134217727;return c!==0?(u=c&~n,u!==0?e=va(u):(i&=c,i!==0?e=va(i):a||(a=c&~l,a!==0&&(e=va(a))))):(c=u&~n,c!==0?e=va(c):i!==0?e=va(i):a||(a=u&~l,a!==0&&(e=va(a)))),e===0?0:t!==0&&t!==e&&!(t&n)&&(n=e&-e,a=t&-t,n>=a||n===32&&(a&4194048)!==0)?t:e}function de(l,t){return(l.pendingLanes&~(l.suspendedLanes&~l.pingedLanes)&t)===0}function qm(l,t){switch(l){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function fo(){var l=He;return He<<=1,!(He&62914560)&&(He=4194304),l}function oi(l){for(var t=[],a=0;31>a;a++)t.push(l);return t}function ye(l,t){l.pendingLanes|=t,t!==268435456&&(l.suspendedLanes=0,l.pingedLanes=0,l.warmLanes=0)}function Gm(l,t,a,u,e,n){var i=l.pendingLanes;l.pendingLanes=a,l.suspendedLanes=0,l.pingedLanes=0,l.warmLanes=0,l.expiredLanes&=a,l.entangledLanes&=a,l.errorRecoveryDisabledLanes&=a,l.shellSuspendCounter=0;var c=l.entanglements,f=l.expirationTimes,h=l.hiddenUpdates;for(a=i&~a;0"u")return null;try{return l.activeElement||l.body}catch{return l.body}}var Km=/[\n"\\]/g;function Il(l){return l.replace(Km,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function ic(l,t,a,u,e,n,i,c){l.name="",i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"?l.type=i:l.removeAttribute("type"),t!=null?i==="number"?(t===0&&l.value===""||l.value!=t)&&(l.value=""+Wl(t)):l.value!==""+Wl(t)&&(l.value=""+Wl(t)):i!=="submit"&&i!=="reset"||l.removeAttribute("value"),t!=null?cc(l,i,Wl(t)):a!=null?cc(l,i,Wl(a)):u!=null&&l.removeAttribute("value"),e==null&&n!=null&&(l.defaultChecked=!!n),e!=null&&(l.checked=e&&typeof e!="function"&&typeof e!="symbol"),c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?l.name=""+Wl(c):l.removeAttribute("name")}function So(l,t,a,u,e,n,i,c){if(n!=null&&typeof n!="function"&&typeof n!="symbol"&&typeof n!="boolean"&&(l.type=n),t!=null||a!=null){if(!(n!=="submit"&&n!=="reset"||t!=null)){nc(l);return}a=a!=null?""+Wl(a):"",t=t!=null?""+Wl(t):a,c||t===l.value||(l.value=t),l.defaultValue=t}u=u??e,u=typeof u!="function"&&typeof u!="symbol"&&!!u,l.checked=c?l.checked:!!u,l.defaultChecked=!!u,i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(l.name=i),nc(l)}function cc(l,t,a){t==="number"&&mn(l.ownerDocument)===l||l.defaultValue===""+a||(l.defaultValue=""+a)}function ka(l,t,a,u){if(l=l.options,t){t={};for(var e=0;e"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),sc=!1;if(Ht)try{var zu={};Object.defineProperty(zu,"passive",{get:function(){sc=!0}}),window.addEventListener("test",zu,zu),window.removeEventListener("test",zu,zu)}catch{sc=!1}var Jt=null,cf=null,we=null;function Ao(){if(we)return we;var l,t=cf,a=t.length,u,e="value"in Jt?Jt.value:Jt.textContent,n=e.length;for(l=0;l=Yu),Ss=String.fromCharCode(32),bs=!1;function _o(l,t){switch(l){case"keyup":return bd.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Mo(l){return l=l.detail,typeof l=="object"&&"data"in l?l.data:null}var Za=!1;function Td(l,t){switch(l){case"compositionend":return Mo(t);case"keypress":return t.which!==32?null:(bs=!0,Ss);case"textInput":return l=t.data,l===Ss&&bs?null:l;default:return null}}function Ed(l,t){if(Za)return l==="compositionend"||!sf&&_o(l,t)?(l=Ao(),we=cf=Jt=null,Za=!1,l):null;switch(l){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:a,offset:t-l};l=u}l:{for(;a;){if(a.nextSibling){a=a.nextSibling;break l}a=a.parentNode}a=void 0}a=zs(a)}}function Uo(l,t){return l&&t?l===t?!0:l&&l.nodeType===3?!1:t&&t.nodeType===3?Uo(l,t.parentNode):"contains"in l?l.contains(t):l.compareDocumentPosition?!!(l.compareDocumentPosition(t)&16):!1:!1}function Ho(l){l=l!=null&&l.ownerDocument!=null&&l.ownerDocument.defaultView!=null?l.ownerDocument.defaultView:window;for(var t=mn(l.document);t instanceof l.HTMLIFrameElement;){try{var a=typeof t.contentWindow.location.href=="string"}catch{a=!1}if(a)l=t.contentWindow;else break;t=mn(l.document)}return t}function of(l){var t=l&&l.nodeName&&l.nodeName.toLowerCase();return t&&(t==="input"&&(l.type==="text"||l.type==="search"||l.type==="tel"||l.type==="url"||l.type==="password")||t==="textarea"||l.contentEditable==="true")}var Ud=Ht&&"documentMode"in document&&11>=document.documentMode,La=null,oc=null,Gu=null,hc=!1;function Ms(l,t,a){var u=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;hc||La==null||La!==mn(u)||(u=La,"selectionStart"in u&&of(u)?u={start:u.selectionStart,end:u.selectionEnd}:(u=(u.ownerDocument&&u.ownerDocument.defaultView||window).getSelection(),u={anchorNode:u.anchorNode,anchorOffset:u.anchorOffset,focusNode:u.focusNode,focusOffset:u.focusOffset}),Gu&&Pu(Gu,u)||(Gu=u,u=Un(oc,"onSelect"),0>=i,e-=i,ot=1<<32-Ll(t)+e|a<O?(C=T,T=null):C=T.sibling;var x=m(o,T,d[O],r);if(x===null){T===null&&(T=C);break}l&&T&&x.alternate===null&&t(o,T),s=n(x,s,O),N===null?A=x:N.sibling=x,N=x,T=C}if(O===d.length)return a(o,T),G&&Et(o,O),A;if(T===null){for(;OO?(C=T,T=null):C=T.sibling;var Dl=m(o,T,x.value,r);if(Dl===null){T===null&&(T=C);break}l&&T&&Dl.alternate===null&&t(o,T),s=n(Dl,s,O),N===null?A=Dl:N.sibling=Dl,N=Dl,T=C}if(x.done)return a(o,T),G&&Et(o,O),A;if(T===null){for(;!x.done;O++,x=d.next())x=y(o,x.value,r),x!==null&&(s=n(x,s,O),N===null?A=x:N.sibling=x,N=x);return G&&Et(o,O),A}for(T=u(T);!x.done;O++,x=d.next())x=v(T,o,O,x.value,r),x!==null&&(l&&x.alternate!==null&&T.delete(x.key===null?O:x.key),s=n(x,s,O),N===null?A=x:N.sibling=x,N=x);return l&&T.forEach(function(et){return t(o,et)}),G&&Et(o,O),A}function j(o,s,d,r){if(typeof d=="object"&&d!==null&&d.type===qa&&d.key===null&&(d=d.props.children),typeof d=="object"&&d!==null){switch(d.$$typeof){case De:l:{for(var A=d.key;s!==null;){if(s.key===A){if(A=d.type,A===qa){if(s.tag===7){a(o,s.sibling),r=e(s,d.props.children),r.return=o,o=r;break l}}else if(s.elementType===A||typeof A=="object"&&A!==null&&A.$$typeof===Gt&&ga(A)===s.type){a(o,s.sibling),r=e(s,d.props),Mu(r,d),r.return=o,o=r;break l}a(o,s);break}else t(o,s);s=s.sibling}d.type===qa?(r=ba(d.props.children,o.mode,r,d.key),r.return=o,o=r):(r=We(d.type,d.key,d.props,null,o.mode,r),Mu(r,d),r.return=o,o=r)}return i(o);case Uu:l:{for(A=d.key;s!==null;){if(s.key===A)if(s.tag===4&&s.stateNode.containerInfo===d.containerInfo&&s.stateNode.implementation===d.implementation){a(o,s.sibling),r=e(s,d.children||[]),r.return=o,o=r;break l}else{a(o,s);break}else t(o,s);s=s.sibling}r=bi(d,o.mode,r),r.return=o,o=r}return i(o);case Gt:return d=ga(d),j(o,s,d,r)}if(Hu(d))return p(o,s,d,r);if(Au(d)){if(A=Au(d),typeof A!="function")throw Error(S(150));return d=A.call(d),z(o,s,d,r)}if(typeof d.then=="function")return j(o,s,xe(d),r);if(d.$$typeof===_t)return j(o,s,je(o,d),r);Be(o,d)}return typeof d=="string"&&d!==""||typeof d=="number"||typeof d=="bigint"?(d=""+d,s!==null&&s.tag===6?(a(o,s.sibling),r=e(s,d),r.return=o,o=r):(a(o,s),r=Si(d,o.mode,r),r.return=o,o=r),i(o)):a(o,s)}return function(o,s,d,r){try{ae=0;var A=j(o,s,d,r);return lu=null,A}catch(T){if(T===bu||T===wn)throw T;var N=Gl(29,T,null,o.mode);return N.lanes=r,N.return=o,N}finally{}}}var _a=Jo(!0),wo=Jo(!1),Xt=!1;function bf(l){l.updateQueue={baseState:l.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Sc(l,t){l=l.updateQueue,t.updateQueue===l&&(t.updateQueue={baseState:l.baseState,firstBaseUpdate:l.firstBaseUpdate,lastBaseUpdate:l.lastBaseUpdate,shared:l.shared,callbacks:null})}function Pt(l){return{lane:l,tag:0,payload:null,callback:null,next:null}}function la(l,t,a){var u=l.updateQueue;if(u===null)return null;if(u=u.shared,Q&2){var e=u.pending;return e===null?t.next=t:(t.next=e.next,e.next=t),u.pending=t,t=yn(l),qo(l,null,a),t}return Jn(l,u,t,a),yn(l)}function Qu(l,t,a){if(t=t.updateQueue,t!==null&&(t=t.shared,(a&4194048)!==0)){var u=t.lanes;u&=l.pendingLanes,a|=u,t.lanes=a,oo(l,a)}}function Ti(l,t){var a=l.updateQueue,u=l.alternate;if(u!==null&&(u=u.updateQueue,a===u)){var e=null,n=null;if(a=a.firstBaseUpdate,a!==null){do{var i={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};n===null?e=n=i:n=n.next=i,a=a.next}while(a!==null);n===null?e=n=t:n=n.next=t}else e=n=t;a={baseState:u.baseState,firstBaseUpdate:e,lastBaseUpdate:n,shared:u.shared,callbacks:u.callbacks},l.updateQueue=a;return}l=a.lastBaseUpdate,l===null?a.firstBaseUpdate=t:l.next=t,a.lastBaseUpdate=t}var bc=!1;function Zu(){if(bc){var l=Pa;if(l!==null)throw l}}function Lu(l,t,a,u){bc=!1;var e=l.updateQueue;Xt=!1;var n=e.firstBaseUpdate,i=e.lastBaseUpdate,c=e.shared.pending;if(c!==null){e.shared.pending=null;var f=c,h=f.next;f.next=null,i===null?n=h:i.next=h,i=f;var g=l.alternate;g!==null&&(g=g.updateQueue,c=g.lastBaseUpdate,c!==i&&(c===null?g.firstBaseUpdate=h:c.next=h,g.lastBaseUpdate=f))}if(n!==null){var y=e.baseState;i=0,g=h=f=null,c=n;do{var m=c.lane&-536870913,v=m!==c.lane;if(v?(q&m)===m:(u&m)===m){m!==0&&m===cu&&(bc=!0),g!==null&&(g=g.next={lane:0,tag:c.tag,payload:c.payload,callback:null,next:null});l:{var p=l,z=c;m=t;var j=a;switch(z.tag){case 1:if(p=z.payload,typeof p=="function"){y=p.call(j,y,m);break l}y=p;break l;case 3:p.flags=p.flags&-65537|128;case 0:if(p=z.payload,m=typeof p=="function"?p.call(j,y,m):p,m==null)break l;y=tl({},y,m);break l;case 2:Xt=!0}}m=c.callback,m!==null&&(l.flags|=64,v&&(l.flags|=8192),v=e.callbacks,v===null?e.callbacks=[m]:v.push(m))}else v={lane:m,tag:c.tag,payload:c.payload,callback:c.callback,next:null},g===null?(h=g=v,f=y):g=g.next=v,i|=m;if(c=c.next,c===null){if(c=e.shared.pending,c===null)break;v=c,c=v.next,v.next=null,e.lastBaseUpdate=v,e.shared.pending=null}}while(1);g===null&&(f=y),e.baseState=f,e.firstBaseUpdate=h,e.lastBaseUpdate=g,n===null&&(e.shared.lanes=0),sa|=i,l.lanes=i,l.memoizedState=y}}function $o(l,t){if(typeof l!="function")throw Error(S(191,l));l.call(t)}function Wo(l,t){var a=l.callbacks;if(a!==null)for(l.callbacks=null,l=0;ln?n:8;var i=M.T,c={};M.T=c,Rf(l,!1,t,a);try{var f=e(),h=M.S;if(h!==null&&h(c,f),f!==null&&typeof f=="object"&&typeof f.then=="function"){var g=Gd(f,u);Vu(l,t,g,Vl(l))}else Vu(l,t,u,Vl(l))}catch(y){Vu(l,t,{then:function(){},status:"rejected",reason:y},Vl())}finally{Z.p=n,i!==null&&c.types!==null&&(i.types=c.types),M.T=i}}function Kd(){}function zc(l,t,a,u){if(l.tag!==5)throw Error(S(476));var e=ph(l).queue;bh(l,e,t,Sa,a===null?Kd:function(){return Th(l),a(u)})}function ph(l){var t=l.memoizedState;if(t!==null)return t;t={memoizedState:Sa,baseState:Sa,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ct,lastRenderedState:Sa},next:null};var a={};return t.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ct,lastRenderedState:a},next:null},l.memoizedState=t,l=l.alternate,l!==null&&(l.memoizedState=t),t}function Th(l){var t=ph(l);t.next===null&&(t=l.alternate.memoizedState),Vu(l,t.next.queue,{},Vl())}function Hf(){return El(ce)}function Eh(){return fl().memoizedState}function Ah(){return fl().memoizedState}function Jd(l){for(var t=l.return;t!==null;){switch(t.tag){case 24:case 3:var a=Vl();l=Pt(a);var u=la(t,l,a);u!==null&&(jl(u,t,a),Qu(u,t,a)),t={cache:gf()},l.payload=t;return}t=t.return}}function wd(l,t,a){var u=Vl();a={lane:u,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},kn(l)?_h(t,a):(a=mf(l,t,a,u),a!==null&&(jl(a,l,u),Mh(a,t,u)))}function zh(l,t,a){var u=Vl();Vu(l,t,a,u)}function Vu(l,t,a,u){var e={lane:u,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(kn(l))_h(t,e);else{var n=l.alternate;if(l.lanes===0&&(n===null||n.lanes===0)&&(n=t.lastRenderedReducer,n!==null))try{var i=t.lastRenderedState,c=n(i,a);if(e.hasEagerState=!0,e.eagerState=c,Kl(c,i))return Jn(l,t,e,0),F===null&&Kn(),!1}catch{}finally{}if(a=mf(l,t,e,u),a!==null)return jl(a,l,u),Mh(a,t,u),!0}return!1}function Rf(l,t,a,u){if(u={lane:2,revertLane:Qf(),gesture:null,action:u,hasEagerState:!1,eagerState:null,next:null},kn(l)){if(t)throw Error(S(479))}else t=mf(l,a,u,2),t!==null&&jl(t,l,2)}function kn(l){var t=l.alternate;return l===R||t!==null&&t===R}function _h(l,t){tu=pn=!0;var a=l.pending;a===null?t.next=t:(t.next=a.next,a.next=t),l.pending=t}function Mh(l,t,a){if(a&4194048){var u=t.lanes;u&=l.pendingLanes,a|=u,t.lanes=a,oo(l,a)}}var ee={readContext:El,use:Wn,useCallback:el,useContext:el,useEffect:el,useImperativeHandle:el,useLayoutEffect:el,useInsertionEffect:el,useMemo:el,useReducer:el,useRef:el,useState:el,useDebugValue:el,useDeferredValue:el,useTransition:el,useSyncExternalStore:el,useId:el,useHostTransitionStatus:el,useFormState:el,useActionState:el,useOptimistic:el,useMemoCache:el,useCacheRefresh:el};ee.useEffectEvent=el;var Oh={readContext:El,use:Wn,useCallback:function(l,t){return _l().memoizedState=[l,t===void 0?null:t],l},useContext:El,useEffect:Qs,useImperativeHandle:function(l,t,a){a=a!=null?a.concat([l]):null,Ie(4194308,4,yh.bind(null,t,l),a)},useLayoutEffect:function(l,t){return Ie(4194308,4,l,t)},useInsertionEffect:function(l,t){Ie(4,2,l,t)},useMemo:function(l,t){var a=_l();t=t===void 0?null:t;var u=l();if(Ma){Kt(!0);try{l()}finally{Kt(!1)}}return a.memoizedState=[u,t],u},useReducer:function(l,t,a){var u=_l();if(a!==void 0){var e=a(t);if(Ma){Kt(!0);try{a(t)}finally{Kt(!1)}}}else e=t;return u.memoizedState=u.baseState=e,l={pending:null,lanes:0,dispatch:null,lastRenderedReducer:l,lastRenderedState:e},u.queue=l,l=l.dispatch=wd.bind(null,R,l),[u.memoizedState,l]},useRef:function(l){var t=_l();return l={current:l},t.memoizedState=l},useState:function(l){l=Ec(l);var t=l.queue,a=zh.bind(null,R,t);return t.dispatch=a,[l.memoizedState,a]},useDebugValue:Nf,useDeferredValue:function(l,t){var a=_l();return Uf(a,l,t)},useTransition:function(){var l=Ec(!1);return l=bh.bind(null,R,l.queue,!0,!1),_l().memoizedState=l,[!1,l]},useSyncExternalStore:function(l,t,a){var u=R,e=_l();if(G){if(a===void 0)throw Error(S(407));a=a()}else{if(a=t(),F===null)throw Error(S(349));q&127||lh(u,t,a)}e.memoizedState=a;var n={value:a,getSnapshot:t};return e.queue=n,Qs(ah.bind(null,u,n,l),[l]),u.flags|=2048,su(9,{destroy:void 0},th.bind(null,u,n,a,t),null),a},useId:function(){var l=_l(),t=F.identifierPrefix;if(G){var a=ht,u=ot;a=(u&~(1<<32-Ll(u)-1)).toString(32)+a,t="_"+t+"R_"+a,a=Tn++,0<\/script>",n=n.removeChild(n.firstChild);break;case"select":n=typeof u.is=="string"?i.createElement("select",{is:u.is}):i.createElement("select"),u.multiple?n.multiple=!0:u.size&&(n.size=u.size);break;default:n=typeof u.is=="string"?i.createElement(e,{is:u.is}):i.createElement(e)}}n[pl]=t,n[xl]=u;l:for(i=t.child;i!==null;){if(i.tag===5||i.tag===6)n.appendChild(i.stateNode);else if(i.tag!==4&&i.tag!==27&&i.child!==null){i.child.return=i,i=i.child;continue}if(i===t)break l;for(;i.sibling===null;){if(i.return===null||i.return===t)break l;i=i.return}i.sibling.return=i.return,i=i.sibling}t.stateNode=n;l:switch(Al(n,e,u),e){case"button":case"input":case"select":case"textarea":u=!!u.autoFocus;break l;case"img":u=!0;break l;default:u=!1}u&&St(t)}}return I(t),Ni(t,t.type,l===null?null:l.memoizedProps,t.pendingProps,a),null;case 6:if(l&&t.stateNode!=null)l.memoizedProps!==u&&St(t);else{if(typeof u!="string"&&t.stateNode===null)throw Error(S(166));if(l=kt.current,Ca(t)){if(l=t.stateNode,a=t.memoizedProps,u=null,e=Tl,e!==null)switch(e.tag){case 27:case 5:u=e.memoizedProps}l[pl]=t,l=!!(l.nodeValue===a||u!==null&&u.suppressHydrationWarning===!0||z1(l.nodeValue,a)),l||ca(t,!0)}else l=Hn(l).createTextNode(u),l[pl]=t,t.stateNode=l}return I(t),null;case 31:if(a=t.memoizedState,l===null||l.memoizedState!==null){if(u=Ca(t),a!==null){if(l===null){if(!u)throw Error(S(318));if(l=t.memoizedState,l=l!==null?l.dehydrated:null,!l)throw Error(S(557));l[pl]=t}else Aa(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;I(t),l=!1}else a=pi(),l!==null&&l.memoizedState!==null&&(l.memoizedState.hydrationErrors=a),l=!0;if(!l)return t.flags&256?(ql(t),t):(ql(t),null);if(t.flags&128)throw Error(S(558))}return I(t),null;case 13:if(u=t.memoizedState,l===null||l.memoizedState!==null&&l.memoizedState.dehydrated!==null){if(e=Ca(t),u!==null&&u.dehydrated!==null){if(l===null){if(!e)throw Error(S(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(S(317));e[pl]=t}else Aa(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;I(t),e=!1}else e=pi(),l!==null&&l.memoizedState!==null&&(l.memoizedState.hydrationErrors=e),e=!0;if(!e)return t.flags&256?(ql(t),t):(ql(t),null)}return ql(t),t.flags&128?(t.lanes=a,t):(a=u!==null,l=l!==null&&l.memoizedState!==null,a&&(u=t.child,e=null,u.alternate!==null&&u.alternate.memoizedState!==null&&u.alternate.memoizedState.cachePool!==null&&(e=u.alternate.memoizedState.cachePool.pool),n=null,u.memoizedState!==null&&u.memoizedState.cachePool!==null&&(n=u.memoizedState.cachePool.pool),n!==e&&(u.flags|=2048)),a!==l&&a&&(t.child.flags|=8192),Ye(t,t.updateQueue),I(t),null);case 4:return eu(),l===null&&Zf(t.stateNode.containerInfo),I(t),null;case 10:return Nt(t.type),I(t),null;case 19:if(Sl(cl),u=t.memoizedState,u===null)return I(t),null;if(e=(t.flags&128)!==0,n=u.rendering,n===null)if(e)Ou(u,!1);else{if(nl!==0||l!==null&&l.flags&128)for(l=t.child;l!==null;){if(n=bn(l),n!==null){for(t.flags|=128,Ou(u,!1),l=n.updateQueue,t.updateQueue=l,Ye(t,l),t.subtreeFlags=0,l=a,a=t.child;a!==null;)Go(a,l),a=a.sibling;return k(cl,cl.current&1|2),G&&Et(t,u.treeForkCount),t.child}l=l.sibling}u.tail!==null&&Ql()>_n&&(t.flags|=128,e=!0,Ou(u,!1),t.lanes=4194304)}else{if(!e)if(l=bn(n),l!==null){if(t.flags|=128,e=!0,l=l.updateQueue,t.updateQueue=l,Ye(t,l),Ou(u,!0),u.tail===null&&u.tailMode==="hidden"&&!n.alternate&&!G)return I(t),null}else 2*Ql()-u.renderingStartTime>_n&&a!==536870912&&(t.flags|=128,e=!0,Ou(u,!1),t.lanes=4194304);u.isBackwards?(n.sibling=t.child,t.child=n):(l=u.last,l!==null?l.sibling=n:t.child=n,u.last=n)}return u.tail!==null?(l=u.tail,u.rendering=l,u.tail=l.sibling,u.renderingStartTime=Ql(),l.sibling=null,a=cl.current,k(cl,e?a&1|2:a&1),G&&Et(t,u.treeForkCount),l):(I(t),null);case 22:case 23:return ql(t),pf(),u=t.memoizedState!==null,l!==null?l.memoizedState!==null!==u&&(t.flags|=8192):u&&(t.flags|=8192),u?a&536870912&&!(t.flags&128)&&(I(t),t.subtreeFlags&6&&(t.flags|=8192)):I(t),a=t.updateQueue,a!==null&&Ye(t,a.retryQueue),a=null,l!==null&&l.memoizedState!==null&&l.memoizedState.cachePool!==null&&(a=l.memoizedState.cachePool.pool),u=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(u=t.memoizedState.cachePool.pool),u!==a&&(t.flags|=2048),l!==null&&Sl(pa),null;case 24:return a=null,l!==null&&(a=l.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),Nt(hl),I(t),null;case 25:return null;case 30:return null}throw Error(S(156,t.tag))}function Id(l,t){switch(vf(t),t.tag){case 1:return l=t.flags,l&65536?(t.flags=l&-65537|128,t):null;case 3:return Nt(hl),eu(),l=t.flags,l&65536&&!(l&128)?(t.flags=l&-65537|128,t):null;case 26:case 27:case 5:return on(t),null;case 31:if(t.memoizedState!==null){if(ql(t),t.alternate===null)throw Error(S(340));Aa()}return l=t.flags,l&65536?(t.flags=l&-65537|128,t):null;case 13:if(ql(t),l=t.memoizedState,l!==null&&l.dehydrated!==null){if(t.alternate===null)throw Error(S(340));Aa()}return l=t.flags,l&65536?(t.flags=l&-65537|128,t):null;case 19:return Sl(cl),null;case 4:return eu(),null;case 10:return Nt(t.type),null;case 22:case 23:return ql(t),pf(),l!==null&&Sl(pa),l=t.flags,l&65536?(t.flags=l&-65537|128,t):null;case 24:return Nt(hl),null;case 25:return null;default:return null}}function Gh(l,t){switch(vf(t),t.tag){case 3:Nt(hl),eu();break;case 26:case 27:case 5:on(t);break;case 4:eu();break;case 31:t.memoizedState!==null&&ql(t);break;case 13:ql(t);break;case 19:Sl(cl);break;case 10:Nt(t.type);break;case 22:case 23:ql(t),pf(),l!==null&&Sl(pa);break;case 24:Nt(hl)}}function be(l,t){try{var a=t.updateQueue,u=a!==null?a.lastEffect:null;if(u!==null){var e=u.next;a=e;do{if((a.tag&l)===l){u=void 0;var n=a.create,i=a.inst;u=n(),i.destroy=u}a=a.next}while(a!==e)}}catch(c){K(t,t.return,c)}}function fa(l,t,a){try{var u=t.updateQueue,e=u!==null?u.lastEffect:null;if(e!==null){var n=e.next;u=n;do{if((u.tag&l)===l){var i=u.inst,c=i.destroy;if(c!==void 0){i.destroy=void 0,e=t;var f=a,h=c;try{h()}catch(g){K(e,f,g)}}}u=u.next}while(u!==n)}}catch(g){K(t,t.return,g)}}function Xh(l){var t=l.updateQueue;if(t!==null){var a=l.stateNode;try{Wo(t,a)}catch(u){K(l,l.return,u)}}}function Qh(l,t,a){a.props=Oa(l.type,l.memoizedProps),a.state=l.memoizedState;try{a.componentWillUnmount()}catch(u){K(l,t,u)}}function Ku(l,t){try{var a=l.ref;if(a!==null){switch(l.tag){case 26:case 27:case 5:var u=l.stateNode;break;case 30:u=l.stateNode;break;default:u=l.stateNode}typeof a=="function"?l.refCleanup=a(u):a.current=u}}catch(e){K(l,t,e)}}function mt(l,t){var a=l.ref,u=l.refCleanup;if(a!==null)if(typeof u=="function")try{u()}catch(e){K(l,t,e)}finally{l.refCleanup=null,l=l.alternate,l!=null&&(l.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(e){K(l,t,e)}else a.current=null}function Zh(l){var t=l.type,a=l.memoizedProps,u=l.stateNode;try{l:switch(t){case"button":case"input":case"select":case"textarea":a.autoFocus&&u.focus();break l;case"img":a.src?u.src=a.src:a.srcSet&&(u.srcset=a.srcSet)}}catch(e){K(l,l.return,e)}}function Ui(l,t,a){try{var u=l.stateNode;py(u,l.type,a,t),u[xl]=t}catch(e){K(l,l.return,e)}}function Lh(l){return l.tag===5||l.tag===3||l.tag===26||l.tag===27&&ha(l.type)||l.tag===4}function Hi(l){l:for(;;){for(;l.sibling===null;){if(l.return===null||Lh(l.return))return null;l=l.return}for(l.sibling.return=l.return,l=l.sibling;l.tag!==5&&l.tag!==6&&l.tag!==18;){if(l.tag===27&&ha(l.type)||l.flags&2||l.child===null||l.tag===4)continue l;l.child.return=l,l=l.child}if(!(l.flags&2))return l.stateNode}}function Nc(l,t,a){var u=l.tag;if(u===5||u===6)l=l.stateNode,t?(a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a).insertBefore(l,t):(t=a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a,t.appendChild(l),a=a._reactRootContainer,a!=null||t.onclick!==null||(t.onclick=Mt));else if(u!==4&&(u===27&&ha(l.type)&&(a=l.stateNode,t=null),l=l.child,l!==null))for(Nc(l,t,a),l=l.sibling;l!==null;)Nc(l,t,a),l=l.sibling}function zn(l,t,a){var u=l.tag;if(u===5||u===6)l=l.stateNode,t?a.insertBefore(l,t):a.appendChild(l);else if(u!==4&&(u===27&&ha(l.type)&&(a=l.stateNode),l=l.child,l!==null))for(zn(l,t,a),l=l.sibling;l!==null;)zn(l,t,a),l=l.sibling}function Vh(l){var t=l.stateNode,a=l.memoizedProps;try{for(var u=l.type,e=t.attributes;e.length;)t.removeAttributeNode(e[0]);Al(t,u,a),t[pl]=l,t[xl]=a}catch(n){K(l,l.return,n)}}var zt=!1,ol=!1,Ri=!1,l0=typeof WeakSet=="function"?WeakSet:Set,gl=null;function Pd(l,t){if(l=l.containerInfo,Bc=xn,l=Ho(l),of(l)){if("selectionStart"in l)var a={start:l.selectionStart,end:l.selectionEnd};else l:{a=(a=l.ownerDocument)&&a.defaultView||window;var u=a.getSelection&&a.getSelection();if(u&&u.rangeCount!==0){a=u.anchorNode;var e=u.anchorOffset,n=u.focusNode;u=u.focusOffset;try{a.nodeType,n.nodeType}catch{a=null;break l}var i=0,c=-1,f=-1,h=0,g=0,y=l,m=null;t:for(;;){for(var v;y!==a||e!==0&&y.nodeType!==3||(c=i+e),y!==n||u!==0&&y.nodeType!==3||(f=i+u),y.nodeType===3&&(i+=y.nodeValue.length),(v=y.firstChild)!==null;)m=y,y=v;for(;;){if(y===l)break t;if(m===a&&++h===e&&(c=i),m===n&&++g===u&&(f=i),(v=y.nextSibling)!==null)break;y=m,m=y.parentNode}y=v}a=c===-1||f===-1?null:{start:c,end:f}}else a=null}a=a||{start:0,end:0}}else a=null;for(Yc={focusedElem:l,selectionRange:a},xn=!1,gl=t;gl!==null;)if(t=gl,l=t.child,(t.subtreeFlags&1028)!==0&&l!==null)l.return=t,gl=l;else for(;gl!==null;){switch(t=gl,n=t.alternate,l=t.flags,t.tag){case 0:if(l&4&&(l=t.updateQueue,l=l!==null?l.events:null,l!==null))for(a=0;a title"))),Al(n,u,a),n[pl]=l,rl(n),u=n;break l;case"link":var i=p0("link","href",e).get(u+(a.href||""));if(i){for(var c=0;cj&&(i=j,j=z,z=i);var o=_s(c,z),s=_s(c,j);if(o&&s&&(v.rangeCount!==1||v.anchorNode!==o.node||v.anchorOffset!==o.offset||v.focusNode!==s.node||v.focusOffset!==s.offset)){var d=y.createRange();d.setStart(o.node,o.offset),v.removeAllRanges(),z>j?(v.addRange(d),v.extend(s.node,s.offset)):(d.setEnd(s.node,s.offset),v.addRange(d))}}}}for(y=[],v=c;v=v.parentNode;)v.nodeType===1&&y.push({element:v,left:v.scrollLeft,top:v.scrollTop});for(typeof c.focus=="function"&&c.focus(),c=0;ca?32:a,M.T=null,a=Rc,Rc=null;var n=aa,i=Ut;if(dl=0,hu=aa=null,Ut=0,Q&6)throw Error(S(331));var c=Q;if(Q|=4,t1(n.current),Ih(n,n.current,i,a),Q=c,pe(0,!1),Zl&&typeof Zl.onPostCommitFiberRoot=="function")try{Zl.onPostCommitFiberRoot(me,n)}catch{}return!0}finally{Z.p=e,M.T=u,g1(l,t)}}function e0(l,t,a){t=Pl(a,t),t=Mc(l.stateNode,t,2),l=la(l,t,2),l!==null&&(ye(l,2),gt(l))}function K(l,t,a){if(l.tag===3)e0(l,l,a);else for(;t!==null;){if(t.tag===3){e0(t,l,a);break}else if(t.tag===1){var u=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof u.componentDidCatch=="function"&&(ta===null||!ta.has(u))){l=Pl(a,l),a=Rh(2),u=la(t,a,2),u!==null&&(Ch(a,u,t,l),ye(u,2),gt(u));break}}t=t.return}}function ji(l,t,a){var u=l.pingCache;if(u===null){u=l.pingCache=new ay;var e=new Set;u.set(t,e)}else e=u.get(t),e===void 0&&(e=new Set,u.set(t,e));e.has(a)||(qf=!0,e.add(a),l=cy.bind(null,l,t,a),t.then(l,l))}function cy(l,t,a){var u=l.pingCache;u!==null&&u.delete(t),l.pingedLanes|=l.suspendedLanes&a,l.warmLanes&=~a,F===l&&(q&a)===a&&(nl===4||nl===3&&(q&62914560)===q&&300>Ql()-In?!(Q&2)&&mu(l,0):Gf|=a,ou===q&&(ou=0)),gt(l)}function S1(l,t){t===0&&(t=fo()),l=Ha(l,t),l!==null&&(ye(l,t),gt(l))}function fy(l){var t=l.memoizedState,a=0;t!==null&&(a=t.retryLane),S1(l,a)}function sy(l,t){var a=0;switch(l.tag){case 31:case 13:var u=l.stateNode,e=l.memoizedState;e!==null&&(a=e.retryLane);break;case 19:u=l.stateNode;break;case 22:u=l.stateNode._retryCache;break;default:throw Error(S(314))}u!==null&&u.delete(t),S1(l,a)}function oy(l,t){return lf(l,t)}var Dn=null,Ya=null,jc=!1,Nn=!1,xi=!1,Wt=0;function gt(l){l!==Ya&&l.next===null&&(Ya===null?Dn=Ya=l:Ya=Ya.next=l),Nn=!0,jc||(jc=!0,my())}function pe(l,t){if(!xi&&Nn){xi=!0;do for(var a=!1,u=Dn;u!==null;){if(!t)if(l!==0){var e=u.pendingLanes;if(e===0)var n=0;else{var i=u.suspendedLanes,c=u.pingedLanes;n=(1<<31-Ll(42|l)+1)-1,n&=e&~(i&~c),n=n&201326741?n&201326741|1:n?n|2:0}n!==0&&(a=!0,n0(u,n))}else n=q,n=Qn(u,u===F?n:0,u.cancelPendingCommit!==null||u.timeoutHandle!==-1),!(n&3)||de(u,n)||(a=!0,n0(u,n));u=u.next}while(a);xi=!1}}function hy(){b1()}function b1(){Nn=jc=!1;var l=0;Wt!==0&&Ey()&&(l=Wt);for(var t=Ql(),a=null,u=Dn;u!==null;){var e=u.next,n=p1(u,t);n===0?(u.next=null,a===null?Dn=e:a.next=e,e===null&&(Ya=a)):(a=u,(l!==0||n&3)&&(Nn=!0)),u=e}dl!==0&&dl!==5||pe(l,!1),Wt!==0&&(Wt=0)}function p1(l,t){for(var a=l.suspendedLanes,u=l.pingedLanes,e=l.expirationTimes,n=l.pendingLanes&-62914561;0c)break;var g=f.transferSize,y=f.initiatorType;g&&o0(y)&&(f=f.responseEnd,i+=g*(f"u"?null:document;function N1(l,t,a){var u=Tu;if(u&&typeof t=="string"&&t){var e=Il(t);e='link[rel="'+l+'"][href="'+e+'"]',typeof a=="string"&&(e+='[crossorigin="'+a+'"]'),r0.has(e)||(r0.add(e),l={rel:l,crossOrigin:a,href:t},u.querySelector(e)===null&&(t=u.createElement("link"),Al(t,"link",l),rl(t),u.head.appendChild(t)))}}function Hy(l){Bt.D(l),N1("dns-prefetch",l,null)}function Ry(l,t){Bt.C(l,t),N1("preconnect",l,t)}function Cy(l,t,a){Bt.L(l,t,a);var u=Tu;if(u&&l&&t){var e='link[rel="preload"][as="'+Il(t)+'"]';t==="image"&&a&&a.imageSrcSet?(e+='[imagesrcset="'+Il(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(e+='[imagesizes="'+Il(a.imageSizes)+'"]')):e+='[href="'+Il(l)+'"]';var n=e;switch(t){case"style":n=du(l);break;case"script":n=Eu(l)}ut.has(n)||(l=tl({rel:"preload",href:t==="image"&&a&&a.imageSrcSet?void 0:l,as:t},a),ut.set(n,l),u.querySelector(e)!==null||t==="style"&&u.querySelector(Te(n))||t==="script"&&u.querySelector(Ee(n))||(t=u.createElement("link"),Al(t,"link",l),rl(t),u.head.appendChild(t)))}}function jy(l,t){Bt.m(l,t);var a=Tu;if(a&&l){var u=t&&typeof t.as=="string"?t.as:"script",e='link[rel="modulepreload"][as="'+Il(u)+'"][href="'+Il(l)+'"]',n=e;switch(u){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":n=Eu(l)}if(!ut.has(n)&&(l=tl({rel:"modulepreload",href:l},t),ut.set(n,l),a.querySelector(e)===null)){switch(u){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(Ee(n)))return}u=a.createElement("link"),Al(u,"link",l),rl(u),a.head.appendChild(u)}}}function xy(l,t,a){Bt.S(l,t,a);var u=Tu;if(u&&l){var e=Fa(u).hoistableStyles,n=du(l);t=t||"default";var i=e.get(n);if(!i){var c={loading:0,preload:null};if(i=u.querySelector(Te(n)))c.loading=5;else{l=tl({rel:"stylesheet",href:l,"data-precedence":t},a),(a=ut.get(n))&&Lf(l,a);var f=i=u.createElement("link");rl(f),Al(f,"link",l),f._p=new Promise(function(h,g){f.onload=h,f.onerror=g}),f.addEventListener("load",function(){c.loading|=1}),f.addEventListener("error",function(){c.loading|=2}),c.loading|=4,an(i,t,u)}i={type:"stylesheet",instance:i,count:1,state:c},e.set(n,i)}}}function By(l,t){Bt.X(l,t);var a=Tu;if(a&&l){var u=Fa(a).hoistableScripts,e=Eu(l),n=u.get(e);n||(n=a.querySelector(Ee(e)),n||(l=tl({src:l,async:!0},t),(t=ut.get(e))&&Vf(l,t),n=a.createElement("script"),rl(n),Al(n,"link",l),a.head.appendChild(n)),n={type:"script",instance:n,count:1,state:null},u.set(e,n))}}function Yy(l,t){Bt.M(l,t);var a=Tu;if(a&&l){var u=Fa(a).hoistableScripts,e=Eu(l),n=u.get(e);n||(n=a.querySelector(Ee(e)),n||(l=tl({src:l,async:!0,type:"module"},t),(t=ut.get(e))&&Vf(l,t),n=a.createElement("script"),rl(n),Al(n,"link",l),a.head.appendChild(n)),n={type:"script",instance:n,count:1,state:null},u.set(e,n))}}function S0(l,t,a,u){var e=(e=kt.current)?Rn(e):null;if(!e)throw Error(S(446));switch(l){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(t=du(a.href),a=Fa(e).hoistableStyles,u=a.get(t),u||(u={type:"style",instance:null,count:0,state:null},a.set(t,u)),u):{type:"void",instance:null,count:0,state:null};case"link":if(a.rel==="stylesheet"&&typeof a.href=="string"&&typeof a.precedence=="string"){l=du(a.href);var n=Fa(e).hoistableStyles,i=n.get(l);if(i||(e=e.ownerDocument||e,i={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},n.set(l,i),(n=e.querySelector(Te(l)))&&!n._p&&(i.instance=n,i.state.loading=5),ut.has(l)||(a={rel:"preload",as:"style",href:a.href,crossOrigin:a.crossOrigin,integrity:a.integrity,media:a.media,hrefLang:a.hrefLang,referrerPolicy:a.referrerPolicy},ut.set(l,a),n||qy(e,l,a,i.state))),t&&u===null)throw Error(S(528,""));return i}if(t&&u!==null)throw Error(S(529,""));return null;case"script":return t=a.async,a=a.src,typeof a=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=Eu(a),a=Fa(e).hoistableScripts,u=a.get(t),u||(u={type:"script",instance:null,count:0,state:null},a.set(t,u)),u):{type:"void",instance:null,count:0,state:null};default:throw Error(S(444,l))}}function du(l){return'href="'+Il(l)+'"'}function Te(l){return'link[rel="stylesheet"]['+l+"]"}function U1(l){return tl({},l,{"data-precedence":l.precedence,precedence:null})}function qy(l,t,a,u){l.querySelector('link[rel="preload"][as="style"]['+t+"]")?u.loading=1:(t=l.createElement("link"),u.preload=t,t.addEventListener("load",function(){return u.loading|=1}),t.addEventListener("error",function(){return u.loading|=2}),Al(t,"link",a),rl(t),l.head.appendChild(t))}function Eu(l){return'[src="'+Il(l)+'"]'}function Ee(l){return"script[async]"+l}function b0(l,t,a){if(t.count++,t.instance===null)switch(t.type){case"style":var u=l.querySelector('style[data-href~="'+Il(a.href)+'"]');if(u)return t.instance=u,rl(u),u;var e=tl({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return u=(l.ownerDocument||l).createElement("style"),rl(u),Al(u,"style",e),an(u,a.precedence,l),t.instance=u;case"stylesheet":e=du(a.href);var n=l.querySelector(Te(e));if(n)return t.state.loading|=4,t.instance=n,rl(n),n;u=U1(a),(e=ut.get(e))&&Lf(u,e),n=(l.ownerDocument||l).createElement("link"),rl(n);var i=n;return i._p=new Promise(function(c,f){i.onload=c,i.onerror=f}),Al(n,"link",u),t.state.loading|=4,an(n,a.precedence,l),t.instance=n;case"script":return n=Eu(a.src),(e=l.querySelector(Ee(n)))?(t.instance=e,rl(e),e):(u=a,(e=ut.get(n))&&(u=tl({},a),Vf(u,e)),l=l.ownerDocument||l,e=l.createElement("script"),rl(e),Al(e,"link",u),l.head.appendChild(e),t.instance=e);case"void":return null;default:throw Error(S(443,t.type))}else t.type==="stylesheet"&&!(t.state.loading&4)&&(u=t.instance,t.state.loading|=4,an(u,a.precedence,l));return t.instance}function an(l,t,a){for(var u=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),e=u.length?u[u.length-1]:null,n=e,i=0;i title"):null)}function Gy(l,t,a){if(a===1||t.itemProp!=null)return!1;switch(l){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;switch(t.rel){case"stylesheet":return l=t.disabled,typeof t.precedence=="string"&&l==null;default:return!0}case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function H1(l){return!(l.type==="stylesheet"&&!(l.state.loading&3))}function Xy(l,t,a,u){if(a.type==="stylesheet"&&(typeof u.media!="string"||matchMedia(u.media).matches!==!1)&&!(a.state.loading&4)){if(a.instance===null){var e=du(u.href),n=t.querySelector(Te(e));if(n){t=n._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(l.count++,l=Cn.bind(l),t.then(l,l)),a.state.loading|=4,a.instance=n,rl(n);return}n=t.ownerDocument||t,u=U1(u),(e=ut.get(e))&&Lf(u,e),n=n.createElement("link"),rl(n);var i=n;i._p=new Promise(function(c,f){i.onload=c,i.onerror=f}),Al(n,"link",u),a.instance=n}l.stylesheets===null&&(l.stylesheets=new Map),l.stylesheets.set(a,t),(t=a.state.preload)&&!(a.state.loading&3)&&(l.count++,a=Cn.bind(l),t.addEventListener("load",a),t.addEventListener("error",a))}}var Qi=0;function Qy(l,t){return l.stylesheets&&l.count===0&&en(l,l.stylesheets),0Qi?50:800)+t);return l.unsuspend=a,function(){l.unsuspend=null,clearTimeout(u),clearTimeout(e)}}:null}function Cn(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)en(this,this.stylesheets);else if(this.unsuspend){var l=this.unsuspend;this.unsuspend=null,l()}}}var jn=null;function en(l,t){l.stylesheets=null,l.unsuspend!==null&&(l.count++,jn=new Map,t.forEach(Zy,l),jn=null,Cn.call(l))}function Zy(l,t){if(!(t.state.loading&4)){var a=jn.get(l);if(a)var u=a.get(null);else{a=new Map,jn.set(l,a);for(var e=l.querySelectorAll("link[data-precedence],style[data-precedence]"),n=0;n"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(G1)}catch(l){console.error(l)}}G1(),G0.exports=Gn;var Fy=G0.exports;const ky=4,D0=[["#3b82f6","#bfdbfe"],["#a855f7","#f0d9ff"],["#10b981","#b7f5da"],["#ef4444","#ffd5d5"],["#f59e0b","#ffeab0"],["#06b6d4","#b8f2fb"],["#6366f1","#d5daff"],["#84cc16","#e3fab3"]];function Iy(l,t,a){const u=t,e=a;switch(l){case 0:return``;case 1:return``;case 2:{const n=[.35,.62,.45,.8,.55];return n.map((i,c)=>{const f=u*.9/n.length-6;return``}).join("")}default:return``}}const N0=new Map;function X1(l,t,a,u){const e=l%D0.length,n=t%ky,i=`${e}-${n}-${a}x${u}`,c=N0.get(i);if(c)return c;const[f,h]=D0[e],g=`g${e}${n}`,y=`${Iy(n,a,u)}`,m=`data:image/svg+xml,${encodeURIComponent(y)}`;return N0.set(i,m),m}const Q1=40,xu=1500,Kc=8,Py=56,Le=["General","Random","Announcements","Engineering","Design","Product","Support","Off Topic","Releases","Incidents","Frontend","Backend","Infra","Mobile","Performance","Security","Docs","Hiring","Watercooler","Standup"],Ft=["Ada Lovelace","Alan Turing","Grace Hopper","Linus Pauling","Marie Curie","Nikola Tesla","Rosalind Franklin","Carl Sagan","Katherine Johnson","Tim Berners-Lee"],Wf=["#368bd6","#ac3ba8","#03b381","#e64f7a","#ff812d","#2dc2c5","#5c56f5","#74d12c"],Ff=Wf.length,Zi=["the","benchmark","switching","between","rooms","should","feel","instant","even","when","the","timeline","is","long","and","full","of","rich","messages","with","avatars","and","timestamps","rendering","performance","matters","a","lot","here","lets","measure","it","carefully","and","compare","across","browsers","over","time"],Yn=["😀","😂","🎉","🔥","❤️","🙏","👀","🚀","😅","🤔","💯","✨","🙌🏽","👍🏻","😍","🥳","😭","🤯","👏","💪🏾","🧠","☕","🐛","📈","👩‍💻","🧑‍🚀","👨‍👩‍👧‍👦","🏳️‍🌈","🤷‍♀️","🙋‍♂️","🫠","🫶"],U0=["👍","❤️","😂","🎉","🔥","✅","👀","🙏","💯","🚀","😅","🤯"],lv=Ft.map(l=>l.split(" ")[0].toLowerCase()),Z1=["scrollTop","scrollHeight","flushSync","requestAnimationFrame","IntersectionObserver","overflow-anchor","content-visibility","useLayoutEffect","getBoundingClientRect","will-change","ResizeObserver","queueMicrotask","clientHeight","offsetHeight"],tv=["the trace","last night's run","this regression","the profile","the spec text","my notes","the dashboard","that comparison"],L1=["traces/2f9c","runs/nightly","profiles/hot-path","spec/scroll-anchoring","notes/timeline","dashboards/perf","reports/42","compare/main"],av=[{site:"example.com",title:"Scroll anchoring, and why feeds jump",description:"How browsers pin a scroll position while content is inserted above the viewport, and where it gives up."},{site:"perf.example.com",title:"Nightly run 482 vs 481",description:"Geomean moved 1.8% on the chat suites. Row measurement dominates the profile."},{site:"docs.example.com",title:"Windowing a variable-height list",description:"Estimate, measure, cache, correct. The four steps every hand-rolled virtualizer ends up with."},{site:"bugs.example.com",title:"Timeline jumps when the panel opens",description:"Narrowing the scroller re-wraps every row, so the cached heights are all stale at once."}],uv=["can we get a number on how bad the jank is before we start moving code around","the window only recycles about twenty rows, so the mount cost should be flat","every row height changes when the panel opens, which invalidates the cache","please do not use smooth scrolling anywhere inside a timed step","prepending history without pinning the anchor makes the viewport jump"],Li=["estimate the row height first, then correct after measuring","cache measured heights per message id","keep the mounted window small and bounded","assign scroll offsets explicitly instead of animating","recycle rows rather than remounting them","break the group when a reply quote is present","re-measure only the rows the resize actually touched"],ev=[{lang:"js",lines:["const scroller = scrollerRef.current;","scroller.scrollTop = scroller.scrollHeight;"]},{lang:"js",lines:["requestAnimationFrame(() => {"," for (const row of mounted)"," heights.set(row.id, row.offsetHeight);","});"]},{lang:"css",lines:[".timeline {"," overflow-anchor: none;"," content-visibility: auto;","}"]},{lang:"sh",lines:["npm run build","node debugging/e2e-chatroom.mjs --browser chrome"]},{lang:"json",lines:["{",' "iterationCount": 10,',' "suites": ["ChatRoom-React"]',"}"]},{lang:"js",lines:["for (const row of rows) {"," if (!heights.has(row.id))"," heights.set(row.id, estimate);","}"]},{lang:"diff",lines:['- scroller.scrollTo({ top, behavior: "smooth" });',"+ scroller.scrollTop = top;"]},{lang:"js",lines:["export function anchorToBottom(node) {"," node.scrollTop = node.scrollHeight;","}"]}];function W(l,t){let a=Math.imul(l+1,2654435761)^Math.imul(t+1,40503);return a^=a>>>15,a=Math.imul(a,2246822519),a^=a>>>13,a=Math.imul(a,3266489917),a^=a>>>16,a>>>0}function dt(l,t,a){return l[W(t,a)%l.length]}function kf(l){return l.split(" ").map(t=>t[0]).join("").slice(0,2).toUpperCase()}function V1(l){const t=Le[l%Le.length];return l{if(!a.length)return;const i=u?" ":"",c=n?" ":"";t.push({type:"text",text:`${i}${a.join(" ")}${c}`}),a=[],u=!1};for(const n of l){if(typeof n=="string"){a.push(n);continue}e(!0),t.push(n),u=!0}return e(!1),t}function iv(l,t,a){if(a===0)return{type:"code",text:dt(Z1,l,t+11)};if(a===1)return{type:"link",text:dt(tv,l,t+12),href:`https://example.com/${dt(L1,l,t+13)}`};if(a===2)return{type:"mention",name:dt(lv,l,t+14)};const u=W(l,t+15)%Q1;return{type:"room",name:nv(u),roomId:`room-${u}`}}function Ve(l,t){const a=6+W(l,t)%22,u=W(l,t+1)%Zi.length,e=[];let n=!1;for(let g=0;g0&&gString(e).padStart(2,"0");return`${u(t)}:${u(a)}`}const If=24*60,Pf=[];for(let l=0;l[l,t%Ff])),Tv=new Map(Ft.map(l=>[l,kf(l)]));function Ev(l,t){const a=[];let u=0;for(;a.length0&&W(n,201)%100<18){const h=W(n,203)%4===0?1+W(n,204)%Math.min(e,400):1+W(n,202)%6,g=u[Math.max(0,e-h)];f={id:g.id,sender:g.sender,excerpt:Sv(g.blocks)}}u.push({id:`room-${l}-msg-${e}`,sender:i,senderInitials:Tv.get(i),colorIndex:pv.get(i),time:Pf[n%If],dayIndex:a[e],blocks:c,replyTo:f,grouped:e>0&&t[e-1]===i&&!f,reactions:F1[n%W1]})}return u}const zv=12;function _v(){const l=[];for(let t=0;t0,reactions:[]}}function Ov({index:l,room:t,selected:a,onSelect:u}){const e=a?"room-list-item room-list-item-selected":"room-list-item";return E.jsxs("button",{id:`room-list-item-${l}`,className:e,type:"button",onClick:()=>u(t.id),children:[E.jsx("span",{className:"avatar",style:{backgroundColor:Wf[t.colorIndex]},children:t.initials}),E.jsxs("span",{className:"room-list-item-text",children:[E.jsx("span",{className:"room-list-item-name",children:t.name}),E.jsx("span",{className:"room-list-item-preview",children:t.lastMessage})]})]})}function Dv({rooms:l,selectedRoomId:t,onSelect:a}){return E.jsx("nav",{className:"room-list","aria-label":"Rooms",children:l.map((u,e)=>E.jsx(Ov,{index:e,room:u,selected:u.id===t,onSelect:a},u.id))})}const I1=J.createContext({selectRoom:()=>{},jumpToMessage:()=>{}});function P1(){return J.useContext(I1)}const Ji=-1;var oe,Hl,At,ft,st,wl,uu,cn;class Nv{constructor(t,a,u){Yt(this,uu);Yt(this,oe,void 0);Yt(this,Hl,void 0);Yt(this,At,void 0);Yt(this,ft,void 0);Yt(this,st,void 0);Yt(this,wl,void 0);zl(this,oe,u),zl(this,Hl,t),zl(this,st,a),zl(this,At,new Float64Array(t).fill(Ji)),zl(this,ft,new Float64Array(t+1)),zl(this,wl,a)}get count(){return L(this,Hl)}get first(){return L(this,st)}extendTo(t){t>=L(this,st)||(zl(this,st,t),zl(this,wl,t))}grow(t){if(t<=L(this,Hl))return;const a=new Float64Array(t);a.set(L(this,At)),a.fill(Ji,L(this,Hl));const u=new Float64Array(t+1);u.set(L(this,ft)),zl(this,wl,Math.min(L(this,wl),L(this,Hl))),zl(this,At,a),zl(this,ft,u),zl(this,Hl,t)}heightAt(t){const a=L(this,At)[t];return a===Ji?L(this,oe):a}measure(t,a){return L(this,At)[t]===a?!1:(L(this,At)[t]=a,t>1;a[n]<=t?u=n:e=n-1}return Math.max(L(this,st),u)}}oe=new WeakMap,Hl=new WeakMap,At=new WeakMap,ft=new WeakMap,st=new WeakMap,wl=new WeakMap,uu=new WeakSet,cn=function(){if(L(this,wl)>L(this,Hl))return;const t=L(this,ft);t[L(this,st)]=0;for(let a=L(this,wl);a{i.preventDefault();const c=a.trim();c&&(t(c),u(""))},n=i=>{i.key==="Enter"&&!i.shiftKey&&e(i)};return E.jsxs("form",{className:"composer",onSubmit:e,children:[E.jsx("input",{id:"composer-input",className:"composer-input",type:"text",autoComplete:"off","aria-label":`Message ${l}`,placeholder:`Message #${l.toLowerCase().replace(/ /g,"-")}`,value:a,onChange:i=>u(i.target.value),onKeyDown:n}),E.jsx("button",{id:"composer-send",className:"composer-send",type:"submit",disabled:a.trim().length===0,children:"Send"})]})}function Hv({reaction:l}){const[t,a]=J.useState(!1),u=t?"reaction reaction-mine":"reaction";return E.jsxs("button",{className:u,type:"button","aria-pressed":t,onClick:()=>a(!t),children:[E.jsx("span",{className:"reaction-emoji",children:l.emoji}),E.jsx("span",{className:"reaction-count",children:l.count+(t?1:0)})]})}function Rv({span:l}){const{selectRoom:t}=P1();return E.jsxs("button",{className:"rich-pill rich-pill-room",type:"button",onClick:()=>t(l.roomId),children:["#",l.name]})}function Cv({span:l}){switch(l.type){case"code":return E.jsx("code",{className:"rich-code",children:l.text});case"link":return E.jsx("a",{className:"rich-link",href:l.href,onClick:t=>t.preventDefault(),children:l.text});case"mention":return E.jsxs("span",{className:"rich-pill rich-pill-mention",children:["@",l.name]});case"room":return E.jsx(Rv,{span:l});default:return l.text}}function wi({spans:l}){return l.map((t,a)=>E.jsx(Cv,{span:t},a))}function jv({block:l}){switch(l.type){case"code":return E.jsx("pre",{className:"rich-code-block","data-lang":l.lang,children:E.jsx("code",{children:l.lines.join(` +`)})});case"quote":return E.jsx("blockquote",{className:"rich-quote",children:E.jsx(wi,{spans:l.spans})});case"image":return E.jsx("img",{className:"rich-image",src:l.src,width:l.width,height:l.height,alt:l.alt,decoding:"sync"});case"unfurl":return E.jsxs("a",{className:"rich-unfurl",href:l.href,onClick:t=>t.preventDefault(),children:[E.jsx("img",{className:"rich-unfurl-thumb",src:l.thumbSrc,width:l.thumbWidth,height:l.thumbHeight,alt:"",decoding:"sync"}),E.jsxs("span",{className:"rich-unfurl-body",children:[E.jsx("span",{className:"rich-unfurl-site",children:l.site}),E.jsx("span",{className:"rich-unfurl-title",children:l.title}),E.jsx("span",{className:"rich-unfurl-description",children:l.description})]})]});case"list":return E.jsx("ul",{className:"rich-list",children:l.items.map((t,a)=>E.jsx("li",{children:E.jsx(wi,{spans:t})},a))});default:return E.jsx("p",{className:"rich-paragraph",children:E.jsx(wi,{spans:l.spans})})}}function xv({blocks:l}){return l.map((t,a)=>E.jsx(jv,{block:t},a))}function Bv({index:l,message:t,highlighted:a,dateLabel:u,unreadBelow:e}){const{jumpToMessage:n}=P1(),i=["timeline-message"];return t.grouped&&i.push("timeline-message-grouped"),a&&i.push("timeline-message-highlighted"),E.jsxs("li",{className:i.join(" "),"data-message-id":t.id,"data-index":l,children:[u!==null&&E.jsx("div",{className:"timeline-date-separator",children:E.jsx("span",{className:"timeline-date-separator-label",children:u})}),e&&E.jsx("div",{className:"timeline-unread-divider","aria-label":"Unread messages",children:E.jsx("span",{className:"timeline-unread-divider-label",children:"New"})}),E.jsxs("div",{className:"timeline-message-row",children:[t.grouped?E.jsx("span",{className:"timeline-message-gutter",children:t.time}):E.jsx("span",{className:"avatar",style:{backgroundColor:Wf[t.colorIndex]},children:t.senderInitials}),E.jsxs("div",{className:"timeline-message-body",children:[t.replyTo&&E.jsxs("button",{className:"timeline-message-reply",type:"button",onClick:()=>n(t.replyTo.id),children:[E.jsx("span",{className:"timeline-message-reply-sender",children:t.replyTo.sender}),E.jsx("span",{className:"timeline-message-reply-excerpt",children:t.replyTo.excerpt})]}),!t.grouped&&E.jsxs("div",{className:"timeline-message-meta",children:[E.jsx("span",{className:"timeline-message-sender",children:t.sender}),E.jsx("span",{className:"timeline-message-time",children:t.time})]}),E.jsx("div",{className:"timeline-message-text",children:E.jsx(xv,{blocks:t.blocks})}),t.reactions.length>0&&E.jsx("div",{className:"timeline-message-reactions",children:t.reactions.map(c=>E.jsx(Hv,{reaction:c},c.emoji))})]})]})]})}const $i=4,Yv=100,qv=4,Gv=300,Xv=120;function Qv({room:l,onSelectRoom:t}){const a=J.useRef(null),[u,e]=J.useState(null),[n,i]=J.useState([]),c=J.useMemo(()=>n.length?[...l.messages,...n]:l.messages,[l.messages,n]),f=Math.max(0,l.messages.length-Gv),[h,g]=J.useState(f),y=J.useMemo(()=>new Nv(l.messages.length,f,Yv),[l.messages,f]);y.grow(c.length),y.extendTo(h);const m=J.useMemo(()=>{let _=null;return X=>(_===null&&(_=new Map(c.map((ul,b)=>[ul.id,b]))),_.get(X))},[c]),[v,p]=J.useState({start:0,end:0}),z=J.useRef(!0),j=J.useRef(null),o=J.useRef(null),[,s]=J.useState(0),d=J.useCallback((_,X)=>{const ul=y.indexAt(_),b=_+X;let D=ul;for(;D+1{const ul=y.offsetAt(_)-(X-y.heightAt(_))/2;return Math.max(0,Math.min(ul,y.totalHeight-X))},[y]),A=J.useCallback(_=>{p(X=>X.start===_.start&&X.end===_.end?X:_)},[]),N=J.useCallback(_=>{const X=y.indexAt(_);return{index:X,offset:_-y.offsetAt(X)}},[y]),T=J.useCallback(()=>{const _=a.current;if(z.current=_.scrollHeight-(_.scrollTop+_.clientHeight)<=qv,y.first>0&&_.scrollTop<_.clientHeight){o.current=N(_.scrollTop),g(Math.max(0,y.first-Xv));return}A(d(_.scrollTop,_.clientHeight))},[N,y,d,A]);J.useLayoutEffect(()=>{const _=a.current,X=_.clientHeight,ul=o.current,b=ul??N(_.scrollTop);let D=!1;for(const U of _.querySelectorAll(".timeline-message"))y.measure(Number(U.dataset.index),U.getBoundingClientRect().height)&&(D=!0);if(D){o.current=b,s(U=>U+1);return}o.current=null,j.current!==null?(_.scrollTop=r(j.current,X),j.current=null):z.current?_.scrollTop=_.scrollHeight:ul&&(_.scrollTop=y.offsetAt(ul.index)+ul.offset),A(d(_.scrollTop,X))});const O=J.useCallback(_=>{const X=m(_);if(X===void 0)return;const ul=a.current;e(_),z.current=!1,j.current=X,X({selectRoom:t,jumpToMessage:O}),[t,O]),x=J.useCallback(_=>{z.current=!0,j.current=null,i(X=>[...X,Mv(l,X.length,_)])},[l]),Dl=c[c.length-1].dayIndex,et=[];for(let _=v.start;_0?c[_-1]:null,b=ul===null||ul.dayIndex!==X.dayIndex;et.push(E.jsx(Bv,{index:_,message:X,highlighted:X.id===u,dateLabel:b?vv(X.dayIndex,Dl):null,unreadBelow:_===l.readUpToIndex+1},X.id))}return E.jsxs(I1.Provider,{value:C,children:[E.jsxs("ol",{id:"timeline",className:"timeline",ref:a,onScroll:T,children:[E.jsx("li",{className:"timeline-spacer",style:{height:y.offsetAt(v.start)},"aria-hidden":"true"}),et,E.jsx("li",{className:"timeline-spacer",style:{height:y.totalHeight-y.offsetAt(v.end)},"aria-hidden":"true"})]}),E.jsx(Uv,{roomName:l.name,onSend:x})]})}function Zv(){const[l,t]=J.useState(Vi[0].id),a=Vi.find(e=>e.id===l),u=e=>t(e);return E.jsxs("div",{className:"app",children:[E.jsx(Dv,{rooms:Vi,selectedRoomId:l,onSelect:u}),E.jsxs("main",{className:"room",children:[E.jsxs("header",{className:"room-header",children:[E.jsx("h1",{id:"room-header-name",className:"room-header-name",children:a.name}),E.jsx("p",{className:"room-header-topic",children:a.topic})]}),E.jsx(Qv,{room:a,onSelectRoom:u},a.id)]})]})}Fy.createRoot(document.getElementById("root")).render(E.jsx(Zv,{})); +//# sourceMappingURL=index-381effb6.js.map diff --git a/suites-experimental/chat-room/dist/assets/index-381effb6.js.map b/suites-experimental/chat-room/dist/assets/index-381effb6.js.map new file mode 100644 index 000000000..a429a4016 --- /dev/null +++ b/suites-experimental/chat-room/dist/assets/index-381effb6.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index-381effb6.js","sources":["../../node_modules/react/cjs/react-jsx-runtime.production.js","../../node_modules/react/jsx-runtime.js","../../node_modules/scheduler/cjs/scheduler.production.js","../../node_modules/scheduler/index.js","../../node_modules/react/cjs/react.production.js","../../node_modules/react/index.js","../../node_modules/react-dom/cjs/react-dom.production.js","../../node_modules/react-dom/index.js","../../node_modules/react-dom/cjs/react-dom-client.production.js","../../node_modules/react-dom/client.js","../../src/data/graphics.js","../../src/data/rooms.js","../../src/components/room-list-item.jsx","../../src/components/room-list.jsx","../../src/actions.js","../../src/row-heights.js","../../src/components/composer.jsx","../../src/components/reaction.jsx","../../src/components/rich-text.jsx","../../src/components/message.jsx","../../src/components/timeline.jsx","../../src/App.jsx","../../src/main.jsx"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\");\nfunction jsxProd(type, config, maybeKey) {\n var key = null;\n void 0 !== maybeKey && (key = \"\" + maybeKey);\n void 0 !== config.key && (key = \"\" + config.key);\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n config = maybeKey.ref;\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n ref: void 0 !== config ? config : null,\n props: maybeKey\n };\n}\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.jsx = jsxProd;\nexports.jsxs = jsxProd;\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\n}\n","/**\n * @license React\n * scheduler.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nfunction push(heap, node) {\n var index = heap.length;\n heap.push(node);\n a: for (; 0 < index; ) {\n var parentIndex = (index - 1) >>> 1,\n parent = heap[parentIndex];\n if (0 < compare(parent, node))\n (heap[parentIndex] = node), (heap[index] = parent), (index = parentIndex);\n else break a;\n }\n}\nfunction peek(heap) {\n return 0 === heap.length ? null : heap[0];\n}\nfunction pop(heap) {\n if (0 === heap.length) return null;\n var first = heap[0],\n last = heap.pop();\n if (last !== first) {\n heap[0] = last;\n a: for (\n var index = 0, length = heap.length, halfLength = length >>> 1;\n index < halfLength;\n\n ) {\n var leftIndex = 2 * (index + 1) - 1,\n left = heap[leftIndex],\n rightIndex = leftIndex + 1,\n right = heap[rightIndex];\n if (0 > compare(left, last))\n rightIndex < length && 0 > compare(right, left)\n ? ((heap[index] = right),\n (heap[rightIndex] = last),\n (index = rightIndex))\n : ((heap[index] = left),\n (heap[leftIndex] = last),\n (index = leftIndex));\n else if (rightIndex < length && 0 > compare(right, last))\n (heap[index] = right), (heap[rightIndex] = last), (index = rightIndex);\n else break a;\n }\n }\n return first;\n}\nfunction compare(a, b) {\n var diff = a.sortIndex - b.sortIndex;\n return 0 !== diff ? diff : a.id - b.id;\n}\nexports.unstable_now = void 0;\nif (\"object\" === typeof performance && \"function\" === typeof performance.now) {\n var localPerformance = performance;\n exports.unstable_now = function () {\n return localPerformance.now();\n };\n} else {\n var localDate = Date,\n initialTime = localDate.now();\n exports.unstable_now = function () {\n return localDate.now() - initialTime;\n };\n}\nvar taskQueue = [],\n timerQueue = [],\n taskIdCounter = 1,\n currentTask = null,\n currentPriorityLevel = 3,\n isPerformingWork = !1,\n isHostCallbackScheduled = !1,\n isHostTimeoutScheduled = !1,\n needsPaint = !1,\n localSetTimeout = \"function\" === typeof setTimeout ? setTimeout : null,\n localClearTimeout = \"function\" === typeof clearTimeout ? clearTimeout : null,\n localSetImmediate = \"undefined\" !== typeof setImmediate ? setImmediate : null;\nfunction advanceTimers(currentTime) {\n for (var timer = peek(timerQueue); null !== timer; ) {\n if (null === timer.callback) pop(timerQueue);\n else if (timer.startTime <= currentTime)\n pop(timerQueue),\n (timer.sortIndex = timer.expirationTime),\n push(taskQueue, timer);\n else break;\n timer = peek(timerQueue);\n }\n}\nfunction handleTimeout(currentTime) {\n isHostTimeoutScheduled = !1;\n advanceTimers(currentTime);\n if (!isHostCallbackScheduled)\n if (null !== peek(taskQueue))\n (isHostCallbackScheduled = !0),\n isMessageLoopRunning ||\n ((isMessageLoopRunning = !0), schedulePerformWorkUntilDeadline());\n else {\n var firstTimer = peek(timerQueue);\n null !== firstTimer &&\n requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);\n }\n}\nvar isMessageLoopRunning = !1,\n taskTimeoutID = -1,\n frameInterval = 5,\n startTime = -1;\nfunction shouldYieldToHost() {\n return needsPaint\n ? !0\n : exports.unstable_now() - startTime < frameInterval\n ? !1\n : !0;\n}\nfunction performWorkUntilDeadline() {\n needsPaint = !1;\n if (isMessageLoopRunning) {\n var currentTime = exports.unstable_now();\n startTime = currentTime;\n var hasMoreWork = !0;\n try {\n a: {\n isHostCallbackScheduled = !1;\n isHostTimeoutScheduled &&\n ((isHostTimeoutScheduled = !1),\n localClearTimeout(taskTimeoutID),\n (taskTimeoutID = -1));\n isPerformingWork = !0;\n var previousPriorityLevel = currentPriorityLevel;\n try {\n b: {\n advanceTimers(currentTime);\n for (\n currentTask = peek(taskQueue);\n null !== currentTask &&\n !(\n currentTask.expirationTime > currentTime && shouldYieldToHost()\n );\n\n ) {\n var callback = currentTask.callback;\n if (\"function\" === typeof callback) {\n currentTask.callback = null;\n currentPriorityLevel = currentTask.priorityLevel;\n var continuationCallback = callback(\n currentTask.expirationTime <= currentTime\n );\n currentTime = exports.unstable_now();\n if (\"function\" === typeof continuationCallback) {\n currentTask.callback = continuationCallback;\n advanceTimers(currentTime);\n hasMoreWork = !0;\n break b;\n }\n currentTask === peek(taskQueue) && pop(taskQueue);\n advanceTimers(currentTime);\n } else pop(taskQueue);\n currentTask = peek(taskQueue);\n }\n if (null !== currentTask) hasMoreWork = !0;\n else {\n var firstTimer = peek(timerQueue);\n null !== firstTimer &&\n requestHostTimeout(\n handleTimeout,\n firstTimer.startTime - currentTime\n );\n hasMoreWork = !1;\n }\n }\n break a;\n } finally {\n (currentTask = null),\n (currentPriorityLevel = previousPriorityLevel),\n (isPerformingWork = !1);\n }\n hasMoreWork = void 0;\n }\n } finally {\n hasMoreWork\n ? schedulePerformWorkUntilDeadline()\n : (isMessageLoopRunning = !1);\n }\n }\n}\nvar schedulePerformWorkUntilDeadline;\nif (\"function\" === typeof localSetImmediate)\n schedulePerformWorkUntilDeadline = function () {\n localSetImmediate(performWorkUntilDeadline);\n };\nelse if (\"undefined\" !== typeof MessageChannel) {\n var channel = new MessageChannel(),\n port = channel.port2;\n channel.port1.onmessage = performWorkUntilDeadline;\n schedulePerformWorkUntilDeadline = function () {\n port.postMessage(null);\n };\n} else\n schedulePerformWorkUntilDeadline = function () {\n localSetTimeout(performWorkUntilDeadline, 0);\n };\nfunction requestHostTimeout(callback, ms) {\n taskTimeoutID = localSetTimeout(function () {\n callback(exports.unstable_now());\n }, ms);\n}\nexports.unstable_IdlePriority = 5;\nexports.unstable_ImmediatePriority = 1;\nexports.unstable_LowPriority = 4;\nexports.unstable_NormalPriority = 3;\nexports.unstable_Profiling = null;\nexports.unstable_UserBlockingPriority = 2;\nexports.unstable_cancelCallback = function (task) {\n task.callback = null;\n};\nexports.unstable_forceFrameRate = function (fps) {\n 0 > fps || 125 < fps\n ? console.error(\n \"forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported\"\n )\n : (frameInterval = 0 < fps ? Math.floor(1e3 / fps) : 5);\n};\nexports.unstable_getCurrentPriorityLevel = function () {\n return currentPriorityLevel;\n};\nexports.unstable_next = function (eventHandler) {\n switch (currentPriorityLevel) {\n case 1:\n case 2:\n case 3:\n var priorityLevel = 3;\n break;\n default:\n priorityLevel = currentPriorityLevel;\n }\n var previousPriorityLevel = currentPriorityLevel;\n currentPriorityLevel = priorityLevel;\n try {\n return eventHandler();\n } finally {\n currentPriorityLevel = previousPriorityLevel;\n }\n};\nexports.unstable_requestPaint = function () {\n needsPaint = !0;\n};\nexports.unstable_runWithPriority = function (priorityLevel, eventHandler) {\n switch (priorityLevel) {\n case 1:\n case 2:\n case 3:\n case 4:\n case 5:\n break;\n default:\n priorityLevel = 3;\n }\n var previousPriorityLevel = currentPriorityLevel;\n currentPriorityLevel = priorityLevel;\n try {\n return eventHandler();\n } finally {\n currentPriorityLevel = previousPriorityLevel;\n }\n};\nexports.unstable_scheduleCallback = function (\n priorityLevel,\n callback,\n options\n) {\n var currentTime = exports.unstable_now();\n \"object\" === typeof options && null !== options\n ? ((options = options.delay),\n (options =\n \"number\" === typeof options && 0 < options\n ? currentTime + options\n : currentTime))\n : (options = currentTime);\n switch (priorityLevel) {\n case 1:\n var timeout = -1;\n break;\n case 2:\n timeout = 250;\n break;\n case 5:\n timeout = 1073741823;\n break;\n case 4:\n timeout = 1e4;\n break;\n default:\n timeout = 5e3;\n }\n timeout = options + timeout;\n priorityLevel = {\n id: taskIdCounter++,\n callback: callback,\n priorityLevel: priorityLevel,\n startTime: options,\n expirationTime: timeout,\n sortIndex: -1\n };\n options > currentTime\n ? ((priorityLevel.sortIndex = options),\n push(timerQueue, priorityLevel),\n null === peek(taskQueue) &&\n priorityLevel === peek(timerQueue) &&\n (isHostTimeoutScheduled\n ? (localClearTimeout(taskTimeoutID), (taskTimeoutID = -1))\n : (isHostTimeoutScheduled = !0),\n requestHostTimeout(handleTimeout, options - currentTime)))\n : ((priorityLevel.sortIndex = timeout),\n push(taskQueue, priorityLevel),\n isHostCallbackScheduled ||\n isPerformingWork ||\n ((isHostCallbackScheduled = !0),\n isMessageLoopRunning ||\n ((isMessageLoopRunning = !0), schedulePerformWorkUntilDeadline())));\n return priorityLevel;\n};\nexports.unstable_shouldYield = shouldYieldToHost;\nexports.unstable_wrapCallback = function (callback) {\n var parentPriorityLevel = currentPriorityLevel;\n return function () {\n var previousPriorityLevel = currentPriorityLevel;\n currentPriorityLevel = parentPriorityLevel;\n try {\n return callback.apply(this, arguments);\n } finally {\n currentPriorityLevel = previousPriorityLevel;\n }\n };\n};\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/scheduler.production.js');\n} else {\n module.exports = require('./cjs/scheduler.development.js');\n}\n","/**\n * @license React\n * react.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\"),\n REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\"),\n REACT_ACTIVITY_TYPE = Symbol.for(\"react.activity\"),\n MAYBE_ITERATOR_SYMBOL = Symbol.iterator;\nfunction getIteratorFn(maybeIterable) {\n if (null === maybeIterable || \"object\" !== typeof maybeIterable) return null;\n maybeIterable =\n (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) ||\n maybeIterable[\"@@iterator\"];\n return \"function\" === typeof maybeIterable ? maybeIterable : null;\n}\nvar ReactNoopUpdateQueue = {\n isMounted: function () {\n return !1;\n },\n enqueueForceUpdate: function () {},\n enqueueReplaceState: function () {},\n enqueueSetState: function () {}\n },\n assign = Object.assign,\n emptyObject = {};\nfunction Component(props, context, updater) {\n this.props = props;\n this.context = context;\n this.refs = emptyObject;\n this.updater = updater || ReactNoopUpdateQueue;\n}\nComponent.prototype.isReactComponent = {};\nComponent.prototype.setState = function (partialState, callback) {\n if (\n \"object\" !== typeof partialState &&\n \"function\" !== typeof partialState &&\n null != partialState\n )\n throw Error(\n \"takes an object of state variables to update or a function which returns an object of state variables.\"\n );\n this.updater.enqueueSetState(this, partialState, callback, \"setState\");\n};\nComponent.prototype.forceUpdate = function (callback) {\n this.updater.enqueueForceUpdate(this, callback, \"forceUpdate\");\n};\nfunction ComponentDummy() {}\nComponentDummy.prototype = Component.prototype;\nfunction PureComponent(props, context, updater) {\n this.props = props;\n this.context = context;\n this.refs = emptyObject;\n this.updater = updater || ReactNoopUpdateQueue;\n}\nvar pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());\npureComponentPrototype.constructor = PureComponent;\nassign(pureComponentPrototype, Component.prototype);\npureComponentPrototype.isPureReactComponent = !0;\nvar isArrayImpl = Array.isArray;\nfunction noop() {}\nvar ReactSharedInternals = { H: null, A: null, T: null, S: null },\n hasOwnProperty = Object.prototype.hasOwnProperty;\nfunction ReactElement(type, key, props) {\n var refProp = props.ref;\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n ref: void 0 !== refProp ? refProp : null,\n props: props\n };\n}\nfunction cloneAndReplaceKey(oldElement, newKey) {\n return ReactElement(oldElement.type, newKey, oldElement.props);\n}\nfunction isValidElement(object) {\n return (\n \"object\" === typeof object &&\n null !== object &&\n object.$$typeof === REACT_ELEMENT_TYPE\n );\n}\nfunction escape(key) {\n var escaperLookup = { \"=\": \"=0\", \":\": \"=2\" };\n return (\n \"$\" +\n key.replace(/[=:]/g, function (match) {\n return escaperLookup[match];\n })\n );\n}\nvar userProvidedKeyEscapeRegex = /\\/+/g;\nfunction getElementKey(element, index) {\n return \"object\" === typeof element && null !== element && null != element.key\n ? escape(\"\" + element.key)\n : index.toString(36);\n}\nfunction resolveThenable(thenable) {\n switch (thenable.status) {\n case \"fulfilled\":\n return thenable.value;\n case \"rejected\":\n throw thenable.reason;\n default:\n switch (\n (\"string\" === typeof thenable.status\n ? thenable.then(noop, noop)\n : ((thenable.status = \"pending\"),\n thenable.then(\n function (fulfilledValue) {\n \"pending\" === thenable.status &&\n ((thenable.status = \"fulfilled\"),\n (thenable.value = fulfilledValue));\n },\n function (error) {\n \"pending\" === thenable.status &&\n ((thenable.status = \"rejected\"), (thenable.reason = error));\n }\n )),\n thenable.status)\n ) {\n case \"fulfilled\":\n return thenable.value;\n case \"rejected\":\n throw thenable.reason;\n }\n }\n throw thenable;\n}\nfunction mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {\n var type = typeof children;\n if (\"undefined\" === type || \"boolean\" === type) children = null;\n var invokeCallback = !1;\n if (null === children) invokeCallback = !0;\n else\n switch (type) {\n case \"bigint\":\n case \"string\":\n case \"number\":\n invokeCallback = !0;\n break;\n case \"object\":\n switch (children.$$typeof) {\n case REACT_ELEMENT_TYPE:\n case REACT_PORTAL_TYPE:\n invokeCallback = !0;\n break;\n case REACT_LAZY_TYPE:\n return (\n (invokeCallback = children._init),\n mapIntoArray(\n invokeCallback(children._payload),\n array,\n escapedPrefix,\n nameSoFar,\n callback\n )\n );\n }\n }\n if (invokeCallback)\n return (\n (callback = callback(children)),\n (invokeCallback =\n \"\" === nameSoFar ? \".\" + getElementKey(children, 0) : nameSoFar),\n isArrayImpl(callback)\n ? ((escapedPrefix = \"\"),\n null != invokeCallback &&\n (escapedPrefix =\n invokeCallback.replace(userProvidedKeyEscapeRegex, \"$&/\") + \"/\"),\n mapIntoArray(callback, array, escapedPrefix, \"\", function (c) {\n return c;\n }))\n : null != callback &&\n (isValidElement(callback) &&\n (callback = cloneAndReplaceKey(\n callback,\n escapedPrefix +\n (null == callback.key ||\n (children && children.key === callback.key)\n ? \"\"\n : (\"\" + callback.key).replace(\n userProvidedKeyEscapeRegex,\n \"$&/\"\n ) + \"/\") +\n invokeCallback\n )),\n array.push(callback)),\n 1\n );\n invokeCallback = 0;\n var nextNamePrefix = \"\" === nameSoFar ? \".\" : nameSoFar + \":\";\n if (isArrayImpl(children))\n for (var i = 0; i < children.length; i++)\n (nameSoFar = children[i]),\n (type = nextNamePrefix + getElementKey(nameSoFar, i)),\n (invokeCallback += mapIntoArray(\n nameSoFar,\n array,\n escapedPrefix,\n type,\n callback\n ));\n else if (((i = getIteratorFn(children)), \"function\" === typeof i))\n for (\n children = i.call(children), i = 0;\n !(nameSoFar = children.next()).done;\n\n )\n (nameSoFar = nameSoFar.value),\n (type = nextNamePrefix + getElementKey(nameSoFar, i++)),\n (invokeCallback += mapIntoArray(\n nameSoFar,\n array,\n escapedPrefix,\n type,\n callback\n ));\n else if (\"object\" === type) {\n if (\"function\" === typeof children.then)\n return mapIntoArray(\n resolveThenable(children),\n array,\n escapedPrefix,\n nameSoFar,\n callback\n );\n array = String(children);\n throw Error(\n \"Objects are not valid as a React child (found: \" +\n (\"[object Object]\" === array\n ? \"object with keys {\" + Object.keys(children).join(\", \") + \"}\"\n : array) +\n \"). If you meant to render a collection of children, use an array instead.\"\n );\n }\n return invokeCallback;\n}\nfunction mapChildren(children, func, context) {\n if (null == children) return children;\n var result = [],\n count = 0;\n mapIntoArray(children, result, \"\", \"\", function (child) {\n return func.call(context, child, count++);\n });\n return result;\n}\nfunction lazyInitializer(payload) {\n if (-1 === payload._status) {\n var ctor = payload._result;\n ctor = ctor();\n ctor.then(\n function (moduleObject) {\n if (0 === payload._status || -1 === payload._status)\n (payload._status = 1), (payload._result = moduleObject);\n },\n function (error) {\n if (0 === payload._status || -1 === payload._status)\n (payload._status = 2), (payload._result = error);\n }\n );\n -1 === payload._status && ((payload._status = 0), (payload._result = ctor));\n }\n if (1 === payload._status) return payload._result.default;\n throw payload._result;\n}\nvar reportGlobalError =\n \"function\" === typeof reportError\n ? reportError\n : function (error) {\n if (\n \"object\" === typeof window &&\n \"function\" === typeof window.ErrorEvent\n ) {\n var event = new window.ErrorEvent(\"error\", {\n bubbles: !0,\n cancelable: !0,\n message:\n \"object\" === typeof error &&\n null !== error &&\n \"string\" === typeof error.message\n ? String(error.message)\n : String(error),\n error: error\n });\n if (!window.dispatchEvent(event)) return;\n } else if (\n \"object\" === typeof process &&\n \"function\" === typeof process.emit\n ) {\n process.emit(\"uncaughtException\", error);\n return;\n }\n console.error(error);\n },\n Children = {\n map: mapChildren,\n forEach: function (children, forEachFunc, forEachContext) {\n mapChildren(\n children,\n function () {\n forEachFunc.apply(this, arguments);\n },\n forEachContext\n );\n },\n count: function (children) {\n var n = 0;\n mapChildren(children, function () {\n n++;\n });\n return n;\n },\n toArray: function (children) {\n return (\n mapChildren(children, function (child) {\n return child;\n }) || []\n );\n },\n only: function (children) {\n if (!isValidElement(children))\n throw Error(\n \"React.Children.only expected to receive a single React element child.\"\n );\n return children;\n }\n };\nexports.Activity = REACT_ACTIVITY_TYPE;\nexports.Children = Children;\nexports.Component = Component;\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.Profiler = REACT_PROFILER_TYPE;\nexports.PureComponent = PureComponent;\nexports.StrictMode = REACT_STRICT_MODE_TYPE;\nexports.Suspense = REACT_SUSPENSE_TYPE;\nexports.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE =\n ReactSharedInternals;\nexports.__COMPILER_RUNTIME = {\n __proto__: null,\n c: function (size) {\n return ReactSharedInternals.H.useMemoCache(size);\n }\n};\nexports.cache = function (fn) {\n return function () {\n return fn.apply(null, arguments);\n };\n};\nexports.cacheSignal = function () {\n return null;\n};\nexports.cloneElement = function (element, config, children) {\n if (null === element || void 0 === element)\n throw Error(\n \"The argument must be a React element, but you passed \" + element + \".\"\n );\n var props = assign({}, element.props),\n key = element.key;\n if (null != config)\n for (propName in (void 0 !== config.key && (key = \"\" + config.key), config))\n !hasOwnProperty.call(config, propName) ||\n \"key\" === propName ||\n \"__self\" === propName ||\n \"__source\" === propName ||\n (\"ref\" === propName && void 0 === config.ref) ||\n (props[propName] = config[propName]);\n var propName = arguments.length - 2;\n if (1 === propName) props.children = children;\n else if (1 < propName) {\n for (var childArray = Array(propName), i = 0; i < propName; i++)\n childArray[i] = arguments[i + 2];\n props.children = childArray;\n }\n return ReactElement(element.type, key, props);\n};\nexports.createContext = function (defaultValue) {\n defaultValue = {\n $$typeof: REACT_CONTEXT_TYPE,\n _currentValue: defaultValue,\n _currentValue2: defaultValue,\n _threadCount: 0,\n Provider: null,\n Consumer: null\n };\n defaultValue.Provider = defaultValue;\n defaultValue.Consumer = {\n $$typeof: REACT_CONSUMER_TYPE,\n _context: defaultValue\n };\n return defaultValue;\n};\nexports.createElement = function (type, config, children) {\n var propName,\n props = {},\n key = null;\n if (null != config)\n for (propName in (void 0 !== config.key && (key = \"\" + config.key), config))\n hasOwnProperty.call(config, propName) &&\n \"key\" !== propName &&\n \"__self\" !== propName &&\n \"__source\" !== propName &&\n (props[propName] = config[propName]);\n var childrenLength = arguments.length - 2;\n if (1 === childrenLength) props.children = children;\n else if (1 < childrenLength) {\n for (var childArray = Array(childrenLength), i = 0; i < childrenLength; i++)\n childArray[i] = arguments[i + 2];\n props.children = childArray;\n }\n if (type && type.defaultProps)\n for (propName in ((childrenLength = type.defaultProps), childrenLength))\n void 0 === props[propName] &&\n (props[propName] = childrenLength[propName]);\n return ReactElement(type, key, props);\n};\nexports.createRef = function () {\n return { current: null };\n};\nexports.forwardRef = function (render) {\n return { $$typeof: REACT_FORWARD_REF_TYPE, render: render };\n};\nexports.isValidElement = isValidElement;\nexports.lazy = function (ctor) {\n return {\n $$typeof: REACT_LAZY_TYPE,\n _payload: { _status: -1, _result: ctor },\n _init: lazyInitializer\n };\n};\nexports.memo = function (type, compare) {\n return {\n $$typeof: REACT_MEMO_TYPE,\n type: type,\n compare: void 0 === compare ? null : compare\n };\n};\nexports.startTransition = function (scope) {\n var prevTransition = ReactSharedInternals.T,\n currentTransition = {};\n ReactSharedInternals.T = currentTransition;\n try {\n var returnValue = scope(),\n onStartTransitionFinish = ReactSharedInternals.S;\n null !== onStartTransitionFinish &&\n onStartTransitionFinish(currentTransition, returnValue);\n \"object\" === typeof returnValue &&\n null !== returnValue &&\n \"function\" === typeof returnValue.then &&\n returnValue.then(noop, reportGlobalError);\n } catch (error) {\n reportGlobalError(error);\n } finally {\n null !== prevTransition &&\n null !== currentTransition.types &&\n (prevTransition.types = currentTransition.types),\n (ReactSharedInternals.T = prevTransition);\n }\n};\nexports.unstable_useCacheRefresh = function () {\n return ReactSharedInternals.H.useCacheRefresh();\n};\nexports.use = function (usable) {\n return ReactSharedInternals.H.use(usable);\n};\nexports.useActionState = function (action, initialState, permalink) {\n return ReactSharedInternals.H.useActionState(action, initialState, permalink);\n};\nexports.useCallback = function (callback, deps) {\n return ReactSharedInternals.H.useCallback(callback, deps);\n};\nexports.useContext = function (Context) {\n return ReactSharedInternals.H.useContext(Context);\n};\nexports.useDebugValue = function () {};\nexports.useDeferredValue = function (value, initialValue) {\n return ReactSharedInternals.H.useDeferredValue(value, initialValue);\n};\nexports.useEffect = function (create, deps) {\n return ReactSharedInternals.H.useEffect(create, deps);\n};\nexports.useEffectEvent = function (callback) {\n return ReactSharedInternals.H.useEffectEvent(callback);\n};\nexports.useId = function () {\n return ReactSharedInternals.H.useId();\n};\nexports.useImperativeHandle = function (ref, create, deps) {\n return ReactSharedInternals.H.useImperativeHandle(ref, create, deps);\n};\nexports.useInsertionEffect = function (create, deps) {\n return ReactSharedInternals.H.useInsertionEffect(create, deps);\n};\nexports.useLayoutEffect = function (create, deps) {\n return ReactSharedInternals.H.useLayoutEffect(create, deps);\n};\nexports.useMemo = function (create, deps) {\n return ReactSharedInternals.H.useMemo(create, deps);\n};\nexports.useOptimistic = function (passthrough, reducer) {\n return ReactSharedInternals.H.useOptimistic(passthrough, reducer);\n};\nexports.useReducer = function (reducer, initialArg, init) {\n return ReactSharedInternals.H.useReducer(reducer, initialArg, init);\n};\nexports.useRef = function (initialValue) {\n return ReactSharedInternals.H.useRef(initialValue);\n};\nexports.useState = function (initialState) {\n return ReactSharedInternals.H.useState(initialState);\n};\nexports.useSyncExternalStore = function (\n subscribe,\n getSnapshot,\n getServerSnapshot\n) {\n return ReactSharedInternals.H.useSyncExternalStore(\n subscribe,\n getSnapshot,\n getServerSnapshot\n );\n};\nexports.useTransition = function () {\n return ReactSharedInternals.H.useTransition();\n};\nexports.version = \"19.2.8\";\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react.production.js');\n} else {\n module.exports = require('./cjs/react.development.js');\n}\n","/**\n * @license React\n * react-dom.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar React = require(\"react\");\nfunction formatProdErrorMessage(code) {\n var url = \"https://react.dev/errors/\" + code;\n if (1 < arguments.length) {\n url += \"?args[]=\" + encodeURIComponent(arguments[1]);\n for (var i = 2; i < arguments.length; i++)\n url += \"&args[]=\" + encodeURIComponent(arguments[i]);\n }\n return (\n \"Minified React error #\" +\n code +\n \"; visit \" +\n url +\n \" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"\n );\n}\nfunction noop() {}\nvar Internals = {\n d: {\n f: noop,\n r: function () {\n throw Error(formatProdErrorMessage(522));\n },\n D: noop,\n C: noop,\n L: noop,\n m: noop,\n X: noop,\n S: noop,\n M: noop\n },\n p: 0,\n findDOMNode: null\n },\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\");\nfunction createPortal$1(children, containerInfo, implementation) {\n var key =\n 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null;\n return {\n $$typeof: REACT_PORTAL_TYPE,\n key: null == key ? null : \"\" + key,\n children: children,\n containerInfo: containerInfo,\n implementation: implementation\n };\n}\nvar ReactSharedInternals =\n React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;\nfunction getCrossOriginStringAs(as, input) {\n if (\"font\" === as) return \"\";\n if (\"string\" === typeof input)\n return \"use-credentials\" === input ? input : \"\";\n}\nexports.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE =\n Internals;\nexports.createPortal = function (children, container) {\n var key =\n 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null;\n if (\n !container ||\n (1 !== container.nodeType &&\n 9 !== container.nodeType &&\n 11 !== container.nodeType)\n )\n throw Error(formatProdErrorMessage(299));\n return createPortal$1(children, container, null, key);\n};\nexports.flushSync = function (fn) {\n var previousTransition = ReactSharedInternals.T,\n previousUpdatePriority = Internals.p;\n try {\n if (((ReactSharedInternals.T = null), (Internals.p = 2), fn)) return fn();\n } finally {\n (ReactSharedInternals.T = previousTransition),\n (Internals.p = previousUpdatePriority),\n Internals.d.f();\n }\n};\nexports.preconnect = function (href, options) {\n \"string\" === typeof href &&\n (options\n ? ((options = options.crossOrigin),\n (options =\n \"string\" === typeof options\n ? \"use-credentials\" === options\n ? options\n : \"\"\n : void 0))\n : (options = null),\n Internals.d.C(href, options));\n};\nexports.prefetchDNS = function (href) {\n \"string\" === typeof href && Internals.d.D(href);\n};\nexports.preinit = function (href, options) {\n if (\"string\" === typeof href && options && \"string\" === typeof options.as) {\n var as = options.as,\n crossOrigin = getCrossOriginStringAs(as, options.crossOrigin),\n integrity =\n \"string\" === typeof options.integrity ? options.integrity : void 0,\n fetchPriority =\n \"string\" === typeof options.fetchPriority\n ? options.fetchPriority\n : void 0;\n \"style\" === as\n ? Internals.d.S(\n href,\n \"string\" === typeof options.precedence ? options.precedence : void 0,\n {\n crossOrigin: crossOrigin,\n integrity: integrity,\n fetchPriority: fetchPriority\n }\n )\n : \"script\" === as &&\n Internals.d.X(href, {\n crossOrigin: crossOrigin,\n integrity: integrity,\n fetchPriority: fetchPriority,\n nonce: \"string\" === typeof options.nonce ? options.nonce : void 0\n });\n }\n};\nexports.preinitModule = function (href, options) {\n if (\"string\" === typeof href)\n if (\"object\" === typeof options && null !== options) {\n if (null == options.as || \"script\" === options.as) {\n var crossOrigin = getCrossOriginStringAs(\n options.as,\n options.crossOrigin\n );\n Internals.d.M(href, {\n crossOrigin: crossOrigin,\n integrity:\n \"string\" === typeof options.integrity ? options.integrity : void 0,\n nonce: \"string\" === typeof options.nonce ? options.nonce : void 0\n });\n }\n } else null == options && Internals.d.M(href);\n};\nexports.preload = function (href, options) {\n if (\n \"string\" === typeof href &&\n \"object\" === typeof options &&\n null !== options &&\n \"string\" === typeof options.as\n ) {\n var as = options.as,\n crossOrigin = getCrossOriginStringAs(as, options.crossOrigin);\n Internals.d.L(href, as, {\n crossOrigin: crossOrigin,\n integrity:\n \"string\" === typeof options.integrity ? options.integrity : void 0,\n nonce: \"string\" === typeof options.nonce ? options.nonce : void 0,\n type: \"string\" === typeof options.type ? options.type : void 0,\n fetchPriority:\n \"string\" === typeof options.fetchPriority\n ? options.fetchPriority\n : void 0,\n referrerPolicy:\n \"string\" === typeof options.referrerPolicy\n ? options.referrerPolicy\n : void 0,\n imageSrcSet:\n \"string\" === typeof options.imageSrcSet ? options.imageSrcSet : void 0,\n imageSizes:\n \"string\" === typeof options.imageSizes ? options.imageSizes : void 0,\n media: \"string\" === typeof options.media ? options.media : void 0\n });\n }\n};\nexports.preloadModule = function (href, options) {\n if (\"string\" === typeof href)\n if (options) {\n var crossOrigin = getCrossOriginStringAs(options.as, options.crossOrigin);\n Internals.d.m(href, {\n as:\n \"string\" === typeof options.as && \"script\" !== options.as\n ? options.as\n : void 0,\n crossOrigin: crossOrigin,\n integrity:\n \"string\" === typeof options.integrity ? options.integrity : void 0\n });\n } else Internals.d.m(href);\n};\nexports.requestFormReset = function (form) {\n Internals.d.r(form);\n};\nexports.unstable_batchedUpdates = function (fn, a) {\n return fn(a);\n};\nexports.useFormState = function (action, initialState, permalink) {\n return ReactSharedInternals.H.useFormState(action, initialState, permalink);\n};\nexports.useFormStatus = function () {\n return ReactSharedInternals.H.useHostTransitionStatus();\n};\nexports.version = \"19.2.8\";\n","'use strict';\n\nfunction checkDCE() {\n /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */\n if (\n typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' ||\n typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== 'function'\n ) {\n return;\n }\n if (process.env.NODE_ENV !== 'production') {\n // This branch is unreachable because this function is only called\n // in production, but the condition is true only in development.\n // Therefore if the branch is still here, dead code elimination wasn't\n // properly applied.\n // Don't change the message. React DevTools relies on it. Also make sure\n // this message doesn't occur elsewhere in this function, or it will cause\n // a false positive.\n throw new Error('^_^');\n }\n try {\n // Verify that the code above has been dead code eliminated (DCE'd).\n __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE);\n } catch (err) {\n // DevTools shouldn't crash React, no matter what.\n // We should still report in case we break this code.\n console.error(err);\n }\n}\n\nif (process.env.NODE_ENV === 'production') {\n // DCE check should happen before ReactDOM bundle executes so that\n // DevTools can report bad minification during injection.\n checkDCE();\n module.exports = require('./cjs/react-dom.production.js');\n} else {\n module.exports = require('./cjs/react-dom.development.js');\n}\n","/**\n * @license React\n * react-dom-client.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n/*\n Modernizr 3.0.0pre (Custom Build) | MIT\n*/\n\"use strict\";\nvar Scheduler = require(\"scheduler\"),\n React = require(\"react\"),\n ReactDOM = require(\"react-dom\");\nfunction formatProdErrorMessage(code) {\n var url = \"https://react.dev/errors/\" + code;\n if (1 < arguments.length) {\n url += \"?args[]=\" + encodeURIComponent(arguments[1]);\n for (var i = 2; i < arguments.length; i++)\n url += \"&args[]=\" + encodeURIComponent(arguments[i]);\n }\n return (\n \"Minified React error #\" +\n code +\n \"; visit \" +\n url +\n \" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"\n );\n}\nfunction isValidContainer(node) {\n return !(\n !node ||\n (1 !== node.nodeType && 9 !== node.nodeType && 11 !== node.nodeType)\n );\n}\nfunction getNearestMountedFiber(fiber) {\n var node = fiber,\n nearestMounted = fiber;\n if (fiber.alternate) for (; node.return; ) node = node.return;\n else {\n fiber = node;\n do\n (node = fiber),\n 0 !== (node.flags & 4098) && (nearestMounted = node.return),\n (fiber = node.return);\n while (fiber);\n }\n return 3 === node.tag ? nearestMounted : null;\n}\nfunction getSuspenseInstanceFromFiber(fiber) {\n if (13 === fiber.tag) {\n var suspenseState = fiber.memoizedState;\n null === suspenseState &&\n ((fiber = fiber.alternate),\n null !== fiber && (suspenseState = fiber.memoizedState));\n if (null !== suspenseState) return suspenseState.dehydrated;\n }\n return null;\n}\nfunction getActivityInstanceFromFiber(fiber) {\n if (31 === fiber.tag) {\n var activityState = fiber.memoizedState;\n null === activityState &&\n ((fiber = fiber.alternate),\n null !== fiber && (activityState = fiber.memoizedState));\n if (null !== activityState) return activityState.dehydrated;\n }\n return null;\n}\nfunction assertIsMounted(fiber) {\n if (getNearestMountedFiber(fiber) !== fiber)\n throw Error(formatProdErrorMessage(188));\n}\nfunction findCurrentFiberUsingSlowPath(fiber) {\n var alternate = fiber.alternate;\n if (!alternate) {\n alternate = getNearestMountedFiber(fiber);\n if (null === alternate) throw Error(formatProdErrorMessage(188));\n return alternate !== fiber ? null : fiber;\n }\n for (var a = fiber, b = alternate; ; ) {\n var parentA = a.return;\n if (null === parentA) break;\n var parentB = parentA.alternate;\n if (null === parentB) {\n b = parentA.return;\n if (null !== b) {\n a = b;\n continue;\n }\n break;\n }\n if (parentA.child === parentB.child) {\n for (parentB = parentA.child; parentB; ) {\n if (parentB === a) return assertIsMounted(parentA), fiber;\n if (parentB === b) return assertIsMounted(parentA), alternate;\n parentB = parentB.sibling;\n }\n throw Error(formatProdErrorMessage(188));\n }\n if (a.return !== b.return) (a = parentA), (b = parentB);\n else {\n for (var didFindChild = !1, child$0 = parentA.child; child$0; ) {\n if (child$0 === a) {\n didFindChild = !0;\n a = parentA;\n b = parentB;\n break;\n }\n if (child$0 === b) {\n didFindChild = !0;\n b = parentA;\n a = parentB;\n break;\n }\n child$0 = child$0.sibling;\n }\n if (!didFindChild) {\n for (child$0 = parentB.child; child$0; ) {\n if (child$0 === a) {\n didFindChild = !0;\n a = parentB;\n b = parentA;\n break;\n }\n if (child$0 === b) {\n didFindChild = !0;\n b = parentB;\n a = parentA;\n break;\n }\n child$0 = child$0.sibling;\n }\n if (!didFindChild) throw Error(formatProdErrorMessage(189));\n }\n }\n if (a.alternate !== b) throw Error(formatProdErrorMessage(190));\n }\n if (3 !== a.tag) throw Error(formatProdErrorMessage(188));\n return a.stateNode.current === a ? fiber : alternate;\n}\nfunction findCurrentHostFiberImpl(node) {\n var tag = node.tag;\n if (5 === tag || 26 === tag || 27 === tag || 6 === tag) return node;\n for (node = node.child; null !== node; ) {\n tag = findCurrentHostFiberImpl(node);\n if (null !== tag) return tag;\n node = node.sibling;\n }\n return null;\n}\nvar assign = Object.assign,\n REACT_LEGACY_ELEMENT_TYPE = Symbol.for(\"react.element\"),\n REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\"),\n REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_SUSPENSE_LIST_TYPE = Symbol.for(\"react.suspense_list\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\");\nSymbol.for(\"react.scope\");\nvar REACT_ACTIVITY_TYPE = Symbol.for(\"react.activity\");\nSymbol.for(\"react.legacy_hidden\");\nSymbol.for(\"react.tracing_marker\");\nvar REACT_MEMO_CACHE_SENTINEL = Symbol.for(\"react.memo_cache_sentinel\");\nSymbol.for(\"react.view_transition\");\nvar MAYBE_ITERATOR_SYMBOL = Symbol.iterator;\nfunction getIteratorFn(maybeIterable) {\n if (null === maybeIterable || \"object\" !== typeof maybeIterable) return null;\n maybeIterable =\n (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) ||\n maybeIterable[\"@@iterator\"];\n return \"function\" === typeof maybeIterable ? maybeIterable : null;\n}\nvar REACT_CLIENT_REFERENCE = Symbol.for(\"react.client.reference\");\nfunction getComponentNameFromType(type) {\n if (null == type) return null;\n if (\"function\" === typeof type)\n return type.$$typeof === REACT_CLIENT_REFERENCE\n ? null\n : type.displayName || type.name || null;\n if (\"string\" === typeof type) return type;\n switch (type) {\n case REACT_FRAGMENT_TYPE:\n return \"Fragment\";\n case REACT_PROFILER_TYPE:\n return \"Profiler\";\n case REACT_STRICT_MODE_TYPE:\n return \"StrictMode\";\n case REACT_SUSPENSE_TYPE:\n return \"Suspense\";\n case REACT_SUSPENSE_LIST_TYPE:\n return \"SuspenseList\";\n case REACT_ACTIVITY_TYPE:\n return \"Activity\";\n }\n if (\"object\" === typeof type)\n switch (type.$$typeof) {\n case REACT_PORTAL_TYPE:\n return \"Portal\";\n case REACT_CONTEXT_TYPE:\n return type.displayName || \"Context\";\n case REACT_CONSUMER_TYPE:\n return (type._context.displayName || \"Context\") + \".Consumer\";\n case REACT_FORWARD_REF_TYPE:\n var innerType = type.render;\n type = type.displayName;\n type ||\n ((type = innerType.displayName || innerType.name || \"\"),\n (type = \"\" !== type ? \"ForwardRef(\" + type + \")\" : \"ForwardRef\"));\n return type;\n case REACT_MEMO_TYPE:\n return (\n (innerType = type.displayName || null),\n null !== innerType\n ? innerType\n : getComponentNameFromType(type.type) || \"Memo\"\n );\n case REACT_LAZY_TYPE:\n innerType = type._payload;\n type = type._init;\n try {\n return getComponentNameFromType(type(innerType));\n } catch (x) {}\n }\n return null;\n}\nvar isArrayImpl = Array.isArray,\n ReactSharedInternals =\n React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,\n ReactDOMSharedInternals =\n ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,\n sharedNotPendingObject = {\n pending: !1,\n data: null,\n method: null,\n action: null\n },\n valueStack = [],\n index = -1;\nfunction createCursor(defaultValue) {\n return { current: defaultValue };\n}\nfunction pop(cursor) {\n 0 > index ||\n ((cursor.current = valueStack[index]), (valueStack[index] = null), index--);\n}\nfunction push(cursor, value) {\n index++;\n valueStack[index] = cursor.current;\n cursor.current = value;\n}\nvar contextStackCursor = createCursor(null),\n contextFiberStackCursor = createCursor(null),\n rootInstanceStackCursor = createCursor(null),\n hostTransitionProviderCursor = createCursor(null);\nfunction pushHostContainer(fiber, nextRootInstance) {\n push(rootInstanceStackCursor, nextRootInstance);\n push(contextFiberStackCursor, fiber);\n push(contextStackCursor, null);\n switch (nextRootInstance.nodeType) {\n case 9:\n case 11:\n fiber = (fiber = nextRootInstance.documentElement)\n ? (fiber = fiber.namespaceURI)\n ? getOwnHostContext(fiber)\n : 0\n : 0;\n break;\n default:\n if (\n ((fiber = nextRootInstance.tagName),\n (nextRootInstance = nextRootInstance.namespaceURI))\n )\n (nextRootInstance = getOwnHostContext(nextRootInstance)),\n (fiber = getChildHostContextProd(nextRootInstance, fiber));\n else\n switch (fiber) {\n case \"svg\":\n fiber = 1;\n break;\n case \"math\":\n fiber = 2;\n break;\n default:\n fiber = 0;\n }\n }\n pop(contextStackCursor);\n push(contextStackCursor, fiber);\n}\nfunction popHostContainer() {\n pop(contextStackCursor);\n pop(contextFiberStackCursor);\n pop(rootInstanceStackCursor);\n}\nfunction pushHostContext(fiber) {\n null !== fiber.memoizedState && push(hostTransitionProviderCursor, fiber);\n var context = contextStackCursor.current;\n var JSCompiler_inline_result = getChildHostContextProd(context, fiber.type);\n context !== JSCompiler_inline_result &&\n (push(contextFiberStackCursor, fiber),\n push(contextStackCursor, JSCompiler_inline_result));\n}\nfunction popHostContext(fiber) {\n contextFiberStackCursor.current === fiber &&\n (pop(contextStackCursor), pop(contextFiberStackCursor));\n hostTransitionProviderCursor.current === fiber &&\n (pop(hostTransitionProviderCursor),\n (HostTransitionContext._currentValue = sharedNotPendingObject));\n}\nvar prefix, suffix;\nfunction describeBuiltInComponentFrame(name) {\n if (void 0 === prefix)\n try {\n throw Error();\n } catch (x) {\n var match = x.stack.trim().match(/\\n( *(at )?)/);\n prefix = (match && match[1]) || \"\";\n suffix =\n -1 < x.stack.indexOf(\"\\n at\")\n ? \" ()\"\n : -1 < x.stack.indexOf(\"@\")\n ? \"@unknown:0:0\"\n : \"\";\n }\n return \"\\n\" + prefix + name + suffix;\n}\nvar reentry = !1;\nfunction describeNativeComponentFrame(fn, construct) {\n if (!fn || reentry) return \"\";\n reentry = !0;\n var previousPrepareStackTrace = Error.prepareStackTrace;\n Error.prepareStackTrace = void 0;\n try {\n var RunInRootFrame = {\n DetermineComponentFrameRoot: function () {\n try {\n if (construct) {\n var Fake = function () {\n throw Error();\n };\n Object.defineProperty(Fake.prototype, \"props\", {\n set: function () {\n throw Error();\n }\n });\n if (\"object\" === typeof Reflect && Reflect.construct) {\n try {\n Reflect.construct(Fake, []);\n } catch (x) {\n var control = x;\n }\n Reflect.construct(fn, [], Fake);\n } else {\n try {\n Fake.call();\n } catch (x$1) {\n control = x$1;\n }\n fn.call(Fake.prototype);\n }\n } else {\n try {\n throw Error();\n } catch (x$2) {\n control = x$2;\n }\n (Fake = fn()) &&\n \"function\" === typeof Fake.catch &&\n Fake.catch(function () {});\n }\n } catch (sample) {\n if (sample && control && \"string\" === typeof sample.stack)\n return [sample.stack, control.stack];\n }\n return [null, null];\n }\n };\n RunInRootFrame.DetermineComponentFrameRoot.displayName =\n \"DetermineComponentFrameRoot\";\n var namePropDescriptor = Object.getOwnPropertyDescriptor(\n RunInRootFrame.DetermineComponentFrameRoot,\n \"name\"\n );\n namePropDescriptor &&\n namePropDescriptor.configurable &&\n Object.defineProperty(\n RunInRootFrame.DetermineComponentFrameRoot,\n \"name\",\n { value: \"DetermineComponentFrameRoot\" }\n );\n var _RunInRootFrame$Deter = RunInRootFrame.DetermineComponentFrameRoot(),\n sampleStack = _RunInRootFrame$Deter[0],\n controlStack = _RunInRootFrame$Deter[1];\n if (sampleStack && controlStack) {\n var sampleLines = sampleStack.split(\"\\n\"),\n controlLines = controlStack.split(\"\\n\");\n for (\n namePropDescriptor = RunInRootFrame = 0;\n RunInRootFrame < sampleLines.length &&\n !sampleLines[RunInRootFrame].includes(\"DetermineComponentFrameRoot\");\n\n )\n RunInRootFrame++;\n for (\n ;\n namePropDescriptor < controlLines.length &&\n !controlLines[namePropDescriptor].includes(\n \"DetermineComponentFrameRoot\"\n );\n\n )\n namePropDescriptor++;\n if (\n RunInRootFrame === sampleLines.length ||\n namePropDescriptor === controlLines.length\n )\n for (\n RunInRootFrame = sampleLines.length - 1,\n namePropDescriptor = controlLines.length - 1;\n 1 <= RunInRootFrame &&\n 0 <= namePropDescriptor &&\n sampleLines[RunInRootFrame] !== controlLines[namePropDescriptor];\n\n )\n namePropDescriptor--;\n for (\n ;\n 1 <= RunInRootFrame && 0 <= namePropDescriptor;\n RunInRootFrame--, namePropDescriptor--\n )\n if (sampleLines[RunInRootFrame] !== controlLines[namePropDescriptor]) {\n if (1 !== RunInRootFrame || 1 !== namePropDescriptor) {\n do\n if (\n (RunInRootFrame--,\n namePropDescriptor--,\n 0 > namePropDescriptor ||\n sampleLines[RunInRootFrame] !==\n controlLines[namePropDescriptor])\n ) {\n var frame =\n \"\\n\" +\n sampleLines[RunInRootFrame].replace(\" at new \", \" at \");\n fn.displayName &&\n frame.includes(\"\") &&\n (frame = frame.replace(\"\", fn.displayName));\n return frame;\n }\n while (1 <= RunInRootFrame && 0 <= namePropDescriptor);\n }\n break;\n }\n }\n } finally {\n (reentry = !1), (Error.prepareStackTrace = previousPrepareStackTrace);\n }\n return (previousPrepareStackTrace = fn ? fn.displayName || fn.name : \"\")\n ? describeBuiltInComponentFrame(previousPrepareStackTrace)\n : \"\";\n}\nfunction describeFiber(fiber, childFiber) {\n switch (fiber.tag) {\n case 26:\n case 27:\n case 5:\n return describeBuiltInComponentFrame(fiber.type);\n case 16:\n return describeBuiltInComponentFrame(\"Lazy\");\n case 13:\n return fiber.child !== childFiber && null !== childFiber\n ? describeBuiltInComponentFrame(\"Suspense Fallback\")\n : describeBuiltInComponentFrame(\"Suspense\");\n case 19:\n return describeBuiltInComponentFrame(\"SuspenseList\");\n case 0:\n case 15:\n return describeNativeComponentFrame(fiber.type, !1);\n case 11:\n return describeNativeComponentFrame(fiber.type.render, !1);\n case 1:\n return describeNativeComponentFrame(fiber.type, !0);\n case 31:\n return describeBuiltInComponentFrame(\"Activity\");\n default:\n return \"\";\n }\n}\nfunction getStackByFiberInDevAndProd(workInProgress) {\n try {\n var info = \"\",\n previous = null;\n do\n (info += describeFiber(workInProgress, previous)),\n (previous = workInProgress),\n (workInProgress = workInProgress.return);\n while (workInProgress);\n return info;\n } catch (x) {\n return \"\\nError generating stack: \" + x.message + \"\\n\" + x.stack;\n }\n}\nvar hasOwnProperty = Object.prototype.hasOwnProperty,\n scheduleCallback$3 = Scheduler.unstable_scheduleCallback,\n cancelCallback$1 = Scheduler.unstable_cancelCallback,\n shouldYield = Scheduler.unstable_shouldYield,\n requestPaint = Scheduler.unstable_requestPaint,\n now = Scheduler.unstable_now,\n getCurrentPriorityLevel = Scheduler.unstable_getCurrentPriorityLevel,\n ImmediatePriority = Scheduler.unstable_ImmediatePriority,\n UserBlockingPriority = Scheduler.unstable_UserBlockingPriority,\n NormalPriority$1 = Scheduler.unstable_NormalPriority,\n LowPriority = Scheduler.unstable_LowPriority,\n IdlePriority = Scheduler.unstable_IdlePriority,\n log$1 = Scheduler.log,\n unstable_setDisableYieldValue = Scheduler.unstable_setDisableYieldValue,\n rendererID = null,\n injectedHook = null;\nfunction setIsStrictModeForDevtools(newIsStrictMode) {\n \"function\" === typeof log$1 && unstable_setDisableYieldValue(newIsStrictMode);\n if (injectedHook && \"function\" === typeof injectedHook.setStrictMode)\n try {\n injectedHook.setStrictMode(rendererID, newIsStrictMode);\n } catch (err) {}\n}\nvar clz32 = Math.clz32 ? Math.clz32 : clz32Fallback,\n log = Math.log,\n LN2 = Math.LN2;\nfunction clz32Fallback(x) {\n x >>>= 0;\n return 0 === x ? 32 : (31 - ((log(x) / LN2) | 0)) | 0;\n}\nvar nextTransitionUpdateLane = 256,\n nextTransitionDeferredLane = 262144,\n nextRetryLane = 4194304;\nfunction getHighestPriorityLanes(lanes) {\n var pendingSyncLanes = lanes & 42;\n if (0 !== pendingSyncLanes) return pendingSyncLanes;\n switch (lanes & -lanes) {\n case 1:\n return 1;\n case 2:\n return 2;\n case 4:\n return 4;\n case 8:\n return 8;\n case 16:\n return 16;\n case 32:\n return 32;\n case 64:\n return 64;\n case 128:\n return 128;\n case 256:\n case 512:\n case 1024:\n case 2048:\n case 4096:\n case 8192:\n case 16384:\n case 32768:\n case 65536:\n case 131072:\n return lanes & 261888;\n case 262144:\n case 524288:\n case 1048576:\n case 2097152:\n return lanes & 3932160;\n case 4194304:\n case 8388608:\n case 16777216:\n case 33554432:\n return lanes & 62914560;\n case 67108864:\n return 67108864;\n case 134217728:\n return 134217728;\n case 268435456:\n return 268435456;\n case 536870912:\n return 536870912;\n case 1073741824:\n return 0;\n default:\n return lanes;\n }\n}\nfunction getNextLanes(root, wipLanes, rootHasPendingCommit) {\n var pendingLanes = root.pendingLanes;\n if (0 === pendingLanes) return 0;\n var nextLanes = 0,\n suspendedLanes = root.suspendedLanes,\n pingedLanes = root.pingedLanes;\n root = root.warmLanes;\n var nonIdlePendingLanes = pendingLanes & 134217727;\n 0 !== nonIdlePendingLanes\n ? ((pendingLanes = nonIdlePendingLanes & ~suspendedLanes),\n 0 !== pendingLanes\n ? (nextLanes = getHighestPriorityLanes(pendingLanes))\n : ((pingedLanes &= nonIdlePendingLanes),\n 0 !== pingedLanes\n ? (nextLanes = getHighestPriorityLanes(pingedLanes))\n : rootHasPendingCommit ||\n ((rootHasPendingCommit = nonIdlePendingLanes & ~root),\n 0 !== rootHasPendingCommit &&\n (nextLanes = getHighestPriorityLanes(rootHasPendingCommit)))))\n : ((nonIdlePendingLanes = pendingLanes & ~suspendedLanes),\n 0 !== nonIdlePendingLanes\n ? (nextLanes = getHighestPriorityLanes(nonIdlePendingLanes))\n : 0 !== pingedLanes\n ? (nextLanes = getHighestPriorityLanes(pingedLanes))\n : rootHasPendingCommit ||\n ((rootHasPendingCommit = pendingLanes & ~root),\n 0 !== rootHasPendingCommit &&\n (nextLanes = getHighestPriorityLanes(rootHasPendingCommit))));\n return 0 === nextLanes\n ? 0\n : 0 !== wipLanes &&\n wipLanes !== nextLanes &&\n 0 === (wipLanes & suspendedLanes) &&\n ((suspendedLanes = nextLanes & -nextLanes),\n (rootHasPendingCommit = wipLanes & -wipLanes),\n suspendedLanes >= rootHasPendingCommit ||\n (32 === suspendedLanes && 0 !== (rootHasPendingCommit & 4194048)))\n ? wipLanes\n : nextLanes;\n}\nfunction checkIfRootIsPrerendering(root, renderLanes) {\n return (\n 0 ===\n (root.pendingLanes &\n ~(root.suspendedLanes & ~root.pingedLanes) &\n renderLanes)\n );\n}\nfunction computeExpirationTime(lane, currentTime) {\n switch (lane) {\n case 1:\n case 2:\n case 4:\n case 8:\n case 64:\n return currentTime + 250;\n case 16:\n case 32:\n case 128:\n case 256:\n case 512:\n case 1024:\n case 2048:\n case 4096:\n case 8192:\n case 16384:\n case 32768:\n case 65536:\n case 131072:\n case 262144:\n case 524288:\n case 1048576:\n case 2097152:\n return currentTime + 5e3;\n case 4194304:\n case 8388608:\n case 16777216:\n case 33554432:\n return -1;\n case 67108864:\n case 134217728:\n case 268435456:\n case 536870912:\n case 1073741824:\n return -1;\n default:\n return -1;\n }\n}\nfunction claimNextRetryLane() {\n var lane = nextRetryLane;\n nextRetryLane <<= 1;\n 0 === (nextRetryLane & 62914560) && (nextRetryLane = 4194304);\n return lane;\n}\nfunction createLaneMap(initial) {\n for (var laneMap = [], i = 0; 31 > i; i++) laneMap.push(initial);\n return laneMap;\n}\nfunction markRootUpdated$1(root, updateLane) {\n root.pendingLanes |= updateLane;\n 268435456 !== updateLane &&\n ((root.suspendedLanes = 0), (root.pingedLanes = 0), (root.warmLanes = 0));\n}\nfunction markRootFinished(\n root,\n finishedLanes,\n remainingLanes,\n spawnedLane,\n updatedLanes,\n suspendedRetryLanes\n) {\n var previouslyPendingLanes = root.pendingLanes;\n root.pendingLanes = remainingLanes;\n root.suspendedLanes = 0;\n root.pingedLanes = 0;\n root.warmLanes = 0;\n root.expiredLanes &= remainingLanes;\n root.entangledLanes &= remainingLanes;\n root.errorRecoveryDisabledLanes &= remainingLanes;\n root.shellSuspendCounter = 0;\n var entanglements = root.entanglements,\n expirationTimes = root.expirationTimes,\n hiddenUpdates = root.hiddenUpdates;\n for (\n remainingLanes = previouslyPendingLanes & ~remainingLanes;\n 0 < remainingLanes;\n\n ) {\n var index$7 = 31 - clz32(remainingLanes),\n lane = 1 << index$7;\n entanglements[index$7] = 0;\n expirationTimes[index$7] = -1;\n var hiddenUpdatesForLane = hiddenUpdates[index$7];\n if (null !== hiddenUpdatesForLane)\n for (\n hiddenUpdates[index$7] = null, index$7 = 0;\n index$7 < hiddenUpdatesForLane.length;\n index$7++\n ) {\n var update = hiddenUpdatesForLane[index$7];\n null !== update && (update.lane &= -536870913);\n }\n remainingLanes &= ~lane;\n }\n 0 !== spawnedLane && markSpawnedDeferredLane(root, spawnedLane, 0);\n 0 !== suspendedRetryLanes &&\n 0 === updatedLanes &&\n 0 !== root.tag &&\n (root.suspendedLanes |=\n suspendedRetryLanes & ~(previouslyPendingLanes & ~finishedLanes));\n}\nfunction markSpawnedDeferredLane(root, spawnedLane, entangledLanes) {\n root.pendingLanes |= spawnedLane;\n root.suspendedLanes &= ~spawnedLane;\n var spawnedLaneIndex = 31 - clz32(spawnedLane);\n root.entangledLanes |= spawnedLane;\n root.entanglements[spawnedLaneIndex] =\n root.entanglements[spawnedLaneIndex] |\n 1073741824 |\n (entangledLanes & 261930);\n}\nfunction markRootEntangled(root, entangledLanes) {\n var rootEntangledLanes = (root.entangledLanes |= entangledLanes);\n for (root = root.entanglements; rootEntangledLanes; ) {\n var index$8 = 31 - clz32(rootEntangledLanes),\n lane = 1 << index$8;\n (lane & entangledLanes) | (root[index$8] & entangledLanes) &&\n (root[index$8] |= entangledLanes);\n rootEntangledLanes &= ~lane;\n }\n}\nfunction getBumpedLaneForHydration(root, renderLanes) {\n var renderLane = renderLanes & -renderLanes;\n renderLane =\n 0 !== (renderLane & 42) ? 1 : getBumpedLaneForHydrationByLane(renderLane);\n return 0 !== (renderLane & (root.suspendedLanes | renderLanes))\n ? 0\n : renderLane;\n}\nfunction getBumpedLaneForHydrationByLane(lane) {\n switch (lane) {\n case 2:\n lane = 1;\n break;\n case 8:\n lane = 4;\n break;\n case 32:\n lane = 16;\n break;\n case 256:\n case 512:\n case 1024:\n case 2048:\n case 4096:\n case 8192:\n case 16384:\n case 32768:\n case 65536:\n case 131072:\n case 262144:\n case 524288:\n case 1048576:\n case 2097152:\n case 4194304:\n case 8388608:\n case 16777216:\n case 33554432:\n lane = 128;\n break;\n case 268435456:\n lane = 134217728;\n break;\n default:\n lane = 0;\n }\n return lane;\n}\nfunction lanesToEventPriority(lanes) {\n lanes &= -lanes;\n return 2 < lanes\n ? 8 < lanes\n ? 0 !== (lanes & 134217727)\n ? 32\n : 268435456\n : 8\n : 2;\n}\nfunction resolveUpdatePriority() {\n var updatePriority = ReactDOMSharedInternals.p;\n if (0 !== updatePriority) return updatePriority;\n updatePriority = window.event;\n return void 0 === updatePriority ? 32 : getEventPriority(updatePriority.type);\n}\nfunction runWithPriority(priority, fn) {\n var previousPriority = ReactDOMSharedInternals.p;\n try {\n return (ReactDOMSharedInternals.p = priority), fn();\n } finally {\n ReactDOMSharedInternals.p = previousPriority;\n }\n}\nvar randomKey = Math.random().toString(36).slice(2),\n internalInstanceKey = \"__reactFiber$\" + randomKey,\n internalPropsKey = \"__reactProps$\" + randomKey,\n internalContainerInstanceKey = \"__reactContainer$\" + randomKey,\n internalEventHandlersKey = \"__reactEvents$\" + randomKey,\n internalEventHandlerListenersKey = \"__reactListeners$\" + randomKey,\n internalEventHandlesSetKey = \"__reactHandles$\" + randomKey,\n internalRootNodeResourcesKey = \"__reactResources$\" + randomKey,\n internalHoistableMarker = \"__reactMarker$\" + randomKey;\nfunction detachDeletedInstance(node) {\n delete node[internalInstanceKey];\n delete node[internalPropsKey];\n delete node[internalEventHandlersKey];\n delete node[internalEventHandlerListenersKey];\n delete node[internalEventHandlesSetKey];\n}\nfunction getClosestInstanceFromNode(targetNode) {\n var targetInst = targetNode[internalInstanceKey];\n if (targetInst) return targetInst;\n for (var parentNode = targetNode.parentNode; parentNode; ) {\n if (\n (targetInst =\n parentNode[internalContainerInstanceKey] ||\n parentNode[internalInstanceKey])\n ) {\n parentNode = targetInst.alternate;\n if (\n null !== targetInst.child ||\n (null !== parentNode && null !== parentNode.child)\n )\n for (\n targetNode = getParentHydrationBoundary(targetNode);\n null !== targetNode;\n\n ) {\n if ((parentNode = targetNode[internalInstanceKey])) return parentNode;\n targetNode = getParentHydrationBoundary(targetNode);\n }\n return targetInst;\n }\n targetNode = parentNode;\n parentNode = targetNode.parentNode;\n }\n return null;\n}\nfunction getInstanceFromNode(node) {\n if (\n (node = node[internalInstanceKey] || node[internalContainerInstanceKey])\n ) {\n var tag = node.tag;\n if (\n 5 === tag ||\n 6 === tag ||\n 13 === tag ||\n 31 === tag ||\n 26 === tag ||\n 27 === tag ||\n 3 === tag\n )\n return node;\n }\n return null;\n}\nfunction getNodeFromInstance(inst) {\n var tag = inst.tag;\n if (5 === tag || 26 === tag || 27 === tag || 6 === tag) return inst.stateNode;\n throw Error(formatProdErrorMessage(33));\n}\nfunction getResourcesFromRoot(root) {\n var resources = root[internalRootNodeResourcesKey];\n resources ||\n (resources = root[internalRootNodeResourcesKey] =\n { hoistableStyles: new Map(), hoistableScripts: new Map() });\n return resources;\n}\nfunction markNodeAsHoistable(node) {\n node[internalHoistableMarker] = !0;\n}\nvar allNativeEvents = new Set(),\n registrationNameDependencies = {};\nfunction registerTwoPhaseEvent(registrationName, dependencies) {\n registerDirectEvent(registrationName, dependencies);\n registerDirectEvent(registrationName + \"Capture\", dependencies);\n}\nfunction registerDirectEvent(registrationName, dependencies) {\n registrationNameDependencies[registrationName] = dependencies;\n for (\n registrationName = 0;\n registrationName < dependencies.length;\n registrationName++\n )\n allNativeEvents.add(dependencies[registrationName]);\n}\nvar VALID_ATTRIBUTE_NAME_REGEX = RegExp(\n \"^[:A-Z_a-z\\\\u00C0-\\\\u00D6\\\\u00D8-\\\\u00F6\\\\u00F8-\\\\u02FF\\\\u0370-\\\\u037D\\\\u037F-\\\\u1FFF\\\\u200C-\\\\u200D\\\\u2070-\\\\u218F\\\\u2C00-\\\\u2FEF\\\\u3001-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFFD][:A-Z_a-z\\\\u00C0-\\\\u00D6\\\\u00D8-\\\\u00F6\\\\u00F8-\\\\u02FF\\\\u0370-\\\\u037D\\\\u037F-\\\\u1FFF\\\\u200C-\\\\u200D\\\\u2070-\\\\u218F\\\\u2C00-\\\\u2FEF\\\\u3001-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFFD\\\\-.0-9\\\\u00B7\\\\u0300-\\\\u036F\\\\u203F-\\\\u2040]*$\"\n ),\n illegalAttributeNameCache = {},\n validatedAttributeNameCache = {};\nfunction isAttributeNameSafe(attributeName) {\n if (hasOwnProperty.call(validatedAttributeNameCache, attributeName))\n return !0;\n if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) return !1;\n if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName))\n return (validatedAttributeNameCache[attributeName] = !0);\n illegalAttributeNameCache[attributeName] = !0;\n return !1;\n}\nfunction setValueForAttribute(node, name, value) {\n if (isAttributeNameSafe(name))\n if (null === value) node.removeAttribute(name);\n else {\n switch (typeof value) {\n case \"undefined\":\n case \"function\":\n case \"symbol\":\n node.removeAttribute(name);\n return;\n case \"boolean\":\n var prefix$10 = name.toLowerCase().slice(0, 5);\n if (\"data-\" !== prefix$10 && \"aria-\" !== prefix$10) {\n node.removeAttribute(name);\n return;\n }\n }\n node.setAttribute(name, \"\" + value);\n }\n}\nfunction setValueForKnownAttribute(node, name, value) {\n if (null === value) node.removeAttribute(name);\n else {\n switch (typeof value) {\n case \"undefined\":\n case \"function\":\n case \"symbol\":\n case \"boolean\":\n node.removeAttribute(name);\n return;\n }\n node.setAttribute(name, \"\" + value);\n }\n}\nfunction setValueForNamespacedAttribute(node, namespace, name, value) {\n if (null === value) node.removeAttribute(name);\n else {\n switch (typeof value) {\n case \"undefined\":\n case \"function\":\n case \"symbol\":\n case \"boolean\":\n node.removeAttribute(name);\n return;\n }\n node.setAttributeNS(namespace, name, \"\" + value);\n }\n}\nfunction getToStringValue(value) {\n switch (typeof value) {\n case \"bigint\":\n case \"boolean\":\n case \"number\":\n case \"string\":\n case \"undefined\":\n return value;\n case \"object\":\n return value;\n default:\n return \"\";\n }\n}\nfunction isCheckable(elem) {\n var type = elem.type;\n return (\n (elem = elem.nodeName) &&\n \"input\" === elem.toLowerCase() &&\n (\"checkbox\" === type || \"radio\" === type)\n );\n}\nfunction trackValueOnNode(node, valueField, currentValue) {\n var descriptor = Object.getOwnPropertyDescriptor(\n node.constructor.prototype,\n valueField\n );\n if (\n !node.hasOwnProperty(valueField) &&\n \"undefined\" !== typeof descriptor &&\n \"function\" === typeof descriptor.get &&\n \"function\" === typeof descriptor.set\n ) {\n var get = descriptor.get,\n set = descriptor.set;\n Object.defineProperty(node, valueField, {\n configurable: !0,\n get: function () {\n return get.call(this);\n },\n set: function (value) {\n currentValue = \"\" + value;\n set.call(this, value);\n }\n });\n Object.defineProperty(node, valueField, {\n enumerable: descriptor.enumerable\n });\n return {\n getValue: function () {\n return currentValue;\n },\n setValue: function (value) {\n currentValue = \"\" + value;\n },\n stopTracking: function () {\n node._valueTracker = null;\n delete node[valueField];\n }\n };\n }\n}\nfunction track(node) {\n if (!node._valueTracker) {\n var valueField = isCheckable(node) ? \"checked\" : \"value\";\n node._valueTracker = trackValueOnNode(\n node,\n valueField,\n \"\" + node[valueField]\n );\n }\n}\nfunction updateValueIfChanged(node) {\n if (!node) return !1;\n var tracker = node._valueTracker;\n if (!tracker) return !0;\n var lastValue = tracker.getValue();\n var value = \"\";\n node &&\n (value = isCheckable(node)\n ? node.checked\n ? \"true\"\n : \"false\"\n : node.value);\n node = value;\n return node !== lastValue ? (tracker.setValue(node), !0) : !1;\n}\nfunction getActiveElement(doc) {\n doc = doc || (\"undefined\" !== typeof document ? document : void 0);\n if (\"undefined\" === typeof doc) return null;\n try {\n return doc.activeElement || doc.body;\n } catch (e) {\n return doc.body;\n }\n}\nvar escapeSelectorAttributeValueInsideDoubleQuotesRegex = /[\\n\"\\\\]/g;\nfunction escapeSelectorAttributeValueInsideDoubleQuotes(value) {\n return value.replace(\n escapeSelectorAttributeValueInsideDoubleQuotesRegex,\n function (ch) {\n return \"\\\\\" + ch.charCodeAt(0).toString(16) + \" \";\n }\n );\n}\nfunction updateInput(\n element,\n value,\n defaultValue,\n lastDefaultValue,\n checked,\n defaultChecked,\n type,\n name\n) {\n element.name = \"\";\n null != type &&\n \"function\" !== typeof type &&\n \"symbol\" !== typeof type &&\n \"boolean\" !== typeof type\n ? (element.type = type)\n : element.removeAttribute(\"type\");\n if (null != value)\n if (\"number\" === type) {\n if ((0 === value && \"\" === element.value) || element.value != value)\n element.value = \"\" + getToStringValue(value);\n } else\n element.value !== \"\" + getToStringValue(value) &&\n (element.value = \"\" + getToStringValue(value));\n else\n (\"submit\" !== type && \"reset\" !== type) || element.removeAttribute(\"value\");\n null != value\n ? setDefaultValue(element, type, getToStringValue(value))\n : null != defaultValue\n ? setDefaultValue(element, type, getToStringValue(defaultValue))\n : null != lastDefaultValue && element.removeAttribute(\"value\");\n null == checked &&\n null != defaultChecked &&\n (element.defaultChecked = !!defaultChecked);\n null != checked &&\n (element.checked =\n checked && \"function\" !== typeof checked && \"symbol\" !== typeof checked);\n null != name &&\n \"function\" !== typeof name &&\n \"symbol\" !== typeof name &&\n \"boolean\" !== typeof name\n ? (element.name = \"\" + getToStringValue(name))\n : element.removeAttribute(\"name\");\n}\nfunction initInput(\n element,\n value,\n defaultValue,\n checked,\n defaultChecked,\n type,\n name,\n isHydrating\n) {\n null != type &&\n \"function\" !== typeof type &&\n \"symbol\" !== typeof type &&\n \"boolean\" !== typeof type &&\n (element.type = type);\n if (null != value || null != defaultValue) {\n if (\n !(\n (\"submit\" !== type && \"reset\" !== type) ||\n (void 0 !== value && null !== value)\n )\n ) {\n track(element);\n return;\n }\n defaultValue =\n null != defaultValue ? \"\" + getToStringValue(defaultValue) : \"\";\n value = null != value ? \"\" + getToStringValue(value) : defaultValue;\n isHydrating || value === element.value || (element.value = value);\n element.defaultValue = value;\n }\n checked = null != checked ? checked : defaultChecked;\n checked =\n \"function\" !== typeof checked && \"symbol\" !== typeof checked && !!checked;\n element.checked = isHydrating ? element.checked : !!checked;\n element.defaultChecked = !!checked;\n null != name &&\n \"function\" !== typeof name &&\n \"symbol\" !== typeof name &&\n \"boolean\" !== typeof name &&\n (element.name = name);\n track(element);\n}\nfunction setDefaultValue(node, type, value) {\n (\"number\" === type && getActiveElement(node.ownerDocument) === node) ||\n node.defaultValue === \"\" + value ||\n (node.defaultValue = \"\" + value);\n}\nfunction updateOptions(node, multiple, propValue, setDefaultSelected) {\n node = node.options;\n if (multiple) {\n multiple = {};\n for (var i = 0; i < propValue.length; i++)\n multiple[\"$\" + propValue[i]] = !0;\n for (propValue = 0; propValue < node.length; propValue++)\n (i = multiple.hasOwnProperty(\"$\" + node[propValue].value)),\n node[propValue].selected !== i && (node[propValue].selected = i),\n i && setDefaultSelected && (node[propValue].defaultSelected = !0);\n } else {\n propValue = \"\" + getToStringValue(propValue);\n multiple = null;\n for (i = 0; i < node.length; i++) {\n if (node[i].value === propValue) {\n node[i].selected = !0;\n setDefaultSelected && (node[i].defaultSelected = !0);\n return;\n }\n null !== multiple || node[i].disabled || (multiple = node[i]);\n }\n null !== multiple && (multiple.selected = !0);\n }\n}\nfunction updateTextarea(element, value, defaultValue) {\n if (\n null != value &&\n ((value = \"\" + getToStringValue(value)),\n value !== element.value && (element.value = value),\n null == defaultValue)\n ) {\n element.defaultValue !== value && (element.defaultValue = value);\n return;\n }\n element.defaultValue =\n null != defaultValue ? \"\" + getToStringValue(defaultValue) : \"\";\n}\nfunction initTextarea(element, value, defaultValue, children) {\n if (null == value) {\n if (null != children) {\n if (null != defaultValue) throw Error(formatProdErrorMessage(92));\n if (isArrayImpl(children)) {\n if (1 < children.length) throw Error(formatProdErrorMessage(93));\n children = children[0];\n }\n defaultValue = children;\n }\n null == defaultValue && (defaultValue = \"\");\n value = defaultValue;\n }\n defaultValue = getToStringValue(value);\n element.defaultValue = defaultValue;\n children = element.textContent;\n children === defaultValue &&\n \"\" !== children &&\n null !== children &&\n (element.value = children);\n track(element);\n}\nfunction setTextContent(node, text) {\n if (text) {\n var firstChild = node.firstChild;\n if (\n firstChild &&\n firstChild === node.lastChild &&\n 3 === firstChild.nodeType\n ) {\n firstChild.nodeValue = text;\n return;\n }\n }\n node.textContent = text;\n}\nvar unitlessNumbers = new Set(\n \"animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIndex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitBoxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp\".split(\n \" \"\n )\n);\nfunction setValueForStyle(style, styleName, value) {\n var isCustomProperty = 0 === styleName.indexOf(\"--\");\n null == value || \"boolean\" === typeof value || \"\" === value\n ? isCustomProperty\n ? style.setProperty(styleName, \"\")\n : \"float\" === styleName\n ? (style.cssFloat = \"\")\n : (style[styleName] = \"\")\n : isCustomProperty\n ? style.setProperty(styleName, value)\n : \"number\" !== typeof value ||\n 0 === value ||\n unitlessNumbers.has(styleName)\n ? \"float\" === styleName\n ? (style.cssFloat = value)\n : (style[styleName] = (\"\" + value).trim())\n : (style[styleName] = value + \"px\");\n}\nfunction setValueForStyles(node, styles, prevStyles) {\n if (null != styles && \"object\" !== typeof styles)\n throw Error(formatProdErrorMessage(62));\n node = node.style;\n if (null != prevStyles) {\n for (var styleName in prevStyles)\n !prevStyles.hasOwnProperty(styleName) ||\n (null != styles && styles.hasOwnProperty(styleName)) ||\n (0 === styleName.indexOf(\"--\")\n ? node.setProperty(styleName, \"\")\n : \"float\" === styleName\n ? (node.cssFloat = \"\")\n : (node[styleName] = \"\"));\n for (var styleName$16 in styles)\n (styleName = styles[styleName$16]),\n styles.hasOwnProperty(styleName$16) &&\n prevStyles[styleName$16] !== styleName &&\n setValueForStyle(node, styleName$16, styleName);\n } else\n for (var styleName$17 in styles)\n styles.hasOwnProperty(styleName$17) &&\n setValueForStyle(node, styleName$17, styles[styleName$17]);\n}\nfunction isCustomElement(tagName) {\n if (-1 === tagName.indexOf(\"-\")) return !1;\n switch (tagName) {\n case \"annotation-xml\":\n case \"color-profile\":\n case \"font-face\":\n case \"font-face-src\":\n case \"font-face-uri\":\n case \"font-face-format\":\n case \"font-face-name\":\n case \"missing-glyph\":\n return !1;\n default:\n return !0;\n }\n}\nvar aliases = new Map([\n [\"acceptCharset\", \"accept-charset\"],\n [\"htmlFor\", \"for\"],\n [\"httpEquiv\", \"http-equiv\"],\n [\"crossOrigin\", \"crossorigin\"],\n [\"accentHeight\", \"accent-height\"],\n [\"alignmentBaseline\", \"alignment-baseline\"],\n [\"arabicForm\", \"arabic-form\"],\n [\"baselineShift\", \"baseline-shift\"],\n [\"capHeight\", \"cap-height\"],\n [\"clipPath\", \"clip-path\"],\n [\"clipRule\", \"clip-rule\"],\n [\"colorInterpolation\", \"color-interpolation\"],\n [\"colorInterpolationFilters\", \"color-interpolation-filters\"],\n [\"colorProfile\", \"color-profile\"],\n [\"colorRendering\", \"color-rendering\"],\n [\"dominantBaseline\", \"dominant-baseline\"],\n [\"enableBackground\", \"enable-background\"],\n [\"fillOpacity\", \"fill-opacity\"],\n [\"fillRule\", \"fill-rule\"],\n [\"floodColor\", \"flood-color\"],\n [\"floodOpacity\", \"flood-opacity\"],\n [\"fontFamily\", \"font-family\"],\n [\"fontSize\", \"font-size\"],\n [\"fontSizeAdjust\", \"font-size-adjust\"],\n [\"fontStretch\", \"font-stretch\"],\n [\"fontStyle\", \"font-style\"],\n [\"fontVariant\", \"font-variant\"],\n [\"fontWeight\", \"font-weight\"],\n [\"glyphName\", \"glyph-name\"],\n [\"glyphOrientationHorizontal\", \"glyph-orientation-horizontal\"],\n [\"glyphOrientationVertical\", \"glyph-orientation-vertical\"],\n [\"horizAdvX\", \"horiz-adv-x\"],\n [\"horizOriginX\", \"horiz-origin-x\"],\n [\"imageRendering\", \"image-rendering\"],\n [\"letterSpacing\", \"letter-spacing\"],\n [\"lightingColor\", \"lighting-color\"],\n [\"markerEnd\", \"marker-end\"],\n [\"markerMid\", \"marker-mid\"],\n [\"markerStart\", \"marker-start\"],\n [\"overlinePosition\", \"overline-position\"],\n [\"overlineThickness\", \"overline-thickness\"],\n [\"paintOrder\", \"paint-order\"],\n [\"panose-1\", \"panose-1\"],\n [\"pointerEvents\", \"pointer-events\"],\n [\"renderingIntent\", \"rendering-intent\"],\n [\"shapeRendering\", \"shape-rendering\"],\n [\"stopColor\", \"stop-color\"],\n [\"stopOpacity\", \"stop-opacity\"],\n [\"strikethroughPosition\", \"strikethrough-position\"],\n [\"strikethroughThickness\", \"strikethrough-thickness\"],\n [\"strokeDasharray\", \"stroke-dasharray\"],\n [\"strokeDashoffset\", \"stroke-dashoffset\"],\n [\"strokeLinecap\", \"stroke-linecap\"],\n [\"strokeLinejoin\", \"stroke-linejoin\"],\n [\"strokeMiterlimit\", \"stroke-miterlimit\"],\n [\"strokeOpacity\", \"stroke-opacity\"],\n [\"strokeWidth\", \"stroke-width\"],\n [\"textAnchor\", \"text-anchor\"],\n [\"textDecoration\", \"text-decoration\"],\n [\"textRendering\", \"text-rendering\"],\n [\"transformOrigin\", \"transform-origin\"],\n [\"underlinePosition\", \"underline-position\"],\n [\"underlineThickness\", \"underline-thickness\"],\n [\"unicodeBidi\", \"unicode-bidi\"],\n [\"unicodeRange\", \"unicode-range\"],\n [\"unitsPerEm\", \"units-per-em\"],\n [\"vAlphabetic\", \"v-alphabetic\"],\n [\"vHanging\", \"v-hanging\"],\n [\"vIdeographic\", \"v-ideographic\"],\n [\"vMathematical\", \"v-mathematical\"],\n [\"vectorEffect\", \"vector-effect\"],\n [\"vertAdvY\", \"vert-adv-y\"],\n [\"vertOriginX\", \"vert-origin-x\"],\n [\"vertOriginY\", \"vert-origin-y\"],\n [\"wordSpacing\", \"word-spacing\"],\n [\"writingMode\", \"writing-mode\"],\n [\"xmlnsXlink\", \"xmlns:xlink\"],\n [\"xHeight\", \"x-height\"]\n ]),\n isJavaScriptProtocol =\n /^[\\u0000-\\u001F ]*j[\\r\\n\\t]*a[\\r\\n\\t]*v[\\r\\n\\t]*a[\\r\\n\\t]*s[\\r\\n\\t]*c[\\r\\n\\t]*r[\\r\\n\\t]*i[\\r\\n\\t]*p[\\r\\n\\t]*t[\\r\\n\\t]*:/i;\nfunction sanitizeURL(url) {\n return isJavaScriptProtocol.test(\"\" + url)\n ? \"javascript:throw new Error('React has blocked a javascript: URL as a security precaution.')\"\n : url;\n}\nfunction noop$1() {}\nvar currentReplayingEvent = null;\nfunction getEventTarget(nativeEvent) {\n nativeEvent = nativeEvent.target || nativeEvent.srcElement || window;\n nativeEvent.correspondingUseElement &&\n (nativeEvent = nativeEvent.correspondingUseElement);\n return 3 === nativeEvent.nodeType ? nativeEvent.parentNode : nativeEvent;\n}\nvar restoreTarget = null,\n restoreQueue = null;\nfunction restoreStateOfTarget(target) {\n var internalInstance = getInstanceFromNode(target);\n if (internalInstance && (target = internalInstance.stateNode)) {\n var props = target[internalPropsKey] || null;\n a: switch (((target = internalInstance.stateNode), internalInstance.type)) {\n case \"input\":\n updateInput(\n target,\n props.value,\n props.defaultValue,\n props.defaultValue,\n props.checked,\n props.defaultChecked,\n props.type,\n props.name\n );\n internalInstance = props.name;\n if (\"radio\" === props.type && null != internalInstance) {\n for (props = target; props.parentNode; ) props = props.parentNode;\n props = props.querySelectorAll(\n 'input[name=\"' +\n escapeSelectorAttributeValueInsideDoubleQuotes(\n \"\" + internalInstance\n ) +\n '\"][type=\"radio\"]'\n );\n for (\n internalInstance = 0;\n internalInstance < props.length;\n internalInstance++\n ) {\n var otherNode = props[internalInstance];\n if (otherNode !== target && otherNode.form === target.form) {\n var otherProps = otherNode[internalPropsKey] || null;\n if (!otherProps) throw Error(formatProdErrorMessage(90));\n updateInput(\n otherNode,\n otherProps.value,\n otherProps.defaultValue,\n otherProps.defaultValue,\n otherProps.checked,\n otherProps.defaultChecked,\n otherProps.type,\n otherProps.name\n );\n }\n }\n for (\n internalInstance = 0;\n internalInstance < props.length;\n internalInstance++\n )\n (otherNode = props[internalInstance]),\n otherNode.form === target.form && updateValueIfChanged(otherNode);\n }\n break a;\n case \"textarea\":\n updateTextarea(target, props.value, props.defaultValue);\n break a;\n case \"select\":\n (internalInstance = props.value),\n null != internalInstance &&\n updateOptions(target, !!props.multiple, internalInstance, !1);\n }\n }\n}\nvar isInsideEventHandler = !1;\nfunction batchedUpdates$1(fn, a, b) {\n if (isInsideEventHandler) return fn(a, b);\n isInsideEventHandler = !0;\n try {\n var JSCompiler_inline_result = fn(a);\n return JSCompiler_inline_result;\n } finally {\n if (\n ((isInsideEventHandler = !1),\n null !== restoreTarget || null !== restoreQueue)\n )\n if (\n (flushSyncWork$1(),\n restoreTarget &&\n ((a = restoreTarget),\n (fn = restoreQueue),\n (restoreQueue = restoreTarget = null),\n restoreStateOfTarget(a),\n fn))\n )\n for (a = 0; a < fn.length; a++) restoreStateOfTarget(fn[a]);\n }\n}\nfunction getListener(inst, registrationName) {\n var stateNode = inst.stateNode;\n if (null === stateNode) return null;\n var props = stateNode[internalPropsKey] || null;\n if (null === props) return null;\n stateNode = props[registrationName];\n a: switch (registrationName) {\n case \"onClick\":\n case \"onClickCapture\":\n case \"onDoubleClick\":\n case \"onDoubleClickCapture\":\n case \"onMouseDown\":\n case \"onMouseDownCapture\":\n case \"onMouseMove\":\n case \"onMouseMoveCapture\":\n case \"onMouseUp\":\n case \"onMouseUpCapture\":\n case \"onMouseEnter\":\n (props = !props.disabled) ||\n ((inst = inst.type),\n (props = !(\n \"button\" === inst ||\n \"input\" === inst ||\n \"select\" === inst ||\n \"textarea\" === inst\n )));\n inst = !props;\n break a;\n default:\n inst = !1;\n }\n if (inst) return null;\n if (stateNode && \"function\" !== typeof stateNode)\n throw Error(\n formatProdErrorMessage(231, registrationName, typeof stateNode)\n );\n return stateNode;\n}\nvar canUseDOM = !(\n \"undefined\" === typeof window ||\n \"undefined\" === typeof window.document ||\n \"undefined\" === typeof window.document.createElement\n ),\n passiveBrowserEventsSupported = !1;\nif (canUseDOM)\n try {\n var options = {};\n Object.defineProperty(options, \"passive\", {\n get: function () {\n passiveBrowserEventsSupported = !0;\n }\n });\n window.addEventListener(\"test\", options, options);\n window.removeEventListener(\"test\", options, options);\n } catch (e) {\n passiveBrowserEventsSupported = !1;\n }\nvar root = null,\n startText = null,\n fallbackText = null;\nfunction getData() {\n if (fallbackText) return fallbackText;\n var start,\n startValue = startText,\n startLength = startValue.length,\n end,\n endValue = \"value\" in root ? root.value : root.textContent,\n endLength = endValue.length;\n for (\n start = 0;\n start < startLength && startValue[start] === endValue[start];\n start++\n );\n var minEnd = startLength - start;\n for (\n end = 1;\n end <= minEnd &&\n startValue[startLength - end] === endValue[endLength - end];\n end++\n );\n return (fallbackText = endValue.slice(start, 1 < end ? 1 - end : void 0));\n}\nfunction getEventCharCode(nativeEvent) {\n var keyCode = nativeEvent.keyCode;\n \"charCode\" in nativeEvent\n ? ((nativeEvent = nativeEvent.charCode),\n 0 === nativeEvent && 13 === keyCode && (nativeEvent = 13))\n : (nativeEvent = keyCode);\n 10 === nativeEvent && (nativeEvent = 13);\n return 32 <= nativeEvent || 13 === nativeEvent ? nativeEvent : 0;\n}\nfunction functionThatReturnsTrue() {\n return !0;\n}\nfunction functionThatReturnsFalse() {\n return !1;\n}\nfunction createSyntheticEvent(Interface) {\n function SyntheticBaseEvent(\n reactName,\n reactEventType,\n targetInst,\n nativeEvent,\n nativeEventTarget\n ) {\n this._reactName = reactName;\n this._targetInst = targetInst;\n this.type = reactEventType;\n this.nativeEvent = nativeEvent;\n this.target = nativeEventTarget;\n this.currentTarget = null;\n for (var propName in Interface)\n Interface.hasOwnProperty(propName) &&\n ((reactName = Interface[propName]),\n (this[propName] = reactName\n ? reactName(nativeEvent)\n : nativeEvent[propName]));\n this.isDefaultPrevented = (\n null != nativeEvent.defaultPrevented\n ? nativeEvent.defaultPrevented\n : !1 === nativeEvent.returnValue\n )\n ? functionThatReturnsTrue\n : functionThatReturnsFalse;\n this.isPropagationStopped = functionThatReturnsFalse;\n return this;\n }\n assign(SyntheticBaseEvent.prototype, {\n preventDefault: function () {\n this.defaultPrevented = !0;\n var event = this.nativeEvent;\n event &&\n (event.preventDefault\n ? event.preventDefault()\n : \"unknown\" !== typeof event.returnValue && (event.returnValue = !1),\n (this.isDefaultPrevented = functionThatReturnsTrue));\n },\n stopPropagation: function () {\n var event = this.nativeEvent;\n event &&\n (event.stopPropagation\n ? event.stopPropagation()\n : \"unknown\" !== typeof event.cancelBubble &&\n (event.cancelBubble = !0),\n (this.isPropagationStopped = functionThatReturnsTrue));\n },\n persist: function () {},\n isPersistent: functionThatReturnsTrue\n });\n return SyntheticBaseEvent;\n}\nvar EventInterface = {\n eventPhase: 0,\n bubbles: 0,\n cancelable: 0,\n timeStamp: function (event) {\n return event.timeStamp || Date.now();\n },\n defaultPrevented: 0,\n isTrusted: 0\n },\n SyntheticEvent = createSyntheticEvent(EventInterface),\n UIEventInterface = assign({}, EventInterface, { view: 0, detail: 0 }),\n SyntheticUIEvent = createSyntheticEvent(UIEventInterface),\n lastMovementX,\n lastMovementY,\n lastMouseEvent,\n MouseEventInterface = assign({}, UIEventInterface, {\n screenX: 0,\n screenY: 0,\n clientX: 0,\n clientY: 0,\n pageX: 0,\n pageY: 0,\n ctrlKey: 0,\n shiftKey: 0,\n altKey: 0,\n metaKey: 0,\n getModifierState: getEventModifierState,\n button: 0,\n buttons: 0,\n relatedTarget: function (event) {\n return void 0 === event.relatedTarget\n ? event.fromElement === event.srcElement\n ? event.toElement\n : event.fromElement\n : event.relatedTarget;\n },\n movementX: function (event) {\n if (\"movementX\" in event) return event.movementX;\n event !== lastMouseEvent &&\n (lastMouseEvent && \"mousemove\" === event.type\n ? ((lastMovementX = event.screenX - lastMouseEvent.screenX),\n (lastMovementY = event.screenY - lastMouseEvent.screenY))\n : (lastMovementY = lastMovementX = 0),\n (lastMouseEvent = event));\n return lastMovementX;\n },\n movementY: function (event) {\n return \"movementY\" in event ? event.movementY : lastMovementY;\n }\n }),\n SyntheticMouseEvent = createSyntheticEvent(MouseEventInterface),\n DragEventInterface = assign({}, MouseEventInterface, { dataTransfer: 0 }),\n SyntheticDragEvent = createSyntheticEvent(DragEventInterface),\n FocusEventInterface = assign({}, UIEventInterface, { relatedTarget: 0 }),\n SyntheticFocusEvent = createSyntheticEvent(FocusEventInterface),\n AnimationEventInterface = assign({}, EventInterface, {\n animationName: 0,\n elapsedTime: 0,\n pseudoElement: 0\n }),\n SyntheticAnimationEvent = createSyntheticEvent(AnimationEventInterface),\n ClipboardEventInterface = assign({}, EventInterface, {\n clipboardData: function (event) {\n return \"clipboardData\" in event\n ? event.clipboardData\n : window.clipboardData;\n }\n }),\n SyntheticClipboardEvent = createSyntheticEvent(ClipboardEventInterface),\n CompositionEventInterface = assign({}, EventInterface, { data: 0 }),\n SyntheticCompositionEvent = createSyntheticEvent(CompositionEventInterface),\n normalizeKey = {\n Esc: \"Escape\",\n Spacebar: \" \",\n Left: \"ArrowLeft\",\n Up: \"ArrowUp\",\n Right: \"ArrowRight\",\n Down: \"ArrowDown\",\n Del: \"Delete\",\n Win: \"OS\",\n Menu: \"ContextMenu\",\n Apps: \"ContextMenu\",\n Scroll: \"ScrollLock\",\n MozPrintableKey: \"Unidentified\"\n },\n translateToKey = {\n 8: \"Backspace\",\n 9: \"Tab\",\n 12: \"Clear\",\n 13: \"Enter\",\n 16: \"Shift\",\n 17: \"Control\",\n 18: \"Alt\",\n 19: \"Pause\",\n 20: \"CapsLock\",\n 27: \"Escape\",\n 32: \" \",\n 33: \"PageUp\",\n 34: \"PageDown\",\n 35: \"End\",\n 36: \"Home\",\n 37: \"ArrowLeft\",\n 38: \"ArrowUp\",\n 39: \"ArrowRight\",\n 40: \"ArrowDown\",\n 45: \"Insert\",\n 46: \"Delete\",\n 112: \"F1\",\n 113: \"F2\",\n 114: \"F3\",\n 115: \"F4\",\n 116: \"F5\",\n 117: \"F6\",\n 118: \"F7\",\n 119: \"F8\",\n 120: \"F9\",\n 121: \"F10\",\n 122: \"F11\",\n 123: \"F12\",\n 144: \"NumLock\",\n 145: \"ScrollLock\",\n 224: \"Meta\"\n },\n modifierKeyToProp = {\n Alt: \"altKey\",\n Control: \"ctrlKey\",\n Meta: \"metaKey\",\n Shift: \"shiftKey\"\n };\nfunction modifierStateGetter(keyArg) {\n var nativeEvent = this.nativeEvent;\n return nativeEvent.getModifierState\n ? nativeEvent.getModifierState(keyArg)\n : (keyArg = modifierKeyToProp[keyArg])\n ? !!nativeEvent[keyArg]\n : !1;\n}\nfunction getEventModifierState() {\n return modifierStateGetter;\n}\nvar KeyboardEventInterface = assign({}, UIEventInterface, {\n key: function (nativeEvent) {\n if (nativeEvent.key) {\n var key = normalizeKey[nativeEvent.key] || nativeEvent.key;\n if (\"Unidentified\" !== key) return key;\n }\n return \"keypress\" === nativeEvent.type\n ? ((nativeEvent = getEventCharCode(nativeEvent)),\n 13 === nativeEvent ? \"Enter\" : String.fromCharCode(nativeEvent))\n : \"keydown\" === nativeEvent.type || \"keyup\" === nativeEvent.type\n ? translateToKey[nativeEvent.keyCode] || \"Unidentified\"\n : \"\";\n },\n code: 0,\n location: 0,\n ctrlKey: 0,\n shiftKey: 0,\n altKey: 0,\n metaKey: 0,\n repeat: 0,\n locale: 0,\n getModifierState: getEventModifierState,\n charCode: function (event) {\n return \"keypress\" === event.type ? getEventCharCode(event) : 0;\n },\n keyCode: function (event) {\n return \"keydown\" === event.type || \"keyup\" === event.type\n ? event.keyCode\n : 0;\n },\n which: function (event) {\n return \"keypress\" === event.type\n ? getEventCharCode(event)\n : \"keydown\" === event.type || \"keyup\" === event.type\n ? event.keyCode\n : 0;\n }\n }),\n SyntheticKeyboardEvent = createSyntheticEvent(KeyboardEventInterface),\n PointerEventInterface = assign({}, MouseEventInterface, {\n pointerId: 0,\n width: 0,\n height: 0,\n pressure: 0,\n tangentialPressure: 0,\n tiltX: 0,\n tiltY: 0,\n twist: 0,\n pointerType: 0,\n isPrimary: 0\n }),\n SyntheticPointerEvent = createSyntheticEvent(PointerEventInterface),\n TouchEventInterface = assign({}, UIEventInterface, {\n touches: 0,\n targetTouches: 0,\n changedTouches: 0,\n altKey: 0,\n metaKey: 0,\n ctrlKey: 0,\n shiftKey: 0,\n getModifierState: getEventModifierState\n }),\n SyntheticTouchEvent = createSyntheticEvent(TouchEventInterface),\n TransitionEventInterface = assign({}, EventInterface, {\n propertyName: 0,\n elapsedTime: 0,\n pseudoElement: 0\n }),\n SyntheticTransitionEvent = createSyntheticEvent(TransitionEventInterface),\n WheelEventInterface = assign({}, MouseEventInterface, {\n deltaX: function (event) {\n return \"deltaX\" in event\n ? event.deltaX\n : \"wheelDeltaX\" in event\n ? -event.wheelDeltaX\n : 0;\n },\n deltaY: function (event) {\n return \"deltaY\" in event\n ? event.deltaY\n : \"wheelDeltaY\" in event\n ? -event.wheelDeltaY\n : \"wheelDelta\" in event\n ? -event.wheelDelta\n : 0;\n },\n deltaZ: 0,\n deltaMode: 0\n }),\n SyntheticWheelEvent = createSyntheticEvent(WheelEventInterface),\n ToggleEventInterface = assign({}, EventInterface, {\n newState: 0,\n oldState: 0\n }),\n SyntheticToggleEvent = createSyntheticEvent(ToggleEventInterface),\n END_KEYCODES = [9, 13, 27, 32],\n canUseCompositionEvent = canUseDOM && \"CompositionEvent\" in window,\n documentMode = null;\ncanUseDOM &&\n \"documentMode\" in document &&\n (documentMode = document.documentMode);\nvar canUseTextInputEvent = canUseDOM && \"TextEvent\" in window && !documentMode,\n useFallbackCompositionData =\n canUseDOM &&\n (!canUseCompositionEvent ||\n (documentMode && 8 < documentMode && 11 >= documentMode)),\n SPACEBAR_CHAR = String.fromCharCode(32),\n hasSpaceKeypress = !1;\nfunction isFallbackCompositionEnd(domEventName, nativeEvent) {\n switch (domEventName) {\n case \"keyup\":\n return -1 !== END_KEYCODES.indexOf(nativeEvent.keyCode);\n case \"keydown\":\n return 229 !== nativeEvent.keyCode;\n case \"keypress\":\n case \"mousedown\":\n case \"focusout\":\n return !0;\n default:\n return !1;\n }\n}\nfunction getDataFromCustomEvent(nativeEvent) {\n nativeEvent = nativeEvent.detail;\n return \"object\" === typeof nativeEvent && \"data\" in nativeEvent\n ? nativeEvent.data\n : null;\n}\nvar isComposing = !1;\nfunction getNativeBeforeInputChars(domEventName, nativeEvent) {\n switch (domEventName) {\n case \"compositionend\":\n return getDataFromCustomEvent(nativeEvent);\n case \"keypress\":\n if (32 !== nativeEvent.which) return null;\n hasSpaceKeypress = !0;\n return SPACEBAR_CHAR;\n case \"textInput\":\n return (\n (domEventName = nativeEvent.data),\n domEventName === SPACEBAR_CHAR && hasSpaceKeypress ? null : domEventName\n );\n default:\n return null;\n }\n}\nfunction getFallbackBeforeInputChars(domEventName, nativeEvent) {\n if (isComposing)\n return \"compositionend\" === domEventName ||\n (!canUseCompositionEvent &&\n isFallbackCompositionEnd(domEventName, nativeEvent))\n ? ((domEventName = getData()),\n (fallbackText = startText = root = null),\n (isComposing = !1),\n domEventName)\n : null;\n switch (domEventName) {\n case \"paste\":\n return null;\n case \"keypress\":\n if (\n !(nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) ||\n (nativeEvent.ctrlKey && nativeEvent.altKey)\n ) {\n if (nativeEvent.char && 1 < nativeEvent.char.length)\n return nativeEvent.char;\n if (nativeEvent.which) return String.fromCharCode(nativeEvent.which);\n }\n return null;\n case \"compositionend\":\n return useFallbackCompositionData && \"ko\" !== nativeEvent.locale\n ? null\n : nativeEvent.data;\n default:\n return null;\n }\n}\nvar supportedInputTypes = {\n color: !0,\n date: !0,\n datetime: !0,\n \"datetime-local\": !0,\n email: !0,\n month: !0,\n number: !0,\n password: !0,\n range: !0,\n search: !0,\n tel: !0,\n text: !0,\n time: !0,\n url: !0,\n week: !0\n};\nfunction isTextInputElement(elem) {\n var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();\n return \"input\" === nodeName\n ? !!supportedInputTypes[elem.type]\n : \"textarea\" === nodeName\n ? !0\n : !1;\n}\nfunction createAndAccumulateChangeEvent(\n dispatchQueue,\n inst,\n nativeEvent,\n target\n) {\n restoreTarget\n ? restoreQueue\n ? restoreQueue.push(target)\n : (restoreQueue = [target])\n : (restoreTarget = target);\n inst = accumulateTwoPhaseListeners(inst, \"onChange\");\n 0 < inst.length &&\n ((nativeEvent = new SyntheticEvent(\n \"onChange\",\n \"change\",\n null,\n nativeEvent,\n target\n )),\n dispatchQueue.push({ event: nativeEvent, listeners: inst }));\n}\nvar activeElement$1 = null,\n activeElementInst$1 = null;\nfunction runEventInBatch(dispatchQueue) {\n processDispatchQueue(dispatchQueue, 0);\n}\nfunction getInstIfValueChanged(targetInst) {\n var targetNode = getNodeFromInstance(targetInst);\n if (updateValueIfChanged(targetNode)) return targetInst;\n}\nfunction getTargetInstForChangeEvent(domEventName, targetInst) {\n if (\"change\" === domEventName) return targetInst;\n}\nvar isInputEventSupported = !1;\nif (canUseDOM) {\n var JSCompiler_inline_result$jscomp$286;\n if (canUseDOM) {\n var isSupported$jscomp$inline_427 = \"oninput\" in document;\n if (!isSupported$jscomp$inline_427) {\n var element$jscomp$inline_428 = document.createElement(\"div\");\n element$jscomp$inline_428.setAttribute(\"oninput\", \"return;\");\n isSupported$jscomp$inline_427 =\n \"function\" === typeof element$jscomp$inline_428.oninput;\n }\n JSCompiler_inline_result$jscomp$286 = isSupported$jscomp$inline_427;\n } else JSCompiler_inline_result$jscomp$286 = !1;\n isInputEventSupported =\n JSCompiler_inline_result$jscomp$286 &&\n (!document.documentMode || 9 < document.documentMode);\n}\nfunction stopWatchingForValueChange() {\n activeElement$1 &&\n (activeElement$1.detachEvent(\"onpropertychange\", handlePropertyChange),\n (activeElementInst$1 = activeElement$1 = null));\n}\nfunction handlePropertyChange(nativeEvent) {\n if (\n \"value\" === nativeEvent.propertyName &&\n getInstIfValueChanged(activeElementInst$1)\n ) {\n var dispatchQueue = [];\n createAndAccumulateChangeEvent(\n dispatchQueue,\n activeElementInst$1,\n nativeEvent,\n getEventTarget(nativeEvent)\n );\n batchedUpdates$1(runEventInBatch, dispatchQueue);\n }\n}\nfunction handleEventsForInputEventPolyfill(domEventName, target, targetInst) {\n \"focusin\" === domEventName\n ? (stopWatchingForValueChange(),\n (activeElement$1 = target),\n (activeElementInst$1 = targetInst),\n activeElement$1.attachEvent(\"onpropertychange\", handlePropertyChange))\n : \"focusout\" === domEventName && stopWatchingForValueChange();\n}\nfunction getTargetInstForInputEventPolyfill(domEventName) {\n if (\n \"selectionchange\" === domEventName ||\n \"keyup\" === domEventName ||\n \"keydown\" === domEventName\n )\n return getInstIfValueChanged(activeElementInst$1);\n}\nfunction getTargetInstForClickEvent(domEventName, targetInst) {\n if (\"click\" === domEventName) return getInstIfValueChanged(targetInst);\n}\nfunction getTargetInstForInputOrChangeEvent(domEventName, targetInst) {\n if (\"input\" === domEventName || \"change\" === domEventName)\n return getInstIfValueChanged(targetInst);\n}\nfunction is(x, y) {\n return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);\n}\nvar objectIs = \"function\" === typeof Object.is ? Object.is : is;\nfunction shallowEqual(objA, objB) {\n if (objectIs(objA, objB)) return !0;\n if (\n \"object\" !== typeof objA ||\n null === objA ||\n \"object\" !== typeof objB ||\n null === objB\n )\n return !1;\n var keysA = Object.keys(objA),\n keysB = Object.keys(objB);\n if (keysA.length !== keysB.length) return !1;\n for (keysB = 0; keysB < keysA.length; keysB++) {\n var currentKey = keysA[keysB];\n if (\n !hasOwnProperty.call(objB, currentKey) ||\n !objectIs(objA[currentKey], objB[currentKey])\n )\n return !1;\n }\n return !0;\n}\nfunction getLeafNode(node) {\n for (; node && node.firstChild; ) node = node.firstChild;\n return node;\n}\nfunction getNodeForCharacterOffset(root, offset) {\n var node = getLeafNode(root);\n root = 0;\n for (var nodeEnd; node; ) {\n if (3 === node.nodeType) {\n nodeEnd = root + node.textContent.length;\n if (root <= offset && nodeEnd >= offset)\n return { node: node, offset: offset - root };\n root = nodeEnd;\n }\n a: {\n for (; node; ) {\n if (node.nextSibling) {\n node = node.nextSibling;\n break a;\n }\n node = node.parentNode;\n }\n node = void 0;\n }\n node = getLeafNode(node);\n }\n}\nfunction containsNode(outerNode, innerNode) {\n return outerNode && innerNode\n ? outerNode === innerNode\n ? !0\n : outerNode && 3 === outerNode.nodeType\n ? !1\n : innerNode && 3 === innerNode.nodeType\n ? containsNode(outerNode, innerNode.parentNode)\n : \"contains\" in outerNode\n ? outerNode.contains(innerNode)\n : outerNode.compareDocumentPosition\n ? !!(outerNode.compareDocumentPosition(innerNode) & 16)\n : !1\n : !1;\n}\nfunction getActiveElementDeep(containerInfo) {\n containerInfo =\n null != containerInfo &&\n null != containerInfo.ownerDocument &&\n null != containerInfo.ownerDocument.defaultView\n ? containerInfo.ownerDocument.defaultView\n : window;\n for (\n var element = getActiveElement(containerInfo.document);\n element instanceof containerInfo.HTMLIFrameElement;\n\n ) {\n try {\n var JSCompiler_inline_result =\n \"string\" === typeof element.contentWindow.location.href;\n } catch (err) {\n JSCompiler_inline_result = !1;\n }\n if (JSCompiler_inline_result) containerInfo = element.contentWindow;\n else break;\n element = getActiveElement(containerInfo.document);\n }\n return element;\n}\nfunction hasSelectionCapabilities(elem) {\n var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();\n return (\n nodeName &&\n ((\"input\" === nodeName &&\n (\"text\" === elem.type ||\n \"search\" === elem.type ||\n \"tel\" === elem.type ||\n \"url\" === elem.type ||\n \"password\" === elem.type)) ||\n \"textarea\" === nodeName ||\n \"true\" === elem.contentEditable)\n );\n}\nvar skipSelectionChangeEvent =\n canUseDOM && \"documentMode\" in document && 11 >= document.documentMode,\n activeElement = null,\n activeElementInst = null,\n lastSelection = null,\n mouseDown = !1;\nfunction constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget) {\n var doc =\n nativeEventTarget.window === nativeEventTarget\n ? nativeEventTarget.document\n : 9 === nativeEventTarget.nodeType\n ? nativeEventTarget\n : nativeEventTarget.ownerDocument;\n mouseDown ||\n null == activeElement ||\n activeElement !== getActiveElement(doc) ||\n ((doc = activeElement),\n \"selectionStart\" in doc && hasSelectionCapabilities(doc)\n ? (doc = { start: doc.selectionStart, end: doc.selectionEnd })\n : ((doc = (\n (doc.ownerDocument && doc.ownerDocument.defaultView) ||\n window\n ).getSelection()),\n (doc = {\n anchorNode: doc.anchorNode,\n anchorOffset: doc.anchorOffset,\n focusNode: doc.focusNode,\n focusOffset: doc.focusOffset\n })),\n (lastSelection && shallowEqual(lastSelection, doc)) ||\n ((lastSelection = doc),\n (doc = accumulateTwoPhaseListeners(activeElementInst, \"onSelect\")),\n 0 < doc.length &&\n ((nativeEvent = new SyntheticEvent(\n \"onSelect\",\n \"select\",\n null,\n nativeEvent,\n nativeEventTarget\n )),\n dispatchQueue.push({ event: nativeEvent, listeners: doc }),\n (nativeEvent.target = activeElement))));\n}\nfunction makePrefixMap(styleProp, eventName) {\n var prefixes = {};\n prefixes[styleProp.toLowerCase()] = eventName.toLowerCase();\n prefixes[\"Webkit\" + styleProp] = \"webkit\" + eventName;\n prefixes[\"Moz\" + styleProp] = \"moz\" + eventName;\n return prefixes;\n}\nvar vendorPrefixes = {\n animationend: makePrefixMap(\"Animation\", \"AnimationEnd\"),\n animationiteration: makePrefixMap(\"Animation\", \"AnimationIteration\"),\n animationstart: makePrefixMap(\"Animation\", \"AnimationStart\"),\n transitionrun: makePrefixMap(\"Transition\", \"TransitionRun\"),\n transitionstart: makePrefixMap(\"Transition\", \"TransitionStart\"),\n transitioncancel: makePrefixMap(\"Transition\", \"TransitionCancel\"),\n transitionend: makePrefixMap(\"Transition\", \"TransitionEnd\")\n },\n prefixedEventNames = {},\n style = {};\ncanUseDOM &&\n ((style = document.createElement(\"div\").style),\n \"AnimationEvent\" in window ||\n (delete vendorPrefixes.animationend.animation,\n delete vendorPrefixes.animationiteration.animation,\n delete vendorPrefixes.animationstart.animation),\n \"TransitionEvent\" in window ||\n delete vendorPrefixes.transitionend.transition);\nfunction getVendorPrefixedEventName(eventName) {\n if (prefixedEventNames[eventName]) return prefixedEventNames[eventName];\n if (!vendorPrefixes[eventName]) return eventName;\n var prefixMap = vendorPrefixes[eventName],\n styleProp;\n for (styleProp in prefixMap)\n if (prefixMap.hasOwnProperty(styleProp) && styleProp in style)\n return (prefixedEventNames[eventName] = prefixMap[styleProp]);\n return eventName;\n}\nvar ANIMATION_END = getVendorPrefixedEventName(\"animationend\"),\n ANIMATION_ITERATION = getVendorPrefixedEventName(\"animationiteration\"),\n ANIMATION_START = getVendorPrefixedEventName(\"animationstart\"),\n TRANSITION_RUN = getVendorPrefixedEventName(\"transitionrun\"),\n TRANSITION_START = getVendorPrefixedEventName(\"transitionstart\"),\n TRANSITION_CANCEL = getVendorPrefixedEventName(\"transitioncancel\"),\n TRANSITION_END = getVendorPrefixedEventName(\"transitionend\"),\n topLevelEventsToReactNames = new Map(),\n simpleEventPluginEvents =\n \"abort auxClick beforeToggle cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel\".split(\n \" \"\n );\nsimpleEventPluginEvents.push(\"scrollEnd\");\nfunction registerSimpleEvent(domEventName, reactName) {\n topLevelEventsToReactNames.set(domEventName, reactName);\n registerTwoPhaseEvent(reactName, [domEventName]);\n}\nvar reportGlobalError =\n \"function\" === typeof reportError\n ? reportError\n : function (error) {\n if (\n \"object\" === typeof window &&\n \"function\" === typeof window.ErrorEvent\n ) {\n var event = new window.ErrorEvent(\"error\", {\n bubbles: !0,\n cancelable: !0,\n message:\n \"object\" === typeof error &&\n null !== error &&\n \"string\" === typeof error.message\n ? String(error.message)\n : String(error),\n error: error\n });\n if (!window.dispatchEvent(event)) return;\n } else if (\n \"object\" === typeof process &&\n \"function\" === typeof process.emit\n ) {\n process.emit(\"uncaughtException\", error);\n return;\n }\n console.error(error);\n },\n concurrentQueues = [],\n concurrentQueuesIndex = 0,\n concurrentlyUpdatedLanes = 0;\nfunction finishQueueingConcurrentUpdates() {\n for (\n var endIndex = concurrentQueuesIndex,\n i = (concurrentlyUpdatedLanes = concurrentQueuesIndex = 0);\n i < endIndex;\n\n ) {\n var fiber = concurrentQueues[i];\n concurrentQueues[i++] = null;\n var queue = concurrentQueues[i];\n concurrentQueues[i++] = null;\n var update = concurrentQueues[i];\n concurrentQueues[i++] = null;\n var lane = concurrentQueues[i];\n concurrentQueues[i++] = null;\n if (null !== queue && null !== update) {\n var pending = queue.pending;\n null === pending\n ? (update.next = update)\n : ((update.next = pending.next), (pending.next = update));\n queue.pending = update;\n }\n 0 !== lane && markUpdateLaneFromFiberToRoot(fiber, update, lane);\n }\n}\nfunction enqueueUpdate$1(fiber, queue, update, lane) {\n concurrentQueues[concurrentQueuesIndex++] = fiber;\n concurrentQueues[concurrentQueuesIndex++] = queue;\n concurrentQueues[concurrentQueuesIndex++] = update;\n concurrentQueues[concurrentQueuesIndex++] = lane;\n concurrentlyUpdatedLanes |= lane;\n fiber.lanes |= lane;\n fiber = fiber.alternate;\n null !== fiber && (fiber.lanes |= lane);\n}\nfunction enqueueConcurrentHookUpdate(fiber, queue, update, lane) {\n enqueueUpdate$1(fiber, queue, update, lane);\n return getRootForUpdatedFiber(fiber);\n}\nfunction enqueueConcurrentRenderForLane(fiber, lane) {\n enqueueUpdate$1(fiber, null, null, lane);\n return getRootForUpdatedFiber(fiber);\n}\nfunction markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) {\n sourceFiber.lanes |= lane;\n var alternate = sourceFiber.alternate;\n null !== alternate && (alternate.lanes |= lane);\n for (var isHidden = !1, parent = sourceFiber.return; null !== parent; )\n (parent.childLanes |= lane),\n (alternate = parent.alternate),\n null !== alternate && (alternate.childLanes |= lane),\n 22 === parent.tag &&\n ((sourceFiber = parent.stateNode),\n null === sourceFiber || sourceFiber._visibility & 1 || (isHidden = !0)),\n (sourceFiber = parent),\n (parent = parent.return);\n return 3 === sourceFiber.tag\n ? ((parent = sourceFiber.stateNode),\n isHidden &&\n null !== update &&\n ((isHidden = 31 - clz32(lane)),\n (sourceFiber = parent.hiddenUpdates),\n (alternate = sourceFiber[isHidden]),\n null === alternate\n ? (sourceFiber[isHidden] = [update])\n : alternate.push(update),\n (update.lane = lane | 536870912)),\n parent)\n : null;\n}\nfunction getRootForUpdatedFiber(sourceFiber) {\n if (50 < nestedUpdateCount)\n throw (\n ((nestedUpdateCount = 0),\n (rootWithNestedUpdates = null),\n Error(formatProdErrorMessage(185)))\n );\n for (var parent = sourceFiber.return; null !== parent; )\n (sourceFiber = parent), (parent = sourceFiber.return);\n return 3 === sourceFiber.tag ? sourceFiber.stateNode : null;\n}\nvar emptyContextObject = {};\nfunction FiberNode(tag, pendingProps, key, mode) {\n this.tag = tag;\n this.key = key;\n this.sibling =\n this.child =\n this.return =\n this.stateNode =\n this.type =\n this.elementType =\n null;\n this.index = 0;\n this.refCleanup = this.ref = null;\n this.pendingProps = pendingProps;\n this.dependencies =\n this.memoizedState =\n this.updateQueue =\n this.memoizedProps =\n null;\n this.mode = mode;\n this.subtreeFlags = this.flags = 0;\n this.deletions = null;\n this.childLanes = this.lanes = 0;\n this.alternate = null;\n}\nfunction createFiberImplClass(tag, pendingProps, key, mode) {\n return new FiberNode(tag, pendingProps, key, mode);\n}\nfunction shouldConstruct(Component) {\n Component = Component.prototype;\n return !(!Component || !Component.isReactComponent);\n}\nfunction createWorkInProgress(current, pendingProps) {\n var workInProgress = current.alternate;\n null === workInProgress\n ? ((workInProgress = createFiberImplClass(\n current.tag,\n pendingProps,\n current.key,\n current.mode\n )),\n (workInProgress.elementType = current.elementType),\n (workInProgress.type = current.type),\n (workInProgress.stateNode = current.stateNode),\n (workInProgress.alternate = current),\n (current.alternate = workInProgress))\n : ((workInProgress.pendingProps = pendingProps),\n (workInProgress.type = current.type),\n (workInProgress.flags = 0),\n (workInProgress.subtreeFlags = 0),\n (workInProgress.deletions = null));\n workInProgress.flags = current.flags & 65011712;\n workInProgress.childLanes = current.childLanes;\n workInProgress.lanes = current.lanes;\n workInProgress.child = current.child;\n workInProgress.memoizedProps = current.memoizedProps;\n workInProgress.memoizedState = current.memoizedState;\n workInProgress.updateQueue = current.updateQueue;\n pendingProps = current.dependencies;\n workInProgress.dependencies =\n null === pendingProps\n ? null\n : { lanes: pendingProps.lanes, firstContext: pendingProps.firstContext };\n workInProgress.sibling = current.sibling;\n workInProgress.index = current.index;\n workInProgress.ref = current.ref;\n workInProgress.refCleanup = current.refCleanup;\n return workInProgress;\n}\nfunction resetWorkInProgress(workInProgress, renderLanes) {\n workInProgress.flags &= 65011714;\n var current = workInProgress.alternate;\n null === current\n ? ((workInProgress.childLanes = 0),\n (workInProgress.lanes = renderLanes),\n (workInProgress.child = null),\n (workInProgress.subtreeFlags = 0),\n (workInProgress.memoizedProps = null),\n (workInProgress.memoizedState = null),\n (workInProgress.updateQueue = null),\n (workInProgress.dependencies = null),\n (workInProgress.stateNode = null))\n : ((workInProgress.childLanes = current.childLanes),\n (workInProgress.lanes = current.lanes),\n (workInProgress.child = current.child),\n (workInProgress.subtreeFlags = 0),\n (workInProgress.deletions = null),\n (workInProgress.memoizedProps = current.memoizedProps),\n (workInProgress.memoizedState = current.memoizedState),\n (workInProgress.updateQueue = current.updateQueue),\n (workInProgress.type = current.type),\n (renderLanes = current.dependencies),\n (workInProgress.dependencies =\n null === renderLanes\n ? null\n : {\n lanes: renderLanes.lanes,\n firstContext: renderLanes.firstContext\n }));\n return workInProgress;\n}\nfunction createFiberFromTypeAndProps(\n type,\n key,\n pendingProps,\n owner,\n mode,\n lanes\n) {\n var fiberTag = 0;\n owner = type;\n if (\"function\" === typeof type) shouldConstruct(type) && (fiberTag = 1);\n else if (\"string\" === typeof type)\n fiberTag = isHostHoistableType(\n type,\n pendingProps,\n contextStackCursor.current\n )\n ? 26\n : \"html\" === type || \"head\" === type || \"body\" === type\n ? 27\n : 5;\n else\n a: switch (type) {\n case REACT_ACTIVITY_TYPE:\n return (\n (type = createFiberImplClass(31, pendingProps, key, mode)),\n (type.elementType = REACT_ACTIVITY_TYPE),\n (type.lanes = lanes),\n type\n );\n case REACT_FRAGMENT_TYPE:\n return createFiberFromFragment(pendingProps.children, mode, lanes, key);\n case REACT_STRICT_MODE_TYPE:\n fiberTag = 8;\n mode |= 24;\n break;\n case REACT_PROFILER_TYPE:\n return (\n (type = createFiberImplClass(12, pendingProps, key, mode | 2)),\n (type.elementType = REACT_PROFILER_TYPE),\n (type.lanes = lanes),\n type\n );\n case REACT_SUSPENSE_TYPE:\n return (\n (type = createFiberImplClass(13, pendingProps, key, mode)),\n (type.elementType = REACT_SUSPENSE_TYPE),\n (type.lanes = lanes),\n type\n );\n case REACT_SUSPENSE_LIST_TYPE:\n return (\n (type = createFiberImplClass(19, pendingProps, key, mode)),\n (type.elementType = REACT_SUSPENSE_LIST_TYPE),\n (type.lanes = lanes),\n type\n );\n default:\n if (\"object\" === typeof type && null !== type)\n switch (type.$$typeof) {\n case REACT_CONTEXT_TYPE:\n fiberTag = 10;\n break a;\n case REACT_CONSUMER_TYPE:\n fiberTag = 9;\n break a;\n case REACT_FORWARD_REF_TYPE:\n fiberTag = 11;\n break a;\n case REACT_MEMO_TYPE:\n fiberTag = 14;\n break a;\n case REACT_LAZY_TYPE:\n fiberTag = 16;\n owner = null;\n break a;\n }\n fiberTag = 29;\n pendingProps = Error(\n formatProdErrorMessage(130, null === type ? \"null\" : typeof type, \"\")\n );\n owner = null;\n }\n key = createFiberImplClass(fiberTag, pendingProps, key, mode);\n key.elementType = type;\n key.type = owner;\n key.lanes = lanes;\n return key;\n}\nfunction createFiberFromFragment(elements, mode, lanes, key) {\n elements = createFiberImplClass(7, elements, key, mode);\n elements.lanes = lanes;\n return elements;\n}\nfunction createFiberFromText(content, mode, lanes) {\n content = createFiberImplClass(6, content, null, mode);\n content.lanes = lanes;\n return content;\n}\nfunction createFiberFromDehydratedFragment(dehydratedNode) {\n var fiber = createFiberImplClass(18, null, null, 0);\n fiber.stateNode = dehydratedNode;\n return fiber;\n}\nfunction createFiberFromPortal(portal, mode, lanes) {\n mode = createFiberImplClass(\n 4,\n null !== portal.children ? portal.children : [],\n portal.key,\n mode\n );\n mode.lanes = lanes;\n mode.stateNode = {\n containerInfo: portal.containerInfo,\n pendingChildren: null,\n implementation: portal.implementation\n };\n return mode;\n}\nvar CapturedStacks = new WeakMap();\nfunction createCapturedValueAtFiber(value, source) {\n if (\"object\" === typeof value && null !== value) {\n var existing = CapturedStacks.get(value);\n if (void 0 !== existing) return existing;\n source = {\n value: value,\n source: source,\n stack: getStackByFiberInDevAndProd(source)\n };\n CapturedStacks.set(value, source);\n return source;\n }\n return {\n value: value,\n source: source,\n stack: getStackByFiberInDevAndProd(source)\n };\n}\nvar forkStack = [],\n forkStackIndex = 0,\n treeForkProvider = null,\n treeForkCount = 0,\n idStack = [],\n idStackIndex = 0,\n treeContextProvider = null,\n treeContextId = 1,\n treeContextOverflow = \"\";\nfunction pushTreeFork(workInProgress, totalChildren) {\n forkStack[forkStackIndex++] = treeForkCount;\n forkStack[forkStackIndex++] = treeForkProvider;\n treeForkProvider = workInProgress;\n treeForkCount = totalChildren;\n}\nfunction pushTreeId(workInProgress, totalChildren, index) {\n idStack[idStackIndex++] = treeContextId;\n idStack[idStackIndex++] = treeContextOverflow;\n idStack[idStackIndex++] = treeContextProvider;\n treeContextProvider = workInProgress;\n var baseIdWithLeadingBit = treeContextId;\n workInProgress = treeContextOverflow;\n var baseLength = 32 - clz32(baseIdWithLeadingBit) - 1;\n baseIdWithLeadingBit &= ~(1 << baseLength);\n index += 1;\n var length = 32 - clz32(totalChildren) + baseLength;\n if (30 < length) {\n var numberOfOverflowBits = baseLength - (baseLength % 5);\n length = (\n baseIdWithLeadingBit &\n ((1 << numberOfOverflowBits) - 1)\n ).toString(32);\n baseIdWithLeadingBit >>= numberOfOverflowBits;\n baseLength -= numberOfOverflowBits;\n treeContextId =\n (1 << (32 - clz32(totalChildren) + baseLength)) |\n (index << baseLength) |\n baseIdWithLeadingBit;\n treeContextOverflow = length + workInProgress;\n } else\n (treeContextId =\n (1 << length) | (index << baseLength) | baseIdWithLeadingBit),\n (treeContextOverflow = workInProgress);\n}\nfunction pushMaterializedTreeId(workInProgress) {\n null !== workInProgress.return &&\n (pushTreeFork(workInProgress, 1), pushTreeId(workInProgress, 1, 0));\n}\nfunction popTreeContext(workInProgress) {\n for (; workInProgress === treeForkProvider; )\n (treeForkProvider = forkStack[--forkStackIndex]),\n (forkStack[forkStackIndex] = null),\n (treeForkCount = forkStack[--forkStackIndex]),\n (forkStack[forkStackIndex] = null);\n for (; workInProgress === treeContextProvider; )\n (treeContextProvider = idStack[--idStackIndex]),\n (idStack[idStackIndex] = null),\n (treeContextOverflow = idStack[--idStackIndex]),\n (idStack[idStackIndex] = null),\n (treeContextId = idStack[--idStackIndex]),\n (idStack[idStackIndex] = null);\n}\nfunction restoreSuspendedTreeContext(workInProgress, suspendedContext) {\n idStack[idStackIndex++] = treeContextId;\n idStack[idStackIndex++] = treeContextOverflow;\n idStack[idStackIndex++] = treeContextProvider;\n treeContextId = suspendedContext.id;\n treeContextOverflow = suspendedContext.overflow;\n treeContextProvider = workInProgress;\n}\nvar hydrationParentFiber = null,\n nextHydratableInstance = null,\n isHydrating = !1,\n hydrationErrors = null,\n rootOrSingletonContext = !1,\n HydrationMismatchException = Error(formatProdErrorMessage(519));\nfunction throwOnHydrationMismatch(fiber) {\n var error = Error(\n formatProdErrorMessage(\n 418,\n 1 < arguments.length && void 0 !== arguments[1] && arguments[1]\n ? \"text\"\n : \"HTML\",\n \"\"\n )\n );\n queueHydrationError(createCapturedValueAtFiber(error, fiber));\n throw HydrationMismatchException;\n}\nfunction prepareToHydrateHostInstance(fiber) {\n var instance = fiber.stateNode,\n type = fiber.type,\n props = fiber.memoizedProps;\n instance[internalInstanceKey] = fiber;\n instance[internalPropsKey] = props;\n switch (type) {\n case \"dialog\":\n listenToNonDelegatedEvent(\"cancel\", instance);\n listenToNonDelegatedEvent(\"close\", instance);\n break;\n case \"iframe\":\n case \"object\":\n case \"embed\":\n listenToNonDelegatedEvent(\"load\", instance);\n break;\n case \"video\":\n case \"audio\":\n for (type = 0; type < mediaEventTypes.length; type++)\n listenToNonDelegatedEvent(mediaEventTypes[type], instance);\n break;\n case \"source\":\n listenToNonDelegatedEvent(\"error\", instance);\n break;\n case \"img\":\n case \"image\":\n case \"link\":\n listenToNonDelegatedEvent(\"error\", instance);\n listenToNonDelegatedEvent(\"load\", instance);\n break;\n case \"details\":\n listenToNonDelegatedEvent(\"toggle\", instance);\n break;\n case \"input\":\n listenToNonDelegatedEvent(\"invalid\", instance);\n initInput(\n instance,\n props.value,\n props.defaultValue,\n props.checked,\n props.defaultChecked,\n props.type,\n props.name,\n !0\n );\n break;\n case \"select\":\n listenToNonDelegatedEvent(\"invalid\", instance);\n break;\n case \"textarea\":\n listenToNonDelegatedEvent(\"invalid\", instance),\n initTextarea(instance, props.value, props.defaultValue, props.children);\n }\n type = props.children;\n (\"string\" !== typeof type &&\n \"number\" !== typeof type &&\n \"bigint\" !== typeof type) ||\n instance.textContent === \"\" + type ||\n !0 === props.suppressHydrationWarning ||\n checkForUnmatchedText(instance.textContent, type)\n ? (null != props.popover &&\n (listenToNonDelegatedEvent(\"beforetoggle\", instance),\n listenToNonDelegatedEvent(\"toggle\", instance)),\n null != props.onScroll && listenToNonDelegatedEvent(\"scroll\", instance),\n null != props.onScrollEnd &&\n listenToNonDelegatedEvent(\"scrollend\", instance),\n null != props.onClick && (instance.onclick = noop$1),\n (instance = !0))\n : (instance = !1);\n instance || throwOnHydrationMismatch(fiber, !0);\n}\nfunction popToNextHostParent(fiber) {\n for (hydrationParentFiber = fiber.return; hydrationParentFiber; )\n switch (hydrationParentFiber.tag) {\n case 5:\n case 31:\n case 13:\n rootOrSingletonContext = !1;\n return;\n case 27:\n case 3:\n rootOrSingletonContext = !0;\n return;\n default:\n hydrationParentFiber = hydrationParentFiber.return;\n }\n}\nfunction popHydrationState(fiber) {\n if (fiber !== hydrationParentFiber) return !1;\n if (!isHydrating) return popToNextHostParent(fiber), (isHydrating = !0), !1;\n var tag = fiber.tag,\n JSCompiler_temp;\n if ((JSCompiler_temp = 3 !== tag && 27 !== tag)) {\n if ((JSCompiler_temp = 5 === tag))\n (JSCompiler_temp = fiber.type),\n (JSCompiler_temp =\n !(\"form\" !== JSCompiler_temp && \"button\" !== JSCompiler_temp) ||\n shouldSetTextContent(fiber.type, fiber.memoizedProps));\n JSCompiler_temp = !JSCompiler_temp;\n }\n JSCompiler_temp && nextHydratableInstance && throwOnHydrationMismatch(fiber);\n popToNextHostParent(fiber);\n if (13 === tag) {\n fiber = fiber.memoizedState;\n fiber = null !== fiber ? fiber.dehydrated : null;\n if (!fiber) throw Error(formatProdErrorMessage(317));\n nextHydratableInstance =\n getNextHydratableInstanceAfterHydrationBoundary(fiber);\n } else if (31 === tag) {\n fiber = fiber.memoizedState;\n fiber = null !== fiber ? fiber.dehydrated : null;\n if (!fiber) throw Error(formatProdErrorMessage(317));\n nextHydratableInstance =\n getNextHydratableInstanceAfterHydrationBoundary(fiber);\n } else\n 27 === tag\n ? ((tag = nextHydratableInstance),\n isSingletonScope(fiber.type)\n ? ((fiber = previousHydratableOnEnteringScopedSingleton),\n (previousHydratableOnEnteringScopedSingleton = null),\n (nextHydratableInstance = fiber))\n : (nextHydratableInstance = tag))\n : (nextHydratableInstance = hydrationParentFiber\n ? getNextHydratable(fiber.stateNode.nextSibling)\n : null);\n return !0;\n}\nfunction resetHydrationState() {\n nextHydratableInstance = hydrationParentFiber = null;\n isHydrating = !1;\n}\nfunction upgradeHydrationErrorsToRecoverable() {\n var queuedErrors = hydrationErrors;\n null !== queuedErrors &&\n (null === workInProgressRootRecoverableErrors\n ? (workInProgressRootRecoverableErrors = queuedErrors)\n : workInProgressRootRecoverableErrors.push.apply(\n workInProgressRootRecoverableErrors,\n queuedErrors\n ),\n (hydrationErrors = null));\n return queuedErrors;\n}\nfunction queueHydrationError(error) {\n null === hydrationErrors\n ? (hydrationErrors = [error])\n : hydrationErrors.push(error);\n}\nvar valueCursor = createCursor(null),\n currentlyRenderingFiber$1 = null,\n lastContextDependency = null;\nfunction pushProvider(providerFiber, context, nextValue) {\n push(valueCursor, context._currentValue);\n context._currentValue = nextValue;\n}\nfunction popProvider(context) {\n context._currentValue = valueCursor.current;\n pop(valueCursor);\n}\nfunction scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) {\n for (; null !== parent; ) {\n var alternate = parent.alternate;\n (parent.childLanes & renderLanes) !== renderLanes\n ? ((parent.childLanes |= renderLanes),\n null !== alternate && (alternate.childLanes |= renderLanes))\n : null !== alternate &&\n (alternate.childLanes & renderLanes) !== renderLanes &&\n (alternate.childLanes |= renderLanes);\n if (parent === propagationRoot) break;\n parent = parent.return;\n }\n}\nfunction propagateContextChanges(\n workInProgress,\n contexts,\n renderLanes,\n forcePropagateEntireTree\n) {\n var fiber = workInProgress.child;\n null !== fiber && (fiber.return = workInProgress);\n for (; null !== fiber; ) {\n var list = fiber.dependencies;\n if (null !== list) {\n var nextFiber = fiber.child;\n list = list.firstContext;\n a: for (; null !== list; ) {\n var dependency = list;\n list = fiber;\n for (var i = 0; i < contexts.length; i++)\n if (dependency.context === contexts[i]) {\n list.lanes |= renderLanes;\n dependency = list.alternate;\n null !== dependency && (dependency.lanes |= renderLanes);\n scheduleContextWorkOnParentPath(\n list.return,\n renderLanes,\n workInProgress\n );\n forcePropagateEntireTree || (nextFiber = null);\n break a;\n }\n list = dependency.next;\n }\n } else if (18 === fiber.tag) {\n nextFiber = fiber.return;\n if (null === nextFiber) throw Error(formatProdErrorMessage(341));\n nextFiber.lanes |= renderLanes;\n list = nextFiber.alternate;\n null !== list && (list.lanes |= renderLanes);\n scheduleContextWorkOnParentPath(nextFiber, renderLanes, workInProgress);\n nextFiber = null;\n } else nextFiber = fiber.child;\n if (null !== nextFiber) nextFiber.return = fiber;\n else\n for (nextFiber = fiber; null !== nextFiber; ) {\n if (nextFiber === workInProgress) {\n nextFiber = null;\n break;\n }\n fiber = nextFiber.sibling;\n if (null !== fiber) {\n fiber.return = nextFiber.return;\n nextFiber = fiber;\n break;\n }\n nextFiber = nextFiber.return;\n }\n fiber = nextFiber;\n }\n}\nfunction propagateParentContextChanges(\n current,\n workInProgress,\n renderLanes,\n forcePropagateEntireTree\n) {\n current = null;\n for (\n var parent = workInProgress, isInsidePropagationBailout = !1;\n null !== parent;\n\n ) {\n if (!isInsidePropagationBailout)\n if (0 !== (parent.flags & 524288)) isInsidePropagationBailout = !0;\n else if (0 !== (parent.flags & 262144)) break;\n if (10 === parent.tag) {\n var currentParent = parent.alternate;\n if (null === currentParent) throw Error(formatProdErrorMessage(387));\n currentParent = currentParent.memoizedProps;\n if (null !== currentParent) {\n var context = parent.type;\n objectIs(parent.pendingProps.value, currentParent.value) ||\n (null !== current ? current.push(context) : (current = [context]));\n }\n } else if (parent === hostTransitionProviderCursor.current) {\n currentParent = parent.alternate;\n if (null === currentParent) throw Error(formatProdErrorMessage(387));\n currentParent.memoizedState.memoizedState !==\n parent.memoizedState.memoizedState &&\n (null !== current\n ? current.push(HostTransitionContext)\n : (current = [HostTransitionContext]));\n }\n parent = parent.return;\n }\n null !== current &&\n propagateContextChanges(\n workInProgress,\n current,\n renderLanes,\n forcePropagateEntireTree\n );\n workInProgress.flags |= 262144;\n}\nfunction checkIfContextChanged(currentDependencies) {\n for (\n currentDependencies = currentDependencies.firstContext;\n null !== currentDependencies;\n\n ) {\n if (\n !objectIs(\n currentDependencies.context._currentValue,\n currentDependencies.memoizedValue\n )\n )\n return !0;\n currentDependencies = currentDependencies.next;\n }\n return !1;\n}\nfunction prepareToReadContext(workInProgress) {\n currentlyRenderingFiber$1 = workInProgress;\n lastContextDependency = null;\n workInProgress = workInProgress.dependencies;\n null !== workInProgress && (workInProgress.firstContext = null);\n}\nfunction readContext(context) {\n return readContextForConsumer(currentlyRenderingFiber$1, context);\n}\nfunction readContextDuringReconciliation(consumer, context) {\n null === currentlyRenderingFiber$1 && prepareToReadContext(consumer);\n return readContextForConsumer(consumer, context);\n}\nfunction readContextForConsumer(consumer, context) {\n var value = context._currentValue;\n context = { context: context, memoizedValue: value, next: null };\n if (null === lastContextDependency) {\n if (null === consumer) throw Error(formatProdErrorMessage(308));\n lastContextDependency = context;\n consumer.dependencies = { lanes: 0, firstContext: context };\n consumer.flags |= 524288;\n } else lastContextDependency = lastContextDependency.next = context;\n return value;\n}\nvar AbortControllerLocal =\n \"undefined\" !== typeof AbortController\n ? AbortController\n : function () {\n var listeners = [],\n signal = (this.signal = {\n aborted: !1,\n addEventListener: function (type, listener) {\n listeners.push(listener);\n }\n });\n this.abort = function () {\n signal.aborted = !0;\n listeners.forEach(function (listener) {\n return listener();\n });\n };\n },\n scheduleCallback$2 = Scheduler.unstable_scheduleCallback,\n NormalPriority = Scheduler.unstable_NormalPriority,\n CacheContext = {\n $$typeof: REACT_CONTEXT_TYPE,\n Consumer: null,\n Provider: null,\n _currentValue: null,\n _currentValue2: null,\n _threadCount: 0\n };\nfunction createCache() {\n return {\n controller: new AbortControllerLocal(),\n data: new Map(),\n refCount: 0\n };\n}\nfunction releaseCache(cache) {\n cache.refCount--;\n 0 === cache.refCount &&\n scheduleCallback$2(NormalPriority, function () {\n cache.controller.abort();\n });\n}\nvar currentEntangledListeners = null,\n currentEntangledPendingCount = 0,\n currentEntangledLane = 0,\n currentEntangledActionThenable = null;\nfunction entangleAsyncAction(transition, thenable) {\n if (null === currentEntangledListeners) {\n var entangledListeners = (currentEntangledListeners = []);\n currentEntangledPendingCount = 0;\n currentEntangledLane = requestTransitionLane();\n currentEntangledActionThenable = {\n status: \"pending\",\n value: void 0,\n then: function (resolve) {\n entangledListeners.push(resolve);\n }\n };\n }\n currentEntangledPendingCount++;\n thenable.then(pingEngtangledActionScope, pingEngtangledActionScope);\n return thenable;\n}\nfunction pingEngtangledActionScope() {\n if (\n 0 === --currentEntangledPendingCount &&\n null !== currentEntangledListeners\n ) {\n null !== currentEntangledActionThenable &&\n (currentEntangledActionThenable.status = \"fulfilled\");\n var listeners = currentEntangledListeners;\n currentEntangledListeners = null;\n currentEntangledLane = 0;\n currentEntangledActionThenable = null;\n for (var i = 0; i < listeners.length; i++) (0, listeners[i])();\n }\n}\nfunction chainThenableValue(thenable, result) {\n var listeners = [],\n thenableWithOverride = {\n status: \"pending\",\n value: null,\n reason: null,\n then: function (resolve) {\n listeners.push(resolve);\n }\n };\n thenable.then(\n function () {\n thenableWithOverride.status = \"fulfilled\";\n thenableWithOverride.value = result;\n for (var i = 0; i < listeners.length; i++) (0, listeners[i])(result);\n },\n function (error) {\n thenableWithOverride.status = \"rejected\";\n thenableWithOverride.reason = error;\n for (error = 0; error < listeners.length; error++)\n (0, listeners[error])(void 0);\n }\n );\n return thenableWithOverride;\n}\nvar prevOnStartTransitionFinish = ReactSharedInternals.S;\nReactSharedInternals.S = function (transition, returnValue) {\n globalMostRecentTransitionTime = now();\n \"object\" === typeof returnValue &&\n null !== returnValue &&\n \"function\" === typeof returnValue.then &&\n entangleAsyncAction(transition, returnValue);\n null !== prevOnStartTransitionFinish &&\n prevOnStartTransitionFinish(transition, returnValue);\n};\nvar resumedCache = createCursor(null);\nfunction peekCacheFromPool() {\n var cacheResumedFromPreviousRender = resumedCache.current;\n return null !== cacheResumedFromPreviousRender\n ? cacheResumedFromPreviousRender\n : workInProgressRoot.pooledCache;\n}\nfunction pushTransition(offscreenWorkInProgress, prevCachePool) {\n null === prevCachePool\n ? push(resumedCache, resumedCache.current)\n : push(resumedCache, prevCachePool.pool);\n}\nfunction getSuspendedCache() {\n var cacheFromPool = peekCacheFromPool();\n return null === cacheFromPool\n ? null\n : { parent: CacheContext._currentValue, pool: cacheFromPool };\n}\nvar SuspenseException = Error(formatProdErrorMessage(460)),\n SuspenseyCommitException = Error(formatProdErrorMessage(474)),\n SuspenseActionException = Error(formatProdErrorMessage(542)),\n noopSuspenseyCommitThenable = { then: function () {} };\nfunction isThenableResolved(thenable) {\n thenable = thenable.status;\n return \"fulfilled\" === thenable || \"rejected\" === thenable;\n}\nfunction trackUsedThenable(thenableState, thenable, index) {\n index = thenableState[index];\n void 0 === index\n ? thenableState.push(thenable)\n : index !== thenable && (thenable.then(noop$1, noop$1), (thenable = index));\n switch (thenable.status) {\n case \"fulfilled\":\n return thenable.value;\n case \"rejected\":\n throw (\n ((thenableState = thenable.reason),\n checkIfUseWrappedInAsyncCatch(thenableState),\n thenableState)\n );\n default:\n if (\"string\" === typeof thenable.status) thenable.then(noop$1, noop$1);\n else {\n thenableState = workInProgressRoot;\n if (null !== thenableState && 100 < thenableState.shellSuspendCounter)\n throw Error(formatProdErrorMessage(482));\n thenableState = thenable;\n thenableState.status = \"pending\";\n thenableState.then(\n function (fulfilledValue) {\n if (\"pending\" === thenable.status) {\n var fulfilledThenable = thenable;\n fulfilledThenable.status = \"fulfilled\";\n fulfilledThenable.value = fulfilledValue;\n }\n },\n function (error) {\n if (\"pending\" === thenable.status) {\n var rejectedThenable = thenable;\n rejectedThenable.status = \"rejected\";\n rejectedThenable.reason = error;\n }\n }\n );\n }\n switch (thenable.status) {\n case \"fulfilled\":\n return thenable.value;\n case \"rejected\":\n throw (\n ((thenableState = thenable.reason),\n checkIfUseWrappedInAsyncCatch(thenableState),\n thenableState)\n );\n }\n suspendedThenable = thenable;\n throw SuspenseException;\n }\n}\nfunction resolveLazy(lazyType) {\n try {\n var init = lazyType._init;\n return init(lazyType._payload);\n } catch (x) {\n if (null !== x && \"object\" === typeof x && \"function\" === typeof x.then)\n throw ((suspendedThenable = x), SuspenseException);\n throw x;\n }\n}\nvar suspendedThenable = null;\nfunction getSuspendedThenable() {\n if (null === suspendedThenable) throw Error(formatProdErrorMessage(459));\n var thenable = suspendedThenable;\n suspendedThenable = null;\n return thenable;\n}\nfunction checkIfUseWrappedInAsyncCatch(rejectedReason) {\n if (\n rejectedReason === SuspenseException ||\n rejectedReason === SuspenseActionException\n )\n throw Error(formatProdErrorMessage(483));\n}\nvar thenableState$1 = null,\n thenableIndexCounter$1 = 0;\nfunction unwrapThenable(thenable) {\n var index = thenableIndexCounter$1;\n thenableIndexCounter$1 += 1;\n null === thenableState$1 && (thenableState$1 = []);\n return trackUsedThenable(thenableState$1, thenable, index);\n}\nfunction coerceRef(workInProgress, element) {\n element = element.props.ref;\n workInProgress.ref = void 0 !== element ? element : null;\n}\nfunction throwOnInvalidObjectTypeImpl(returnFiber, newChild) {\n if (newChild.$$typeof === REACT_LEGACY_ELEMENT_TYPE)\n throw Error(formatProdErrorMessage(525));\n returnFiber = Object.prototype.toString.call(newChild);\n throw Error(\n formatProdErrorMessage(\n 31,\n \"[object Object]\" === returnFiber\n ? \"object with keys {\" + Object.keys(newChild).join(\", \") + \"}\"\n : returnFiber\n )\n );\n}\nfunction createChildReconciler(shouldTrackSideEffects) {\n function deleteChild(returnFiber, childToDelete) {\n if (shouldTrackSideEffects) {\n var deletions = returnFiber.deletions;\n null === deletions\n ? ((returnFiber.deletions = [childToDelete]), (returnFiber.flags |= 16))\n : deletions.push(childToDelete);\n }\n }\n function deleteRemainingChildren(returnFiber, currentFirstChild) {\n if (!shouldTrackSideEffects) return null;\n for (; null !== currentFirstChild; )\n deleteChild(returnFiber, currentFirstChild),\n (currentFirstChild = currentFirstChild.sibling);\n return null;\n }\n function mapRemainingChildren(currentFirstChild) {\n for (var existingChildren = new Map(); null !== currentFirstChild; )\n null !== currentFirstChild.key\n ? existingChildren.set(currentFirstChild.key, currentFirstChild)\n : existingChildren.set(currentFirstChild.index, currentFirstChild),\n (currentFirstChild = currentFirstChild.sibling);\n return existingChildren;\n }\n function useFiber(fiber, pendingProps) {\n fiber = createWorkInProgress(fiber, pendingProps);\n fiber.index = 0;\n fiber.sibling = null;\n return fiber;\n }\n function placeChild(newFiber, lastPlacedIndex, newIndex) {\n newFiber.index = newIndex;\n if (!shouldTrackSideEffects)\n return (newFiber.flags |= 1048576), lastPlacedIndex;\n newIndex = newFiber.alternate;\n if (null !== newIndex)\n return (\n (newIndex = newIndex.index),\n newIndex < lastPlacedIndex\n ? ((newFiber.flags |= 67108866), lastPlacedIndex)\n : newIndex\n );\n newFiber.flags |= 67108866;\n return lastPlacedIndex;\n }\n function placeSingleChild(newFiber) {\n shouldTrackSideEffects &&\n null === newFiber.alternate &&\n (newFiber.flags |= 67108866);\n return newFiber;\n }\n function updateTextNode(returnFiber, current, textContent, lanes) {\n if (null === current || 6 !== current.tag)\n return (\n (current = createFiberFromText(textContent, returnFiber.mode, lanes)),\n (current.return = returnFiber),\n current\n );\n current = useFiber(current, textContent);\n current.return = returnFiber;\n return current;\n }\n function updateElement(returnFiber, current, element, lanes) {\n var elementType = element.type;\n if (elementType === REACT_FRAGMENT_TYPE)\n return updateFragment(\n returnFiber,\n current,\n element.props.children,\n lanes,\n element.key\n );\n if (\n null !== current &&\n (current.elementType === elementType ||\n (\"object\" === typeof elementType &&\n null !== elementType &&\n elementType.$$typeof === REACT_LAZY_TYPE &&\n resolveLazy(elementType) === current.type))\n )\n return (\n (current = useFiber(current, element.props)),\n coerceRef(current, element),\n (current.return = returnFiber),\n current\n );\n current = createFiberFromTypeAndProps(\n element.type,\n element.key,\n element.props,\n null,\n returnFiber.mode,\n lanes\n );\n coerceRef(current, element);\n current.return = returnFiber;\n return current;\n }\n function updatePortal(returnFiber, current, portal, lanes) {\n if (\n null === current ||\n 4 !== current.tag ||\n current.stateNode.containerInfo !== portal.containerInfo ||\n current.stateNode.implementation !== portal.implementation\n )\n return (\n (current = createFiberFromPortal(portal, returnFiber.mode, lanes)),\n (current.return = returnFiber),\n current\n );\n current = useFiber(current, portal.children || []);\n current.return = returnFiber;\n return current;\n }\n function updateFragment(returnFiber, current, fragment, lanes, key) {\n if (null === current || 7 !== current.tag)\n return (\n (current = createFiberFromFragment(\n fragment,\n returnFiber.mode,\n lanes,\n key\n )),\n (current.return = returnFiber),\n current\n );\n current = useFiber(current, fragment);\n current.return = returnFiber;\n return current;\n }\n function createChild(returnFiber, newChild, lanes) {\n if (\n (\"string\" === typeof newChild && \"\" !== newChild) ||\n \"number\" === typeof newChild ||\n \"bigint\" === typeof newChild\n )\n return (\n (newChild = createFiberFromText(\n \"\" + newChild,\n returnFiber.mode,\n lanes\n )),\n (newChild.return = returnFiber),\n newChild\n );\n if (\"object\" === typeof newChild && null !== newChild) {\n switch (newChild.$$typeof) {\n case REACT_ELEMENT_TYPE:\n return (\n (lanes = createFiberFromTypeAndProps(\n newChild.type,\n newChild.key,\n newChild.props,\n null,\n returnFiber.mode,\n lanes\n )),\n coerceRef(lanes, newChild),\n (lanes.return = returnFiber),\n lanes\n );\n case REACT_PORTAL_TYPE:\n return (\n (newChild = createFiberFromPortal(\n newChild,\n returnFiber.mode,\n lanes\n )),\n (newChild.return = returnFiber),\n newChild\n );\n case REACT_LAZY_TYPE:\n return (\n (newChild = resolveLazy(newChild)),\n createChild(returnFiber, newChild, lanes)\n );\n }\n if (isArrayImpl(newChild) || getIteratorFn(newChild))\n return (\n (newChild = createFiberFromFragment(\n newChild,\n returnFiber.mode,\n lanes,\n null\n )),\n (newChild.return = returnFiber),\n newChild\n );\n if (\"function\" === typeof newChild.then)\n return createChild(returnFiber, unwrapThenable(newChild), lanes);\n if (newChild.$$typeof === REACT_CONTEXT_TYPE)\n return createChild(\n returnFiber,\n readContextDuringReconciliation(returnFiber, newChild),\n lanes\n );\n throwOnInvalidObjectTypeImpl(returnFiber, newChild);\n }\n return null;\n }\n function updateSlot(returnFiber, oldFiber, newChild, lanes) {\n var key = null !== oldFiber ? oldFiber.key : null;\n if (\n (\"string\" === typeof newChild && \"\" !== newChild) ||\n \"number\" === typeof newChild ||\n \"bigint\" === typeof newChild\n )\n return null !== key\n ? null\n : updateTextNode(returnFiber, oldFiber, \"\" + newChild, lanes);\n if (\"object\" === typeof newChild && null !== newChild) {\n switch (newChild.$$typeof) {\n case REACT_ELEMENT_TYPE:\n return newChild.key === key\n ? updateElement(returnFiber, oldFiber, newChild, lanes)\n : null;\n case REACT_PORTAL_TYPE:\n return newChild.key === key\n ? updatePortal(returnFiber, oldFiber, newChild, lanes)\n : null;\n case REACT_LAZY_TYPE:\n return (\n (newChild = resolveLazy(newChild)),\n updateSlot(returnFiber, oldFiber, newChild, lanes)\n );\n }\n if (isArrayImpl(newChild) || getIteratorFn(newChild))\n return null !== key\n ? null\n : updateFragment(returnFiber, oldFiber, newChild, lanes, null);\n if (\"function\" === typeof newChild.then)\n return updateSlot(\n returnFiber,\n oldFiber,\n unwrapThenable(newChild),\n lanes\n );\n if (newChild.$$typeof === REACT_CONTEXT_TYPE)\n return updateSlot(\n returnFiber,\n oldFiber,\n readContextDuringReconciliation(returnFiber, newChild),\n lanes\n );\n throwOnInvalidObjectTypeImpl(returnFiber, newChild);\n }\n return null;\n }\n function updateFromMap(\n existingChildren,\n returnFiber,\n newIdx,\n newChild,\n lanes\n ) {\n if (\n (\"string\" === typeof newChild && \"\" !== newChild) ||\n \"number\" === typeof newChild ||\n \"bigint\" === typeof newChild\n )\n return (\n (existingChildren = existingChildren.get(newIdx) || null),\n updateTextNode(returnFiber, existingChildren, \"\" + newChild, lanes)\n );\n if (\"object\" === typeof newChild && null !== newChild) {\n switch (newChild.$$typeof) {\n case REACT_ELEMENT_TYPE:\n return (\n (existingChildren =\n existingChildren.get(\n null === newChild.key ? newIdx : newChild.key\n ) || null),\n updateElement(returnFiber, existingChildren, newChild, lanes)\n );\n case REACT_PORTAL_TYPE:\n return (\n (existingChildren =\n existingChildren.get(\n null === newChild.key ? newIdx : newChild.key\n ) || null),\n updatePortal(returnFiber, existingChildren, newChild, lanes)\n );\n case REACT_LAZY_TYPE:\n return (\n (newChild = resolveLazy(newChild)),\n updateFromMap(\n existingChildren,\n returnFiber,\n newIdx,\n newChild,\n lanes\n )\n );\n }\n if (isArrayImpl(newChild) || getIteratorFn(newChild))\n return (\n (existingChildren = existingChildren.get(newIdx) || null),\n updateFragment(returnFiber, existingChildren, newChild, lanes, null)\n );\n if (\"function\" === typeof newChild.then)\n return updateFromMap(\n existingChildren,\n returnFiber,\n newIdx,\n unwrapThenable(newChild),\n lanes\n );\n if (newChild.$$typeof === REACT_CONTEXT_TYPE)\n return updateFromMap(\n existingChildren,\n returnFiber,\n newIdx,\n readContextDuringReconciliation(returnFiber, newChild),\n lanes\n );\n throwOnInvalidObjectTypeImpl(returnFiber, newChild);\n }\n return null;\n }\n function reconcileChildrenArray(\n returnFiber,\n currentFirstChild,\n newChildren,\n lanes\n ) {\n for (\n var resultingFirstChild = null,\n previousNewFiber = null,\n oldFiber = currentFirstChild,\n newIdx = (currentFirstChild = 0),\n nextOldFiber = null;\n null !== oldFiber && newIdx < newChildren.length;\n newIdx++\n ) {\n oldFiber.index > newIdx\n ? ((nextOldFiber = oldFiber), (oldFiber = null))\n : (nextOldFiber = oldFiber.sibling);\n var newFiber = updateSlot(\n returnFiber,\n oldFiber,\n newChildren[newIdx],\n lanes\n );\n if (null === newFiber) {\n null === oldFiber && (oldFiber = nextOldFiber);\n break;\n }\n shouldTrackSideEffects &&\n oldFiber &&\n null === newFiber.alternate &&\n deleteChild(returnFiber, oldFiber);\n currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx);\n null === previousNewFiber\n ? (resultingFirstChild = newFiber)\n : (previousNewFiber.sibling = newFiber);\n previousNewFiber = newFiber;\n oldFiber = nextOldFiber;\n }\n if (newIdx === newChildren.length)\n return (\n deleteRemainingChildren(returnFiber, oldFiber),\n isHydrating && pushTreeFork(returnFiber, newIdx),\n resultingFirstChild\n );\n if (null === oldFiber) {\n for (; newIdx < newChildren.length; newIdx++)\n (oldFiber = createChild(returnFiber, newChildren[newIdx], lanes)),\n null !== oldFiber &&\n ((currentFirstChild = placeChild(\n oldFiber,\n currentFirstChild,\n newIdx\n )),\n null === previousNewFiber\n ? (resultingFirstChild = oldFiber)\n : (previousNewFiber.sibling = oldFiber),\n (previousNewFiber = oldFiber));\n isHydrating && pushTreeFork(returnFiber, newIdx);\n return resultingFirstChild;\n }\n for (\n oldFiber = mapRemainingChildren(oldFiber);\n newIdx < newChildren.length;\n newIdx++\n )\n (nextOldFiber = updateFromMap(\n oldFiber,\n returnFiber,\n newIdx,\n newChildren[newIdx],\n lanes\n )),\n null !== nextOldFiber &&\n (shouldTrackSideEffects &&\n null !== nextOldFiber.alternate &&\n oldFiber.delete(\n null === nextOldFiber.key ? newIdx : nextOldFiber.key\n ),\n (currentFirstChild = placeChild(\n nextOldFiber,\n currentFirstChild,\n newIdx\n )),\n null === previousNewFiber\n ? (resultingFirstChild = nextOldFiber)\n : (previousNewFiber.sibling = nextOldFiber),\n (previousNewFiber = nextOldFiber));\n shouldTrackSideEffects &&\n oldFiber.forEach(function (child) {\n return deleteChild(returnFiber, child);\n });\n isHydrating && pushTreeFork(returnFiber, newIdx);\n return resultingFirstChild;\n }\n function reconcileChildrenIterator(\n returnFiber,\n currentFirstChild,\n newChildren,\n lanes\n ) {\n if (null == newChildren) throw Error(formatProdErrorMessage(151));\n for (\n var resultingFirstChild = null,\n previousNewFiber = null,\n oldFiber = currentFirstChild,\n newIdx = (currentFirstChild = 0),\n nextOldFiber = null,\n step = newChildren.next();\n null !== oldFiber && !step.done;\n newIdx++, step = newChildren.next()\n ) {\n oldFiber.index > newIdx\n ? ((nextOldFiber = oldFiber), (oldFiber = null))\n : (nextOldFiber = oldFiber.sibling);\n var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes);\n if (null === newFiber) {\n null === oldFiber && (oldFiber = nextOldFiber);\n break;\n }\n shouldTrackSideEffects &&\n oldFiber &&\n null === newFiber.alternate &&\n deleteChild(returnFiber, oldFiber);\n currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx);\n null === previousNewFiber\n ? (resultingFirstChild = newFiber)\n : (previousNewFiber.sibling = newFiber);\n previousNewFiber = newFiber;\n oldFiber = nextOldFiber;\n }\n if (step.done)\n return (\n deleteRemainingChildren(returnFiber, oldFiber),\n isHydrating && pushTreeFork(returnFiber, newIdx),\n resultingFirstChild\n );\n if (null === oldFiber) {\n for (; !step.done; newIdx++, step = newChildren.next())\n (step = createChild(returnFiber, step.value, lanes)),\n null !== step &&\n ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)),\n null === previousNewFiber\n ? (resultingFirstChild = step)\n : (previousNewFiber.sibling = step),\n (previousNewFiber = step));\n isHydrating && pushTreeFork(returnFiber, newIdx);\n return resultingFirstChild;\n }\n for (\n oldFiber = mapRemainingChildren(oldFiber);\n !step.done;\n newIdx++, step = newChildren.next()\n )\n (step = updateFromMap(oldFiber, returnFiber, newIdx, step.value, lanes)),\n null !== step &&\n (shouldTrackSideEffects &&\n null !== step.alternate &&\n oldFiber.delete(null === step.key ? newIdx : step.key),\n (currentFirstChild = placeChild(step, currentFirstChild, newIdx)),\n null === previousNewFiber\n ? (resultingFirstChild = step)\n : (previousNewFiber.sibling = step),\n (previousNewFiber = step));\n shouldTrackSideEffects &&\n oldFiber.forEach(function (child) {\n return deleteChild(returnFiber, child);\n });\n isHydrating && pushTreeFork(returnFiber, newIdx);\n return resultingFirstChild;\n }\n function reconcileChildFibersImpl(\n returnFiber,\n currentFirstChild,\n newChild,\n lanes\n ) {\n \"object\" === typeof newChild &&\n null !== newChild &&\n newChild.type === REACT_FRAGMENT_TYPE &&\n null === newChild.key &&\n (newChild = newChild.props.children);\n if (\"object\" === typeof newChild && null !== newChild) {\n switch (newChild.$$typeof) {\n case REACT_ELEMENT_TYPE:\n a: {\n for (var key = newChild.key; null !== currentFirstChild; ) {\n if (currentFirstChild.key === key) {\n key = newChild.type;\n if (key === REACT_FRAGMENT_TYPE) {\n if (7 === currentFirstChild.tag) {\n deleteRemainingChildren(\n returnFiber,\n currentFirstChild.sibling\n );\n lanes = useFiber(\n currentFirstChild,\n newChild.props.children\n );\n lanes.return = returnFiber;\n returnFiber = lanes;\n break a;\n }\n } else if (\n currentFirstChild.elementType === key ||\n (\"object\" === typeof key &&\n null !== key &&\n key.$$typeof === REACT_LAZY_TYPE &&\n resolveLazy(key) === currentFirstChild.type)\n ) {\n deleteRemainingChildren(\n returnFiber,\n currentFirstChild.sibling\n );\n lanes = useFiber(currentFirstChild, newChild.props);\n coerceRef(lanes, newChild);\n lanes.return = returnFiber;\n returnFiber = lanes;\n break a;\n }\n deleteRemainingChildren(returnFiber, currentFirstChild);\n break;\n } else deleteChild(returnFiber, currentFirstChild);\n currentFirstChild = currentFirstChild.sibling;\n }\n newChild.type === REACT_FRAGMENT_TYPE\n ? ((lanes = createFiberFromFragment(\n newChild.props.children,\n returnFiber.mode,\n lanes,\n newChild.key\n )),\n (lanes.return = returnFiber),\n (returnFiber = lanes))\n : ((lanes = createFiberFromTypeAndProps(\n newChild.type,\n newChild.key,\n newChild.props,\n null,\n returnFiber.mode,\n lanes\n )),\n coerceRef(lanes, newChild),\n (lanes.return = returnFiber),\n (returnFiber = lanes));\n }\n return placeSingleChild(returnFiber);\n case REACT_PORTAL_TYPE:\n a: {\n for (key = newChild.key; null !== currentFirstChild; ) {\n if (currentFirstChild.key === key)\n if (\n 4 === currentFirstChild.tag &&\n currentFirstChild.stateNode.containerInfo ===\n newChild.containerInfo &&\n currentFirstChild.stateNode.implementation ===\n newChild.implementation\n ) {\n deleteRemainingChildren(\n returnFiber,\n currentFirstChild.sibling\n );\n lanes = useFiber(currentFirstChild, newChild.children || []);\n lanes.return = returnFiber;\n returnFiber = lanes;\n break a;\n } else {\n deleteRemainingChildren(returnFiber, currentFirstChild);\n break;\n }\n else deleteChild(returnFiber, currentFirstChild);\n currentFirstChild = currentFirstChild.sibling;\n }\n lanes = createFiberFromPortal(newChild, returnFiber.mode, lanes);\n lanes.return = returnFiber;\n returnFiber = lanes;\n }\n return placeSingleChild(returnFiber);\n case REACT_LAZY_TYPE:\n return (\n (newChild = resolveLazy(newChild)),\n reconcileChildFibersImpl(\n returnFiber,\n currentFirstChild,\n newChild,\n lanes\n )\n );\n }\n if (isArrayImpl(newChild))\n return reconcileChildrenArray(\n returnFiber,\n currentFirstChild,\n newChild,\n lanes\n );\n if (getIteratorFn(newChild)) {\n key = getIteratorFn(newChild);\n if (\"function\" !== typeof key) throw Error(formatProdErrorMessage(150));\n newChild = key.call(newChild);\n return reconcileChildrenIterator(\n returnFiber,\n currentFirstChild,\n newChild,\n lanes\n );\n }\n if (\"function\" === typeof newChild.then)\n return reconcileChildFibersImpl(\n returnFiber,\n currentFirstChild,\n unwrapThenable(newChild),\n lanes\n );\n if (newChild.$$typeof === REACT_CONTEXT_TYPE)\n return reconcileChildFibersImpl(\n returnFiber,\n currentFirstChild,\n readContextDuringReconciliation(returnFiber, newChild),\n lanes\n );\n throwOnInvalidObjectTypeImpl(returnFiber, newChild);\n }\n return (\"string\" === typeof newChild && \"\" !== newChild) ||\n \"number\" === typeof newChild ||\n \"bigint\" === typeof newChild\n ? ((newChild = \"\" + newChild),\n null !== currentFirstChild && 6 === currentFirstChild.tag\n ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling),\n (lanes = useFiber(currentFirstChild, newChild)),\n (lanes.return = returnFiber),\n (returnFiber = lanes))\n : (deleteRemainingChildren(returnFiber, currentFirstChild),\n (lanes = createFiberFromText(newChild, returnFiber.mode, lanes)),\n (lanes.return = returnFiber),\n (returnFiber = lanes)),\n placeSingleChild(returnFiber))\n : deleteRemainingChildren(returnFiber, currentFirstChild);\n }\n return function (returnFiber, currentFirstChild, newChild, lanes) {\n try {\n thenableIndexCounter$1 = 0;\n var firstChildFiber = reconcileChildFibersImpl(\n returnFiber,\n currentFirstChild,\n newChild,\n lanes\n );\n thenableState$1 = null;\n return firstChildFiber;\n } catch (x) {\n if (x === SuspenseException || x === SuspenseActionException) throw x;\n var fiber = createFiberImplClass(29, x, null, returnFiber.mode);\n fiber.lanes = lanes;\n fiber.return = returnFiber;\n return fiber;\n } finally {\n }\n };\n}\nvar reconcileChildFibers = createChildReconciler(!0),\n mountChildFibers = createChildReconciler(!1),\n hasForceUpdate = !1;\nfunction initializeUpdateQueue(fiber) {\n fiber.updateQueue = {\n baseState: fiber.memoizedState,\n firstBaseUpdate: null,\n lastBaseUpdate: null,\n shared: { pending: null, lanes: 0, hiddenCallbacks: null },\n callbacks: null\n };\n}\nfunction cloneUpdateQueue(current, workInProgress) {\n current = current.updateQueue;\n workInProgress.updateQueue === current &&\n (workInProgress.updateQueue = {\n baseState: current.baseState,\n firstBaseUpdate: current.firstBaseUpdate,\n lastBaseUpdate: current.lastBaseUpdate,\n shared: current.shared,\n callbacks: null\n });\n}\nfunction createUpdate(lane) {\n return { lane: lane, tag: 0, payload: null, callback: null, next: null };\n}\nfunction enqueueUpdate(fiber, update, lane) {\n var updateQueue = fiber.updateQueue;\n if (null === updateQueue) return null;\n updateQueue = updateQueue.shared;\n if (0 !== (executionContext & 2)) {\n var pending = updateQueue.pending;\n null === pending\n ? (update.next = update)\n : ((update.next = pending.next), (pending.next = update));\n updateQueue.pending = update;\n update = getRootForUpdatedFiber(fiber);\n markUpdateLaneFromFiberToRoot(fiber, null, lane);\n return update;\n }\n enqueueUpdate$1(fiber, updateQueue, update, lane);\n return getRootForUpdatedFiber(fiber);\n}\nfunction entangleTransitions(root, fiber, lane) {\n fiber = fiber.updateQueue;\n if (null !== fiber && ((fiber = fiber.shared), 0 !== (lane & 4194048))) {\n var queueLanes = fiber.lanes;\n queueLanes &= root.pendingLanes;\n lane |= queueLanes;\n fiber.lanes = lane;\n markRootEntangled(root, lane);\n }\n}\nfunction enqueueCapturedUpdate(workInProgress, capturedUpdate) {\n var queue = workInProgress.updateQueue,\n current = workInProgress.alternate;\n if (\n null !== current &&\n ((current = current.updateQueue), queue === current)\n ) {\n var newFirst = null,\n newLast = null;\n queue = queue.firstBaseUpdate;\n if (null !== queue) {\n do {\n var clone = {\n lane: queue.lane,\n tag: queue.tag,\n payload: queue.payload,\n callback: null,\n next: null\n };\n null === newLast\n ? (newFirst = newLast = clone)\n : (newLast = newLast.next = clone);\n queue = queue.next;\n } while (null !== queue);\n null === newLast\n ? (newFirst = newLast = capturedUpdate)\n : (newLast = newLast.next = capturedUpdate);\n } else newFirst = newLast = capturedUpdate;\n queue = {\n baseState: current.baseState,\n firstBaseUpdate: newFirst,\n lastBaseUpdate: newLast,\n shared: current.shared,\n callbacks: current.callbacks\n };\n workInProgress.updateQueue = queue;\n return;\n }\n workInProgress = queue.lastBaseUpdate;\n null === workInProgress\n ? (queue.firstBaseUpdate = capturedUpdate)\n : (workInProgress.next = capturedUpdate);\n queue.lastBaseUpdate = capturedUpdate;\n}\nvar didReadFromEntangledAsyncAction = !1;\nfunction suspendIfUpdateReadFromEntangledAsyncAction() {\n if (didReadFromEntangledAsyncAction) {\n var entangledActionThenable = currentEntangledActionThenable;\n if (null !== entangledActionThenable) throw entangledActionThenable;\n }\n}\nfunction processUpdateQueue(\n workInProgress$jscomp$0,\n props,\n instance$jscomp$0,\n renderLanes\n) {\n didReadFromEntangledAsyncAction = !1;\n var queue = workInProgress$jscomp$0.updateQueue;\n hasForceUpdate = !1;\n var firstBaseUpdate = queue.firstBaseUpdate,\n lastBaseUpdate = queue.lastBaseUpdate,\n pendingQueue = queue.shared.pending;\n if (null !== pendingQueue) {\n queue.shared.pending = null;\n var lastPendingUpdate = pendingQueue,\n firstPendingUpdate = lastPendingUpdate.next;\n lastPendingUpdate.next = null;\n null === lastBaseUpdate\n ? (firstBaseUpdate = firstPendingUpdate)\n : (lastBaseUpdate.next = firstPendingUpdate);\n lastBaseUpdate = lastPendingUpdate;\n var current = workInProgress$jscomp$0.alternate;\n null !== current &&\n ((current = current.updateQueue),\n (pendingQueue = current.lastBaseUpdate),\n pendingQueue !== lastBaseUpdate &&\n (null === pendingQueue\n ? (current.firstBaseUpdate = firstPendingUpdate)\n : (pendingQueue.next = firstPendingUpdate),\n (current.lastBaseUpdate = lastPendingUpdate)));\n }\n if (null !== firstBaseUpdate) {\n var newState = queue.baseState;\n lastBaseUpdate = 0;\n current = firstPendingUpdate = lastPendingUpdate = null;\n pendingQueue = firstBaseUpdate;\n do {\n var updateLane = pendingQueue.lane & -536870913,\n isHiddenUpdate = updateLane !== pendingQueue.lane;\n if (\n isHiddenUpdate\n ? (workInProgressRootRenderLanes & updateLane) === updateLane\n : (renderLanes & updateLane) === updateLane\n ) {\n 0 !== updateLane &&\n updateLane === currentEntangledLane &&\n (didReadFromEntangledAsyncAction = !0);\n null !== current &&\n (current = current.next =\n {\n lane: 0,\n tag: pendingQueue.tag,\n payload: pendingQueue.payload,\n callback: null,\n next: null\n });\n a: {\n var workInProgress = workInProgress$jscomp$0,\n update = pendingQueue;\n updateLane = props;\n var instance = instance$jscomp$0;\n switch (update.tag) {\n case 1:\n workInProgress = update.payload;\n if (\"function\" === typeof workInProgress) {\n newState = workInProgress.call(instance, newState, updateLane);\n break a;\n }\n newState = workInProgress;\n break a;\n case 3:\n workInProgress.flags = (workInProgress.flags & -65537) | 128;\n case 0:\n workInProgress = update.payload;\n updateLane =\n \"function\" === typeof workInProgress\n ? workInProgress.call(instance, newState, updateLane)\n : workInProgress;\n if (null === updateLane || void 0 === updateLane) break a;\n newState = assign({}, newState, updateLane);\n break a;\n case 2:\n hasForceUpdate = !0;\n }\n }\n updateLane = pendingQueue.callback;\n null !== updateLane &&\n ((workInProgress$jscomp$0.flags |= 64),\n isHiddenUpdate && (workInProgress$jscomp$0.flags |= 8192),\n (isHiddenUpdate = queue.callbacks),\n null === isHiddenUpdate\n ? (queue.callbacks = [updateLane])\n : isHiddenUpdate.push(updateLane));\n } else\n (isHiddenUpdate = {\n lane: updateLane,\n tag: pendingQueue.tag,\n payload: pendingQueue.payload,\n callback: pendingQueue.callback,\n next: null\n }),\n null === current\n ? ((firstPendingUpdate = current = isHiddenUpdate),\n (lastPendingUpdate = newState))\n : (current = current.next = isHiddenUpdate),\n (lastBaseUpdate |= updateLane);\n pendingQueue = pendingQueue.next;\n if (null === pendingQueue)\n if (((pendingQueue = queue.shared.pending), null === pendingQueue))\n break;\n else\n (isHiddenUpdate = pendingQueue),\n (pendingQueue = isHiddenUpdate.next),\n (isHiddenUpdate.next = null),\n (queue.lastBaseUpdate = isHiddenUpdate),\n (queue.shared.pending = null);\n } while (1);\n null === current && (lastPendingUpdate = newState);\n queue.baseState = lastPendingUpdate;\n queue.firstBaseUpdate = firstPendingUpdate;\n queue.lastBaseUpdate = current;\n null === firstBaseUpdate && (queue.shared.lanes = 0);\n workInProgressRootSkippedLanes |= lastBaseUpdate;\n workInProgress$jscomp$0.lanes = lastBaseUpdate;\n workInProgress$jscomp$0.memoizedState = newState;\n }\n}\nfunction callCallback(callback, context) {\n if (\"function\" !== typeof callback)\n throw Error(formatProdErrorMessage(191, callback));\n callback.call(context);\n}\nfunction commitCallbacks(updateQueue, context) {\n var callbacks = updateQueue.callbacks;\n if (null !== callbacks)\n for (\n updateQueue.callbacks = null, updateQueue = 0;\n updateQueue < callbacks.length;\n updateQueue++\n )\n callCallback(callbacks[updateQueue], context);\n}\nvar currentTreeHiddenStackCursor = createCursor(null),\n prevEntangledRenderLanesCursor = createCursor(0);\nfunction pushHiddenContext(fiber, context) {\n fiber = entangledRenderLanes;\n push(prevEntangledRenderLanesCursor, fiber);\n push(currentTreeHiddenStackCursor, context);\n entangledRenderLanes = fiber | context.baseLanes;\n}\nfunction reuseHiddenContextOnStack() {\n push(prevEntangledRenderLanesCursor, entangledRenderLanes);\n push(currentTreeHiddenStackCursor, currentTreeHiddenStackCursor.current);\n}\nfunction popHiddenContext() {\n entangledRenderLanes = prevEntangledRenderLanesCursor.current;\n pop(currentTreeHiddenStackCursor);\n pop(prevEntangledRenderLanesCursor);\n}\nvar suspenseHandlerStackCursor = createCursor(null),\n shellBoundary = null;\nfunction pushPrimaryTreeSuspenseHandler(handler) {\n var current = handler.alternate;\n push(suspenseStackCursor, suspenseStackCursor.current & 1);\n push(suspenseHandlerStackCursor, handler);\n null === shellBoundary &&\n (null === current || null !== currentTreeHiddenStackCursor.current\n ? (shellBoundary = handler)\n : null !== current.memoizedState && (shellBoundary = handler));\n}\nfunction pushDehydratedActivitySuspenseHandler(fiber) {\n push(suspenseStackCursor, suspenseStackCursor.current);\n push(suspenseHandlerStackCursor, fiber);\n null === shellBoundary && (shellBoundary = fiber);\n}\nfunction pushOffscreenSuspenseHandler(fiber) {\n 22 === fiber.tag\n ? (push(suspenseStackCursor, suspenseStackCursor.current),\n push(suspenseHandlerStackCursor, fiber),\n null === shellBoundary && (shellBoundary = fiber))\n : reuseSuspenseHandlerOnStack(fiber);\n}\nfunction reuseSuspenseHandlerOnStack() {\n push(suspenseStackCursor, suspenseStackCursor.current);\n push(suspenseHandlerStackCursor, suspenseHandlerStackCursor.current);\n}\nfunction popSuspenseHandler(fiber) {\n pop(suspenseHandlerStackCursor);\n shellBoundary === fiber && (shellBoundary = null);\n pop(suspenseStackCursor);\n}\nvar suspenseStackCursor = createCursor(0);\nfunction findFirstSuspended(row) {\n for (var node = row; null !== node; ) {\n if (13 === node.tag) {\n var state = node.memoizedState;\n if (\n null !== state &&\n ((state = state.dehydrated),\n null === state ||\n isSuspenseInstancePending(state) ||\n isSuspenseInstanceFallback(state))\n )\n return node;\n } else if (\n 19 === node.tag &&\n (\"forwards\" === node.memoizedProps.revealOrder ||\n \"backwards\" === node.memoizedProps.revealOrder ||\n \"unstable_legacy-backwards\" === node.memoizedProps.revealOrder ||\n \"together\" === node.memoizedProps.revealOrder)\n ) {\n if (0 !== (node.flags & 128)) return node;\n } else if (null !== node.child) {\n node.child.return = node;\n node = node.child;\n continue;\n }\n if (node === row) break;\n for (; null === node.sibling; ) {\n if (null === node.return || node.return === row) return null;\n node = node.return;\n }\n node.sibling.return = node.return;\n node = node.sibling;\n }\n return null;\n}\nvar renderLanes = 0,\n currentlyRenderingFiber = null,\n currentHook = null,\n workInProgressHook = null,\n didScheduleRenderPhaseUpdate = !1,\n didScheduleRenderPhaseUpdateDuringThisPass = !1,\n shouldDoubleInvokeUserFnsInHooksDEV = !1,\n localIdCounter = 0,\n thenableIndexCounter = 0,\n thenableState = null,\n globalClientIdCounter = 0;\nfunction throwInvalidHookError() {\n throw Error(formatProdErrorMessage(321));\n}\nfunction areHookInputsEqual(nextDeps, prevDeps) {\n if (null === prevDeps) return !1;\n for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++)\n if (!objectIs(nextDeps[i], prevDeps[i])) return !1;\n return !0;\n}\nfunction renderWithHooks(\n current,\n workInProgress,\n Component,\n props,\n secondArg,\n nextRenderLanes\n) {\n renderLanes = nextRenderLanes;\n currentlyRenderingFiber = workInProgress;\n workInProgress.memoizedState = null;\n workInProgress.updateQueue = null;\n workInProgress.lanes = 0;\n ReactSharedInternals.H =\n null === current || null === current.memoizedState\n ? HooksDispatcherOnMount\n : HooksDispatcherOnUpdate;\n shouldDoubleInvokeUserFnsInHooksDEV = !1;\n nextRenderLanes = Component(props, secondArg);\n shouldDoubleInvokeUserFnsInHooksDEV = !1;\n didScheduleRenderPhaseUpdateDuringThisPass &&\n (nextRenderLanes = renderWithHooksAgain(\n workInProgress,\n Component,\n props,\n secondArg\n ));\n finishRenderingHooks(current);\n return nextRenderLanes;\n}\nfunction finishRenderingHooks(current) {\n ReactSharedInternals.H = ContextOnlyDispatcher;\n var didRenderTooFewHooks = null !== currentHook && null !== currentHook.next;\n renderLanes = 0;\n workInProgressHook = currentHook = currentlyRenderingFiber = null;\n didScheduleRenderPhaseUpdate = !1;\n thenableIndexCounter = 0;\n thenableState = null;\n if (didRenderTooFewHooks) throw Error(formatProdErrorMessage(300));\n null === current ||\n didReceiveUpdate ||\n ((current = current.dependencies),\n null !== current &&\n checkIfContextChanged(current) &&\n (didReceiveUpdate = !0));\n}\nfunction renderWithHooksAgain(workInProgress, Component, props, secondArg) {\n currentlyRenderingFiber = workInProgress;\n var numberOfReRenders = 0;\n do {\n didScheduleRenderPhaseUpdateDuringThisPass && (thenableState = null);\n thenableIndexCounter = 0;\n didScheduleRenderPhaseUpdateDuringThisPass = !1;\n if (25 <= numberOfReRenders) throw Error(formatProdErrorMessage(301));\n numberOfReRenders += 1;\n workInProgressHook = currentHook = null;\n if (null != workInProgress.updateQueue) {\n var children = workInProgress.updateQueue;\n children.lastEffect = null;\n children.events = null;\n children.stores = null;\n null != children.memoCache && (children.memoCache.index = 0);\n }\n ReactSharedInternals.H = HooksDispatcherOnRerender;\n children = Component(props, secondArg);\n } while (didScheduleRenderPhaseUpdateDuringThisPass);\n return children;\n}\nfunction TransitionAwareHostComponent() {\n var dispatcher = ReactSharedInternals.H,\n maybeThenable = dispatcher.useState()[0];\n maybeThenable =\n \"function\" === typeof maybeThenable.then\n ? useThenable(maybeThenable)\n : maybeThenable;\n dispatcher = dispatcher.useState()[0];\n (null !== currentHook ? currentHook.memoizedState : null) !== dispatcher &&\n (currentlyRenderingFiber.flags |= 1024);\n return maybeThenable;\n}\nfunction checkDidRenderIdHook() {\n var didRenderIdHook = 0 !== localIdCounter;\n localIdCounter = 0;\n return didRenderIdHook;\n}\nfunction bailoutHooks(current, workInProgress, lanes) {\n workInProgress.updateQueue = current.updateQueue;\n workInProgress.flags &= -2053;\n current.lanes &= ~lanes;\n}\nfunction resetHooksOnUnwind(workInProgress) {\n if (didScheduleRenderPhaseUpdate) {\n for (\n workInProgress = workInProgress.memoizedState;\n null !== workInProgress;\n\n ) {\n var queue = workInProgress.queue;\n null !== queue && (queue.pending = null);\n workInProgress = workInProgress.next;\n }\n didScheduleRenderPhaseUpdate = !1;\n }\n renderLanes = 0;\n workInProgressHook = currentHook = currentlyRenderingFiber = null;\n didScheduleRenderPhaseUpdateDuringThisPass = !1;\n thenableIndexCounter = localIdCounter = 0;\n thenableState = null;\n}\nfunction mountWorkInProgressHook() {\n var hook = {\n memoizedState: null,\n baseState: null,\n baseQueue: null,\n queue: null,\n next: null\n };\n null === workInProgressHook\n ? (currentlyRenderingFiber.memoizedState = workInProgressHook = hook)\n : (workInProgressHook = workInProgressHook.next = hook);\n return workInProgressHook;\n}\nfunction updateWorkInProgressHook() {\n if (null === currentHook) {\n var nextCurrentHook = currentlyRenderingFiber.alternate;\n nextCurrentHook =\n null !== nextCurrentHook ? nextCurrentHook.memoizedState : null;\n } else nextCurrentHook = currentHook.next;\n var nextWorkInProgressHook =\n null === workInProgressHook\n ? currentlyRenderingFiber.memoizedState\n : workInProgressHook.next;\n if (null !== nextWorkInProgressHook)\n (workInProgressHook = nextWorkInProgressHook),\n (currentHook = nextCurrentHook);\n else {\n if (null === nextCurrentHook) {\n if (null === currentlyRenderingFiber.alternate)\n throw Error(formatProdErrorMessage(467));\n throw Error(formatProdErrorMessage(310));\n }\n currentHook = nextCurrentHook;\n nextCurrentHook = {\n memoizedState: currentHook.memoizedState,\n baseState: currentHook.baseState,\n baseQueue: currentHook.baseQueue,\n queue: currentHook.queue,\n next: null\n };\n null === workInProgressHook\n ? (currentlyRenderingFiber.memoizedState = workInProgressHook =\n nextCurrentHook)\n : (workInProgressHook = workInProgressHook.next = nextCurrentHook);\n }\n return workInProgressHook;\n}\nfunction createFunctionComponentUpdateQueue() {\n return { lastEffect: null, events: null, stores: null, memoCache: null };\n}\nfunction useThenable(thenable) {\n var index = thenableIndexCounter;\n thenableIndexCounter += 1;\n null === thenableState && (thenableState = []);\n thenable = trackUsedThenable(thenableState, thenable, index);\n index = currentlyRenderingFiber;\n null ===\n (null === workInProgressHook\n ? index.memoizedState\n : workInProgressHook.next) &&\n ((index = index.alternate),\n (ReactSharedInternals.H =\n null === index || null === index.memoizedState\n ? HooksDispatcherOnMount\n : HooksDispatcherOnUpdate));\n return thenable;\n}\nfunction use(usable) {\n if (null !== usable && \"object\" === typeof usable) {\n if (\"function\" === typeof usable.then) return useThenable(usable);\n if (usable.$$typeof === REACT_CONTEXT_TYPE) return readContext(usable);\n }\n throw Error(formatProdErrorMessage(438, String(usable)));\n}\nfunction useMemoCache(size) {\n var memoCache = null,\n updateQueue = currentlyRenderingFiber.updateQueue;\n null !== updateQueue && (memoCache = updateQueue.memoCache);\n if (null == memoCache) {\n var current = currentlyRenderingFiber.alternate;\n null !== current &&\n ((current = current.updateQueue),\n null !== current &&\n ((current = current.memoCache),\n null != current &&\n (memoCache = {\n data: current.data.map(function (array) {\n return array.slice();\n }),\n index: 0\n })));\n }\n null == memoCache && (memoCache = { data: [], index: 0 });\n null === updateQueue &&\n ((updateQueue = createFunctionComponentUpdateQueue()),\n (currentlyRenderingFiber.updateQueue = updateQueue));\n updateQueue.memoCache = memoCache;\n updateQueue = memoCache.data[memoCache.index];\n if (void 0 === updateQueue)\n for (\n updateQueue = memoCache.data[memoCache.index] = Array(size), current = 0;\n current < size;\n current++\n )\n updateQueue[current] = REACT_MEMO_CACHE_SENTINEL;\n memoCache.index++;\n return updateQueue;\n}\nfunction basicStateReducer(state, action) {\n return \"function\" === typeof action ? action(state) : action;\n}\nfunction updateReducer(reducer) {\n var hook = updateWorkInProgressHook();\n return updateReducerImpl(hook, currentHook, reducer);\n}\nfunction updateReducerImpl(hook, current, reducer) {\n var queue = hook.queue;\n if (null === queue) throw Error(formatProdErrorMessage(311));\n queue.lastRenderedReducer = reducer;\n var baseQueue = hook.baseQueue,\n pendingQueue = queue.pending;\n if (null !== pendingQueue) {\n if (null !== baseQueue) {\n var baseFirst = baseQueue.next;\n baseQueue.next = pendingQueue.next;\n pendingQueue.next = baseFirst;\n }\n current.baseQueue = baseQueue = pendingQueue;\n queue.pending = null;\n }\n pendingQueue = hook.baseState;\n if (null === baseQueue) hook.memoizedState = pendingQueue;\n else {\n current = baseQueue.next;\n var newBaseQueueFirst = (baseFirst = null),\n newBaseQueueLast = null,\n update = current,\n didReadFromEntangledAsyncAction$60 = !1;\n do {\n var updateLane = update.lane & -536870913;\n if (\n updateLane !== update.lane\n ? (workInProgressRootRenderLanes & updateLane) === updateLane\n : (renderLanes & updateLane) === updateLane\n ) {\n var revertLane = update.revertLane;\n if (0 === revertLane)\n null !== newBaseQueueLast &&\n (newBaseQueueLast = newBaseQueueLast.next =\n {\n lane: 0,\n revertLane: 0,\n gesture: null,\n action: update.action,\n hasEagerState: update.hasEagerState,\n eagerState: update.eagerState,\n next: null\n }),\n updateLane === currentEntangledLane &&\n (didReadFromEntangledAsyncAction$60 = !0);\n else if ((renderLanes & revertLane) === revertLane) {\n update = update.next;\n revertLane === currentEntangledLane &&\n (didReadFromEntangledAsyncAction$60 = !0);\n continue;\n } else\n (updateLane = {\n lane: 0,\n revertLane: update.revertLane,\n gesture: null,\n action: update.action,\n hasEagerState: update.hasEagerState,\n eagerState: update.eagerState,\n next: null\n }),\n null === newBaseQueueLast\n ? ((newBaseQueueFirst = newBaseQueueLast = updateLane),\n (baseFirst = pendingQueue))\n : (newBaseQueueLast = newBaseQueueLast.next = updateLane),\n (currentlyRenderingFiber.lanes |= revertLane),\n (workInProgressRootSkippedLanes |= revertLane);\n updateLane = update.action;\n shouldDoubleInvokeUserFnsInHooksDEV &&\n reducer(pendingQueue, updateLane);\n pendingQueue = update.hasEagerState\n ? update.eagerState\n : reducer(pendingQueue, updateLane);\n } else\n (revertLane = {\n lane: updateLane,\n revertLane: update.revertLane,\n gesture: update.gesture,\n action: update.action,\n hasEagerState: update.hasEagerState,\n eagerState: update.eagerState,\n next: null\n }),\n null === newBaseQueueLast\n ? ((newBaseQueueFirst = newBaseQueueLast = revertLane),\n (baseFirst = pendingQueue))\n : (newBaseQueueLast = newBaseQueueLast.next = revertLane),\n (currentlyRenderingFiber.lanes |= updateLane),\n (workInProgressRootSkippedLanes |= updateLane);\n update = update.next;\n } while (null !== update && update !== current);\n null === newBaseQueueLast\n ? (baseFirst = pendingQueue)\n : (newBaseQueueLast.next = newBaseQueueFirst);\n if (\n !objectIs(pendingQueue, hook.memoizedState) &&\n ((didReceiveUpdate = !0),\n didReadFromEntangledAsyncAction$60 &&\n ((reducer = currentEntangledActionThenable), null !== reducer))\n )\n throw reducer;\n hook.memoizedState = pendingQueue;\n hook.baseState = baseFirst;\n hook.baseQueue = newBaseQueueLast;\n queue.lastRenderedState = pendingQueue;\n }\n null === baseQueue && (queue.lanes = 0);\n return [hook.memoizedState, queue.dispatch];\n}\nfunction rerenderReducer(reducer) {\n var hook = updateWorkInProgressHook(),\n queue = hook.queue;\n if (null === queue) throw Error(formatProdErrorMessage(311));\n queue.lastRenderedReducer = reducer;\n var dispatch = queue.dispatch,\n lastRenderPhaseUpdate = queue.pending,\n newState = hook.memoizedState;\n if (null !== lastRenderPhaseUpdate) {\n queue.pending = null;\n var update = (lastRenderPhaseUpdate = lastRenderPhaseUpdate.next);\n do (newState = reducer(newState, update.action)), (update = update.next);\n while (update !== lastRenderPhaseUpdate);\n objectIs(newState, hook.memoizedState) || (didReceiveUpdate = !0);\n hook.memoizedState = newState;\n null === hook.baseQueue && (hook.baseState = newState);\n queue.lastRenderedState = newState;\n }\n return [newState, dispatch];\n}\nfunction updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {\n var fiber = currentlyRenderingFiber,\n hook = updateWorkInProgressHook(),\n isHydrating$jscomp$0 = isHydrating;\n if (isHydrating$jscomp$0) {\n if (void 0 === getServerSnapshot) throw Error(formatProdErrorMessage(407));\n getServerSnapshot = getServerSnapshot();\n } else getServerSnapshot = getSnapshot();\n var snapshotChanged = !objectIs(\n (currentHook || hook).memoizedState,\n getServerSnapshot\n );\n snapshotChanged &&\n ((hook.memoizedState = getServerSnapshot), (didReceiveUpdate = !0));\n hook = hook.queue;\n updateEffect(subscribeToStore.bind(null, fiber, hook, subscribe), [\n subscribe\n ]);\n if (\n hook.getSnapshot !== getSnapshot ||\n snapshotChanged ||\n (null !== workInProgressHook && workInProgressHook.memoizedState.tag & 1)\n ) {\n fiber.flags |= 2048;\n pushSimpleEffect(\n 9,\n { destroy: void 0 },\n updateStoreInstance.bind(\n null,\n fiber,\n hook,\n getServerSnapshot,\n getSnapshot\n ),\n null\n );\n if (null === workInProgressRoot) throw Error(formatProdErrorMessage(349));\n isHydrating$jscomp$0 ||\n 0 !== (renderLanes & 127) ||\n pushStoreConsistencyCheck(fiber, getSnapshot, getServerSnapshot);\n }\n return getServerSnapshot;\n}\nfunction pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) {\n fiber.flags |= 16384;\n fiber = { getSnapshot: getSnapshot, value: renderedSnapshot };\n getSnapshot = currentlyRenderingFiber.updateQueue;\n null === getSnapshot\n ? ((getSnapshot = createFunctionComponentUpdateQueue()),\n (currentlyRenderingFiber.updateQueue = getSnapshot),\n (getSnapshot.stores = [fiber]))\n : ((renderedSnapshot = getSnapshot.stores),\n null === renderedSnapshot\n ? (getSnapshot.stores = [fiber])\n : renderedSnapshot.push(fiber));\n}\nfunction updateStoreInstance(fiber, inst, nextSnapshot, getSnapshot) {\n inst.value = nextSnapshot;\n inst.getSnapshot = getSnapshot;\n checkIfSnapshotChanged(inst) && forceStoreRerender(fiber);\n}\nfunction subscribeToStore(fiber, inst, subscribe) {\n return subscribe(function () {\n checkIfSnapshotChanged(inst) && forceStoreRerender(fiber);\n });\n}\nfunction checkIfSnapshotChanged(inst) {\n var latestGetSnapshot = inst.getSnapshot;\n inst = inst.value;\n try {\n var nextValue = latestGetSnapshot();\n return !objectIs(inst, nextValue);\n } catch (error) {\n return !0;\n }\n}\nfunction forceStoreRerender(fiber) {\n var root = enqueueConcurrentRenderForLane(fiber, 2);\n null !== root && scheduleUpdateOnFiber(root, fiber, 2);\n}\nfunction mountStateImpl(initialState) {\n var hook = mountWorkInProgressHook();\n if (\"function\" === typeof initialState) {\n var initialStateInitializer = initialState;\n initialState = initialStateInitializer();\n if (shouldDoubleInvokeUserFnsInHooksDEV) {\n setIsStrictModeForDevtools(!0);\n try {\n initialStateInitializer();\n } finally {\n setIsStrictModeForDevtools(!1);\n }\n }\n }\n hook.memoizedState = hook.baseState = initialState;\n hook.queue = {\n pending: null,\n lanes: 0,\n dispatch: null,\n lastRenderedReducer: basicStateReducer,\n lastRenderedState: initialState\n };\n return hook;\n}\nfunction updateOptimisticImpl(hook, current, passthrough, reducer) {\n hook.baseState = passthrough;\n return updateReducerImpl(\n hook,\n currentHook,\n \"function\" === typeof reducer ? reducer : basicStateReducer\n );\n}\nfunction dispatchActionState(\n fiber,\n actionQueue,\n setPendingState,\n setState,\n payload\n) {\n if (isRenderPhaseUpdate(fiber)) throw Error(formatProdErrorMessage(485));\n fiber = actionQueue.action;\n if (null !== fiber) {\n var actionNode = {\n payload: payload,\n action: fiber,\n next: null,\n isTransition: !0,\n status: \"pending\",\n value: null,\n reason: null,\n listeners: [],\n then: function (listener) {\n actionNode.listeners.push(listener);\n }\n };\n null !== ReactSharedInternals.T\n ? setPendingState(!0)\n : (actionNode.isTransition = !1);\n setState(actionNode);\n setPendingState = actionQueue.pending;\n null === setPendingState\n ? ((actionNode.next = actionQueue.pending = actionNode),\n runActionStateAction(actionQueue, actionNode))\n : ((actionNode.next = setPendingState.next),\n (actionQueue.pending = setPendingState.next = actionNode));\n }\n}\nfunction runActionStateAction(actionQueue, node) {\n var action = node.action,\n payload = node.payload,\n prevState = actionQueue.state;\n if (node.isTransition) {\n var prevTransition = ReactSharedInternals.T,\n currentTransition = {};\n ReactSharedInternals.T = currentTransition;\n try {\n var returnValue = action(prevState, payload),\n onStartTransitionFinish = ReactSharedInternals.S;\n null !== onStartTransitionFinish &&\n onStartTransitionFinish(currentTransition, returnValue);\n handleActionReturnValue(actionQueue, node, returnValue);\n } catch (error) {\n onActionError(actionQueue, node, error);\n } finally {\n null !== prevTransition &&\n null !== currentTransition.types &&\n (prevTransition.types = currentTransition.types),\n (ReactSharedInternals.T = prevTransition);\n }\n } else\n try {\n (prevTransition = action(prevState, payload)),\n handleActionReturnValue(actionQueue, node, prevTransition);\n } catch (error$66) {\n onActionError(actionQueue, node, error$66);\n }\n}\nfunction handleActionReturnValue(actionQueue, node, returnValue) {\n null !== returnValue &&\n \"object\" === typeof returnValue &&\n \"function\" === typeof returnValue.then\n ? returnValue.then(\n function (nextState) {\n onActionSuccess(actionQueue, node, nextState);\n },\n function (error) {\n return onActionError(actionQueue, node, error);\n }\n )\n : onActionSuccess(actionQueue, node, returnValue);\n}\nfunction onActionSuccess(actionQueue, actionNode, nextState) {\n actionNode.status = \"fulfilled\";\n actionNode.value = nextState;\n notifyActionListeners(actionNode);\n actionQueue.state = nextState;\n actionNode = actionQueue.pending;\n null !== actionNode &&\n ((nextState = actionNode.next),\n nextState === actionNode\n ? (actionQueue.pending = null)\n : ((nextState = nextState.next),\n (actionNode.next = nextState),\n runActionStateAction(actionQueue, nextState)));\n}\nfunction onActionError(actionQueue, actionNode, error) {\n var last = actionQueue.pending;\n actionQueue.pending = null;\n if (null !== last) {\n last = last.next;\n do\n (actionNode.status = \"rejected\"),\n (actionNode.reason = error),\n notifyActionListeners(actionNode),\n (actionNode = actionNode.next);\n while (actionNode !== last);\n }\n actionQueue.action = null;\n}\nfunction notifyActionListeners(actionNode) {\n actionNode = actionNode.listeners;\n for (var i = 0; i < actionNode.length; i++) (0, actionNode[i])();\n}\nfunction actionStateReducer(oldState, newState) {\n return newState;\n}\nfunction mountActionState(action, initialStateProp) {\n if (isHydrating) {\n var ssrFormState = workInProgressRoot.formState;\n if (null !== ssrFormState) {\n a: {\n var JSCompiler_inline_result = currentlyRenderingFiber;\n if (isHydrating) {\n if (nextHydratableInstance) {\n b: {\n var JSCompiler_inline_result$jscomp$0 = nextHydratableInstance;\n for (\n var inRootOrSingleton = rootOrSingletonContext;\n 8 !== JSCompiler_inline_result$jscomp$0.nodeType;\n\n ) {\n if (!inRootOrSingleton) {\n JSCompiler_inline_result$jscomp$0 = null;\n break b;\n }\n JSCompiler_inline_result$jscomp$0 = getNextHydratable(\n JSCompiler_inline_result$jscomp$0.nextSibling\n );\n if (null === JSCompiler_inline_result$jscomp$0) {\n JSCompiler_inline_result$jscomp$0 = null;\n break b;\n }\n }\n inRootOrSingleton = JSCompiler_inline_result$jscomp$0.data;\n JSCompiler_inline_result$jscomp$0 =\n \"F!\" === inRootOrSingleton || \"F\" === inRootOrSingleton\n ? JSCompiler_inline_result$jscomp$0\n : null;\n }\n if (JSCompiler_inline_result$jscomp$0) {\n nextHydratableInstance = getNextHydratable(\n JSCompiler_inline_result$jscomp$0.nextSibling\n );\n JSCompiler_inline_result =\n \"F!\" === JSCompiler_inline_result$jscomp$0.data;\n break a;\n }\n }\n throwOnHydrationMismatch(JSCompiler_inline_result);\n }\n JSCompiler_inline_result = !1;\n }\n JSCompiler_inline_result && (initialStateProp = ssrFormState[0]);\n }\n }\n ssrFormState = mountWorkInProgressHook();\n ssrFormState.memoizedState = ssrFormState.baseState = initialStateProp;\n JSCompiler_inline_result = {\n pending: null,\n lanes: 0,\n dispatch: null,\n lastRenderedReducer: actionStateReducer,\n lastRenderedState: initialStateProp\n };\n ssrFormState.queue = JSCompiler_inline_result;\n ssrFormState = dispatchSetState.bind(\n null,\n currentlyRenderingFiber,\n JSCompiler_inline_result\n );\n JSCompiler_inline_result.dispatch = ssrFormState;\n JSCompiler_inline_result = mountStateImpl(!1);\n inRootOrSingleton = dispatchOptimisticSetState.bind(\n null,\n currentlyRenderingFiber,\n !1,\n JSCompiler_inline_result.queue\n );\n JSCompiler_inline_result = mountWorkInProgressHook();\n JSCompiler_inline_result$jscomp$0 = {\n state: initialStateProp,\n dispatch: null,\n action: action,\n pending: null\n };\n JSCompiler_inline_result.queue = JSCompiler_inline_result$jscomp$0;\n ssrFormState = dispatchActionState.bind(\n null,\n currentlyRenderingFiber,\n JSCompiler_inline_result$jscomp$0,\n inRootOrSingleton,\n ssrFormState\n );\n JSCompiler_inline_result$jscomp$0.dispatch = ssrFormState;\n JSCompiler_inline_result.memoizedState = action;\n return [initialStateProp, ssrFormState, !1];\n}\nfunction updateActionState(action) {\n var stateHook = updateWorkInProgressHook();\n return updateActionStateImpl(stateHook, currentHook, action);\n}\nfunction updateActionStateImpl(stateHook, currentStateHook, action) {\n currentStateHook = updateReducerImpl(\n stateHook,\n currentStateHook,\n actionStateReducer\n )[0];\n stateHook = updateReducer(basicStateReducer)[0];\n if (\n \"object\" === typeof currentStateHook &&\n null !== currentStateHook &&\n \"function\" === typeof currentStateHook.then\n )\n try {\n var state = useThenable(currentStateHook);\n } catch (x) {\n if (x === SuspenseException) throw SuspenseActionException;\n throw x;\n }\n else state = currentStateHook;\n currentStateHook = updateWorkInProgressHook();\n var actionQueue = currentStateHook.queue,\n dispatch = actionQueue.dispatch;\n action !== currentStateHook.memoizedState &&\n ((currentlyRenderingFiber.flags |= 2048),\n pushSimpleEffect(\n 9,\n { destroy: void 0 },\n actionStateActionEffect.bind(null, actionQueue, action),\n null\n ));\n return [state, dispatch, stateHook];\n}\nfunction actionStateActionEffect(actionQueue, action) {\n actionQueue.action = action;\n}\nfunction rerenderActionState(action) {\n var stateHook = updateWorkInProgressHook(),\n currentStateHook = currentHook;\n if (null !== currentStateHook)\n return updateActionStateImpl(stateHook, currentStateHook, action);\n updateWorkInProgressHook();\n stateHook = stateHook.memoizedState;\n currentStateHook = updateWorkInProgressHook();\n var dispatch = currentStateHook.queue.dispatch;\n currentStateHook.memoizedState = action;\n return [stateHook, dispatch, !1];\n}\nfunction pushSimpleEffect(tag, inst, create, deps) {\n tag = { tag: tag, create: create, deps: deps, inst: inst, next: null };\n inst = currentlyRenderingFiber.updateQueue;\n null === inst &&\n ((inst = createFunctionComponentUpdateQueue()),\n (currentlyRenderingFiber.updateQueue = inst));\n create = inst.lastEffect;\n null === create\n ? (inst.lastEffect = tag.next = tag)\n : ((deps = create.next),\n (create.next = tag),\n (tag.next = deps),\n (inst.lastEffect = tag));\n return tag;\n}\nfunction updateRef() {\n return updateWorkInProgressHook().memoizedState;\n}\nfunction mountEffectImpl(fiberFlags, hookFlags, create, deps) {\n var hook = mountWorkInProgressHook();\n currentlyRenderingFiber.flags |= fiberFlags;\n hook.memoizedState = pushSimpleEffect(\n 1 | hookFlags,\n { destroy: void 0 },\n create,\n void 0 === deps ? null : deps\n );\n}\nfunction updateEffectImpl(fiberFlags, hookFlags, create, deps) {\n var hook = updateWorkInProgressHook();\n deps = void 0 === deps ? null : deps;\n var inst = hook.memoizedState.inst;\n null !== currentHook &&\n null !== deps &&\n areHookInputsEqual(deps, currentHook.memoizedState.deps)\n ? (hook.memoizedState = pushSimpleEffect(hookFlags, inst, create, deps))\n : ((currentlyRenderingFiber.flags |= fiberFlags),\n (hook.memoizedState = pushSimpleEffect(\n 1 | hookFlags,\n inst,\n create,\n deps\n )));\n}\nfunction mountEffect(create, deps) {\n mountEffectImpl(8390656, 8, create, deps);\n}\nfunction updateEffect(create, deps) {\n updateEffectImpl(2048, 8, create, deps);\n}\nfunction useEffectEventImpl(payload) {\n currentlyRenderingFiber.flags |= 4;\n var componentUpdateQueue = currentlyRenderingFiber.updateQueue;\n if (null === componentUpdateQueue)\n (componentUpdateQueue = createFunctionComponentUpdateQueue()),\n (currentlyRenderingFiber.updateQueue = componentUpdateQueue),\n (componentUpdateQueue.events = [payload]);\n else {\n var events = componentUpdateQueue.events;\n null === events\n ? (componentUpdateQueue.events = [payload])\n : events.push(payload);\n }\n}\nfunction updateEvent(callback) {\n var ref = updateWorkInProgressHook().memoizedState;\n useEffectEventImpl({ ref: ref, nextImpl: callback });\n return function () {\n if (0 !== (executionContext & 2)) throw Error(formatProdErrorMessage(440));\n return ref.impl.apply(void 0, arguments);\n };\n}\nfunction updateInsertionEffect(create, deps) {\n return updateEffectImpl(4, 2, create, deps);\n}\nfunction updateLayoutEffect(create, deps) {\n return updateEffectImpl(4, 4, create, deps);\n}\nfunction imperativeHandleEffect(create, ref) {\n if (\"function\" === typeof ref) {\n create = create();\n var refCleanup = ref(create);\n return function () {\n \"function\" === typeof refCleanup ? refCleanup() : ref(null);\n };\n }\n if (null !== ref && void 0 !== ref)\n return (\n (create = create()),\n (ref.current = create),\n function () {\n ref.current = null;\n }\n );\n}\nfunction updateImperativeHandle(ref, create, deps) {\n deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;\n updateEffectImpl(4, 4, imperativeHandleEffect.bind(null, create, ref), deps);\n}\nfunction mountDebugValue() {}\nfunction updateCallback(callback, deps) {\n var hook = updateWorkInProgressHook();\n deps = void 0 === deps ? null : deps;\n var prevState = hook.memoizedState;\n if (null !== deps && areHookInputsEqual(deps, prevState[1]))\n return prevState[0];\n hook.memoizedState = [callback, deps];\n return callback;\n}\nfunction updateMemo(nextCreate, deps) {\n var hook = updateWorkInProgressHook();\n deps = void 0 === deps ? null : deps;\n var prevState = hook.memoizedState;\n if (null !== deps && areHookInputsEqual(deps, prevState[1]))\n return prevState[0];\n prevState = nextCreate();\n if (shouldDoubleInvokeUserFnsInHooksDEV) {\n setIsStrictModeForDevtools(!0);\n try {\n nextCreate();\n } finally {\n setIsStrictModeForDevtools(!1);\n }\n }\n hook.memoizedState = [prevState, deps];\n return prevState;\n}\nfunction mountDeferredValueImpl(hook, value, initialValue) {\n if (\n void 0 === initialValue ||\n (0 !== (renderLanes & 1073741824) &&\n 0 === (workInProgressRootRenderLanes & 261930))\n )\n return (hook.memoizedState = value);\n hook.memoizedState = initialValue;\n hook = requestDeferredLane();\n currentlyRenderingFiber.lanes |= hook;\n workInProgressRootSkippedLanes |= hook;\n return initialValue;\n}\nfunction updateDeferredValueImpl(hook, prevValue, value, initialValue) {\n if (objectIs(value, prevValue)) return value;\n if (null !== currentTreeHiddenStackCursor.current)\n return (\n (hook = mountDeferredValueImpl(hook, value, initialValue)),\n objectIs(hook, prevValue) || (didReceiveUpdate = !0),\n hook\n );\n if (\n 0 === (renderLanes & 42) ||\n (0 !== (renderLanes & 1073741824) &&\n 0 === (workInProgressRootRenderLanes & 261930))\n )\n return (didReceiveUpdate = !0), (hook.memoizedState = value);\n hook = requestDeferredLane();\n currentlyRenderingFiber.lanes |= hook;\n workInProgressRootSkippedLanes |= hook;\n return prevValue;\n}\nfunction startTransition(fiber, queue, pendingState, finishedState, callback) {\n var previousPriority = ReactDOMSharedInternals.p;\n ReactDOMSharedInternals.p =\n 0 !== previousPriority && 8 > previousPriority ? previousPriority : 8;\n var prevTransition = ReactSharedInternals.T,\n currentTransition = {};\n ReactSharedInternals.T = currentTransition;\n dispatchOptimisticSetState(fiber, !1, queue, pendingState);\n try {\n var returnValue = callback(),\n onStartTransitionFinish = ReactSharedInternals.S;\n null !== onStartTransitionFinish &&\n onStartTransitionFinish(currentTransition, returnValue);\n if (\n null !== returnValue &&\n \"object\" === typeof returnValue &&\n \"function\" === typeof returnValue.then\n ) {\n var thenableForFinishedState = chainThenableValue(\n returnValue,\n finishedState\n );\n dispatchSetStateInternal(\n fiber,\n queue,\n thenableForFinishedState,\n requestUpdateLane(fiber)\n );\n } else\n dispatchSetStateInternal(\n fiber,\n queue,\n finishedState,\n requestUpdateLane(fiber)\n );\n } catch (error) {\n dispatchSetStateInternal(\n fiber,\n queue,\n { then: function () {}, status: \"rejected\", reason: error },\n requestUpdateLane()\n );\n } finally {\n (ReactDOMSharedInternals.p = previousPriority),\n null !== prevTransition &&\n null !== currentTransition.types &&\n (prevTransition.types = currentTransition.types),\n (ReactSharedInternals.T = prevTransition);\n }\n}\nfunction noop() {}\nfunction startHostTransition(formFiber, pendingState, action, formData) {\n if (5 !== formFiber.tag) throw Error(formatProdErrorMessage(476));\n var queue = ensureFormComponentIsStateful(formFiber).queue;\n startTransition(\n formFiber,\n queue,\n pendingState,\n sharedNotPendingObject,\n null === action\n ? noop\n : function () {\n requestFormReset$1(formFiber);\n return action(formData);\n }\n );\n}\nfunction ensureFormComponentIsStateful(formFiber) {\n var existingStateHook = formFiber.memoizedState;\n if (null !== existingStateHook) return existingStateHook;\n existingStateHook = {\n memoizedState: sharedNotPendingObject,\n baseState: sharedNotPendingObject,\n baseQueue: null,\n queue: {\n pending: null,\n lanes: 0,\n dispatch: null,\n lastRenderedReducer: basicStateReducer,\n lastRenderedState: sharedNotPendingObject\n },\n next: null\n };\n var initialResetState = {};\n existingStateHook.next = {\n memoizedState: initialResetState,\n baseState: initialResetState,\n baseQueue: null,\n queue: {\n pending: null,\n lanes: 0,\n dispatch: null,\n lastRenderedReducer: basicStateReducer,\n lastRenderedState: initialResetState\n },\n next: null\n };\n formFiber.memoizedState = existingStateHook;\n formFiber = formFiber.alternate;\n null !== formFiber && (formFiber.memoizedState = existingStateHook);\n return existingStateHook;\n}\nfunction requestFormReset$1(formFiber) {\n var stateHook = ensureFormComponentIsStateful(formFiber);\n null === stateHook.next && (stateHook = formFiber.alternate.memoizedState);\n dispatchSetStateInternal(\n formFiber,\n stateHook.next.queue,\n {},\n requestUpdateLane()\n );\n}\nfunction useHostTransitionStatus() {\n return readContext(HostTransitionContext);\n}\nfunction updateId() {\n return updateWorkInProgressHook().memoizedState;\n}\nfunction updateRefresh() {\n return updateWorkInProgressHook().memoizedState;\n}\nfunction refreshCache(fiber) {\n for (var provider = fiber.return; null !== provider; ) {\n switch (provider.tag) {\n case 24:\n case 3:\n var lane = requestUpdateLane();\n fiber = createUpdate(lane);\n var root$69 = enqueueUpdate(provider, fiber, lane);\n null !== root$69 &&\n (scheduleUpdateOnFiber(root$69, provider, lane),\n entangleTransitions(root$69, provider, lane));\n provider = { cache: createCache() };\n fiber.payload = provider;\n return;\n }\n provider = provider.return;\n }\n}\nfunction dispatchReducerAction(fiber, queue, action) {\n var lane = requestUpdateLane();\n action = {\n lane: lane,\n revertLane: 0,\n gesture: null,\n action: action,\n hasEagerState: !1,\n eagerState: null,\n next: null\n };\n isRenderPhaseUpdate(fiber)\n ? enqueueRenderPhaseUpdate(queue, action)\n : ((action = enqueueConcurrentHookUpdate(fiber, queue, action, lane)),\n null !== action &&\n (scheduleUpdateOnFiber(action, fiber, lane),\n entangleTransitionUpdate(action, queue, lane)));\n}\nfunction dispatchSetState(fiber, queue, action) {\n var lane = requestUpdateLane();\n dispatchSetStateInternal(fiber, queue, action, lane);\n}\nfunction dispatchSetStateInternal(fiber, queue, action, lane) {\n var update = {\n lane: lane,\n revertLane: 0,\n gesture: null,\n action: action,\n hasEagerState: !1,\n eagerState: null,\n next: null\n };\n if (isRenderPhaseUpdate(fiber)) enqueueRenderPhaseUpdate(queue, update);\n else {\n var alternate = fiber.alternate;\n if (\n 0 === fiber.lanes &&\n (null === alternate || 0 === alternate.lanes) &&\n ((alternate = queue.lastRenderedReducer), null !== alternate)\n )\n try {\n var currentState = queue.lastRenderedState,\n eagerState = alternate(currentState, action);\n update.hasEagerState = !0;\n update.eagerState = eagerState;\n if (objectIs(eagerState, currentState))\n return (\n enqueueUpdate$1(fiber, queue, update, 0),\n null === workInProgressRoot && finishQueueingConcurrentUpdates(),\n !1\n );\n } catch (error) {\n } finally {\n }\n action = enqueueConcurrentHookUpdate(fiber, queue, update, lane);\n if (null !== action)\n return (\n scheduleUpdateOnFiber(action, fiber, lane),\n entangleTransitionUpdate(action, queue, lane),\n !0\n );\n }\n return !1;\n}\nfunction dispatchOptimisticSetState(fiber, throwIfDuringRender, queue, action) {\n action = {\n lane: 2,\n revertLane: requestTransitionLane(),\n gesture: null,\n action: action,\n hasEagerState: !1,\n eagerState: null,\n next: null\n };\n if (isRenderPhaseUpdate(fiber)) {\n if (throwIfDuringRender) throw Error(formatProdErrorMessage(479));\n } else\n (throwIfDuringRender = enqueueConcurrentHookUpdate(\n fiber,\n queue,\n action,\n 2\n )),\n null !== throwIfDuringRender &&\n scheduleUpdateOnFiber(throwIfDuringRender, fiber, 2);\n}\nfunction isRenderPhaseUpdate(fiber) {\n var alternate = fiber.alternate;\n return (\n fiber === currentlyRenderingFiber ||\n (null !== alternate && alternate === currentlyRenderingFiber)\n );\n}\nfunction enqueueRenderPhaseUpdate(queue, update) {\n didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate =\n !0;\n var pending = queue.pending;\n null === pending\n ? (update.next = update)\n : ((update.next = pending.next), (pending.next = update));\n queue.pending = update;\n}\nfunction entangleTransitionUpdate(root, queue, lane) {\n if (0 !== (lane & 4194048)) {\n var queueLanes = queue.lanes;\n queueLanes &= root.pendingLanes;\n lane |= queueLanes;\n queue.lanes = lane;\n markRootEntangled(root, lane);\n }\n}\nvar ContextOnlyDispatcher = {\n readContext: readContext,\n use: use,\n useCallback: throwInvalidHookError,\n useContext: throwInvalidHookError,\n useEffect: throwInvalidHookError,\n useImperativeHandle: throwInvalidHookError,\n useLayoutEffect: throwInvalidHookError,\n useInsertionEffect: throwInvalidHookError,\n useMemo: throwInvalidHookError,\n useReducer: throwInvalidHookError,\n useRef: throwInvalidHookError,\n useState: throwInvalidHookError,\n useDebugValue: throwInvalidHookError,\n useDeferredValue: throwInvalidHookError,\n useTransition: throwInvalidHookError,\n useSyncExternalStore: throwInvalidHookError,\n useId: throwInvalidHookError,\n useHostTransitionStatus: throwInvalidHookError,\n useFormState: throwInvalidHookError,\n useActionState: throwInvalidHookError,\n useOptimistic: throwInvalidHookError,\n useMemoCache: throwInvalidHookError,\n useCacheRefresh: throwInvalidHookError\n};\nContextOnlyDispatcher.useEffectEvent = throwInvalidHookError;\nvar HooksDispatcherOnMount = {\n readContext: readContext,\n use: use,\n useCallback: function (callback, deps) {\n mountWorkInProgressHook().memoizedState = [\n callback,\n void 0 === deps ? null : deps\n ];\n return callback;\n },\n useContext: readContext,\n useEffect: mountEffect,\n useImperativeHandle: function (ref, create, deps) {\n deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null;\n mountEffectImpl(\n 4194308,\n 4,\n imperativeHandleEffect.bind(null, create, ref),\n deps\n );\n },\n useLayoutEffect: function (create, deps) {\n return mountEffectImpl(4194308, 4, create, deps);\n },\n useInsertionEffect: function (create, deps) {\n mountEffectImpl(4, 2, create, deps);\n },\n useMemo: function (nextCreate, deps) {\n var hook = mountWorkInProgressHook();\n deps = void 0 === deps ? null : deps;\n var nextValue = nextCreate();\n if (shouldDoubleInvokeUserFnsInHooksDEV) {\n setIsStrictModeForDevtools(!0);\n try {\n nextCreate();\n } finally {\n setIsStrictModeForDevtools(!1);\n }\n }\n hook.memoizedState = [nextValue, deps];\n return nextValue;\n },\n useReducer: function (reducer, initialArg, init) {\n var hook = mountWorkInProgressHook();\n if (void 0 !== init) {\n var initialState = init(initialArg);\n if (shouldDoubleInvokeUserFnsInHooksDEV) {\n setIsStrictModeForDevtools(!0);\n try {\n init(initialArg);\n } finally {\n setIsStrictModeForDevtools(!1);\n }\n }\n } else initialState = initialArg;\n hook.memoizedState = hook.baseState = initialState;\n reducer = {\n pending: null,\n lanes: 0,\n dispatch: null,\n lastRenderedReducer: reducer,\n lastRenderedState: initialState\n };\n hook.queue = reducer;\n reducer = reducer.dispatch = dispatchReducerAction.bind(\n null,\n currentlyRenderingFiber,\n reducer\n );\n return [hook.memoizedState, reducer];\n },\n useRef: function (initialValue) {\n var hook = mountWorkInProgressHook();\n initialValue = { current: initialValue };\n return (hook.memoizedState = initialValue);\n },\n useState: function (initialState) {\n initialState = mountStateImpl(initialState);\n var queue = initialState.queue,\n dispatch = dispatchSetState.bind(null, currentlyRenderingFiber, queue);\n queue.dispatch = dispatch;\n return [initialState.memoizedState, dispatch];\n },\n useDebugValue: mountDebugValue,\n useDeferredValue: function (value, initialValue) {\n var hook = mountWorkInProgressHook();\n return mountDeferredValueImpl(hook, value, initialValue);\n },\n useTransition: function () {\n var stateHook = mountStateImpl(!1);\n stateHook = startTransition.bind(\n null,\n currentlyRenderingFiber,\n stateHook.queue,\n !0,\n !1\n );\n mountWorkInProgressHook().memoizedState = stateHook;\n return [!1, stateHook];\n },\n useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) {\n var fiber = currentlyRenderingFiber,\n hook = mountWorkInProgressHook();\n if (isHydrating) {\n if (void 0 === getServerSnapshot)\n throw Error(formatProdErrorMessage(407));\n getServerSnapshot = getServerSnapshot();\n } else {\n getServerSnapshot = getSnapshot();\n if (null === workInProgressRoot)\n throw Error(formatProdErrorMessage(349));\n 0 !== (workInProgressRootRenderLanes & 127) ||\n pushStoreConsistencyCheck(fiber, getSnapshot, getServerSnapshot);\n }\n hook.memoizedState = getServerSnapshot;\n var inst = { value: getServerSnapshot, getSnapshot: getSnapshot };\n hook.queue = inst;\n mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [\n subscribe\n ]);\n fiber.flags |= 2048;\n pushSimpleEffect(\n 9,\n { destroy: void 0 },\n updateStoreInstance.bind(\n null,\n fiber,\n inst,\n getServerSnapshot,\n getSnapshot\n ),\n null\n );\n return getServerSnapshot;\n },\n useId: function () {\n var hook = mountWorkInProgressHook(),\n identifierPrefix = workInProgressRoot.identifierPrefix;\n if (isHydrating) {\n var JSCompiler_inline_result = treeContextOverflow;\n var idWithLeadingBit = treeContextId;\n JSCompiler_inline_result =\n (\n idWithLeadingBit & ~(1 << (32 - clz32(idWithLeadingBit) - 1))\n ).toString(32) + JSCompiler_inline_result;\n identifierPrefix =\n \"_\" + identifierPrefix + \"R_\" + JSCompiler_inline_result;\n JSCompiler_inline_result = localIdCounter++;\n 0 < JSCompiler_inline_result &&\n (identifierPrefix += \"H\" + JSCompiler_inline_result.toString(32));\n identifierPrefix += \"_\";\n } else\n (JSCompiler_inline_result = globalClientIdCounter++),\n (identifierPrefix =\n \"_\" +\n identifierPrefix +\n \"r_\" +\n JSCompiler_inline_result.toString(32) +\n \"_\");\n return (hook.memoizedState = identifierPrefix);\n },\n useHostTransitionStatus: useHostTransitionStatus,\n useFormState: mountActionState,\n useActionState: mountActionState,\n useOptimistic: function (passthrough) {\n var hook = mountWorkInProgressHook();\n hook.memoizedState = hook.baseState = passthrough;\n var queue = {\n pending: null,\n lanes: 0,\n dispatch: null,\n lastRenderedReducer: null,\n lastRenderedState: null\n };\n hook.queue = queue;\n hook = dispatchOptimisticSetState.bind(\n null,\n currentlyRenderingFiber,\n !0,\n queue\n );\n queue.dispatch = hook;\n return [passthrough, hook];\n },\n useMemoCache: useMemoCache,\n useCacheRefresh: function () {\n return (mountWorkInProgressHook().memoizedState = refreshCache.bind(\n null,\n currentlyRenderingFiber\n ));\n },\n useEffectEvent: function (callback) {\n var hook = mountWorkInProgressHook(),\n ref = { impl: callback };\n hook.memoizedState = ref;\n return function () {\n if (0 !== (executionContext & 2))\n throw Error(formatProdErrorMessage(440));\n return ref.impl.apply(void 0, arguments);\n };\n }\n },\n HooksDispatcherOnUpdate = {\n readContext: readContext,\n use: use,\n useCallback: updateCallback,\n useContext: readContext,\n useEffect: updateEffect,\n useImperativeHandle: updateImperativeHandle,\n useInsertionEffect: updateInsertionEffect,\n useLayoutEffect: updateLayoutEffect,\n useMemo: updateMemo,\n useReducer: updateReducer,\n useRef: updateRef,\n useState: function () {\n return updateReducer(basicStateReducer);\n },\n useDebugValue: mountDebugValue,\n useDeferredValue: function (value, initialValue) {\n var hook = updateWorkInProgressHook();\n return updateDeferredValueImpl(\n hook,\n currentHook.memoizedState,\n value,\n initialValue\n );\n },\n useTransition: function () {\n var booleanOrThenable = updateReducer(basicStateReducer)[0],\n start = updateWorkInProgressHook().memoizedState;\n return [\n \"boolean\" === typeof booleanOrThenable\n ? booleanOrThenable\n : useThenable(booleanOrThenable),\n start\n ];\n },\n useSyncExternalStore: updateSyncExternalStore,\n useId: updateId,\n useHostTransitionStatus: useHostTransitionStatus,\n useFormState: updateActionState,\n useActionState: updateActionState,\n useOptimistic: function (passthrough, reducer) {\n var hook = updateWorkInProgressHook();\n return updateOptimisticImpl(hook, currentHook, passthrough, reducer);\n },\n useMemoCache: useMemoCache,\n useCacheRefresh: updateRefresh\n };\nHooksDispatcherOnUpdate.useEffectEvent = updateEvent;\nvar HooksDispatcherOnRerender = {\n readContext: readContext,\n use: use,\n useCallback: updateCallback,\n useContext: readContext,\n useEffect: updateEffect,\n useImperativeHandle: updateImperativeHandle,\n useInsertionEffect: updateInsertionEffect,\n useLayoutEffect: updateLayoutEffect,\n useMemo: updateMemo,\n useReducer: rerenderReducer,\n useRef: updateRef,\n useState: function () {\n return rerenderReducer(basicStateReducer);\n },\n useDebugValue: mountDebugValue,\n useDeferredValue: function (value, initialValue) {\n var hook = updateWorkInProgressHook();\n return null === currentHook\n ? mountDeferredValueImpl(hook, value, initialValue)\n : updateDeferredValueImpl(\n hook,\n currentHook.memoizedState,\n value,\n initialValue\n );\n },\n useTransition: function () {\n var booleanOrThenable = rerenderReducer(basicStateReducer)[0],\n start = updateWorkInProgressHook().memoizedState;\n return [\n \"boolean\" === typeof booleanOrThenable\n ? booleanOrThenable\n : useThenable(booleanOrThenable),\n start\n ];\n },\n useSyncExternalStore: updateSyncExternalStore,\n useId: updateId,\n useHostTransitionStatus: useHostTransitionStatus,\n useFormState: rerenderActionState,\n useActionState: rerenderActionState,\n useOptimistic: function (passthrough, reducer) {\n var hook = updateWorkInProgressHook();\n if (null !== currentHook)\n return updateOptimisticImpl(hook, currentHook, passthrough, reducer);\n hook.baseState = passthrough;\n return [passthrough, hook.queue.dispatch];\n },\n useMemoCache: useMemoCache,\n useCacheRefresh: updateRefresh\n};\nHooksDispatcherOnRerender.useEffectEvent = updateEvent;\nfunction applyDerivedStateFromProps(\n workInProgress,\n ctor,\n getDerivedStateFromProps,\n nextProps\n) {\n ctor = workInProgress.memoizedState;\n getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor);\n getDerivedStateFromProps =\n null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps\n ? ctor\n : assign({}, ctor, getDerivedStateFromProps);\n workInProgress.memoizedState = getDerivedStateFromProps;\n 0 === workInProgress.lanes &&\n (workInProgress.updateQueue.baseState = getDerivedStateFromProps);\n}\nvar classComponentUpdater = {\n enqueueSetState: function (inst, payload, callback) {\n inst = inst._reactInternals;\n var lane = requestUpdateLane(),\n update = createUpdate(lane);\n update.payload = payload;\n void 0 !== callback && null !== callback && (update.callback = callback);\n payload = enqueueUpdate(inst, update, lane);\n null !== payload &&\n (scheduleUpdateOnFiber(payload, inst, lane),\n entangleTransitions(payload, inst, lane));\n },\n enqueueReplaceState: function (inst, payload, callback) {\n inst = inst._reactInternals;\n var lane = requestUpdateLane(),\n update = createUpdate(lane);\n update.tag = 1;\n update.payload = payload;\n void 0 !== callback && null !== callback && (update.callback = callback);\n payload = enqueueUpdate(inst, update, lane);\n null !== payload &&\n (scheduleUpdateOnFiber(payload, inst, lane),\n entangleTransitions(payload, inst, lane));\n },\n enqueueForceUpdate: function (inst, callback) {\n inst = inst._reactInternals;\n var lane = requestUpdateLane(),\n update = createUpdate(lane);\n update.tag = 2;\n void 0 !== callback && null !== callback && (update.callback = callback);\n callback = enqueueUpdate(inst, update, lane);\n null !== callback &&\n (scheduleUpdateOnFiber(callback, inst, lane),\n entangleTransitions(callback, inst, lane));\n }\n};\nfunction checkShouldComponentUpdate(\n workInProgress,\n ctor,\n oldProps,\n newProps,\n oldState,\n newState,\n nextContext\n) {\n workInProgress = workInProgress.stateNode;\n return \"function\" === typeof workInProgress.shouldComponentUpdate\n ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext)\n : ctor.prototype && ctor.prototype.isPureReactComponent\n ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)\n : !0;\n}\nfunction callComponentWillReceiveProps(\n workInProgress,\n instance,\n newProps,\n nextContext\n) {\n workInProgress = instance.state;\n \"function\" === typeof instance.componentWillReceiveProps &&\n instance.componentWillReceiveProps(newProps, nextContext);\n \"function\" === typeof instance.UNSAFE_componentWillReceiveProps &&\n instance.UNSAFE_componentWillReceiveProps(newProps, nextContext);\n instance.state !== workInProgress &&\n classComponentUpdater.enqueueReplaceState(instance, instance.state, null);\n}\nfunction resolveClassComponentProps(Component, baseProps) {\n var newProps = baseProps;\n if (\"ref\" in baseProps) {\n newProps = {};\n for (var propName in baseProps)\n \"ref\" !== propName && (newProps[propName] = baseProps[propName]);\n }\n if ((Component = Component.defaultProps)) {\n newProps === baseProps && (newProps = assign({}, newProps));\n for (var propName$73 in Component)\n void 0 === newProps[propName$73] &&\n (newProps[propName$73] = Component[propName$73]);\n }\n return newProps;\n}\nfunction defaultOnUncaughtError(error) {\n reportGlobalError(error);\n}\nfunction defaultOnCaughtError(error) {\n console.error(error);\n}\nfunction defaultOnRecoverableError(error) {\n reportGlobalError(error);\n}\nfunction logUncaughtError(root, errorInfo) {\n try {\n var onUncaughtError = root.onUncaughtError;\n onUncaughtError(errorInfo.value, { componentStack: errorInfo.stack });\n } catch (e$74) {\n setTimeout(function () {\n throw e$74;\n });\n }\n}\nfunction logCaughtError(root, boundary, errorInfo) {\n try {\n var onCaughtError = root.onCaughtError;\n onCaughtError(errorInfo.value, {\n componentStack: errorInfo.stack,\n errorBoundary: 1 === boundary.tag ? boundary.stateNode : null\n });\n } catch (e$75) {\n setTimeout(function () {\n throw e$75;\n });\n }\n}\nfunction createRootErrorUpdate(root, errorInfo, lane) {\n lane = createUpdate(lane);\n lane.tag = 3;\n lane.payload = { element: null };\n lane.callback = function () {\n logUncaughtError(root, errorInfo);\n };\n return lane;\n}\nfunction createClassErrorUpdate(lane) {\n lane = createUpdate(lane);\n lane.tag = 3;\n return lane;\n}\nfunction initializeClassErrorUpdate(update, root, fiber, errorInfo) {\n var getDerivedStateFromError = fiber.type.getDerivedStateFromError;\n if (\"function\" === typeof getDerivedStateFromError) {\n var error = errorInfo.value;\n update.payload = function () {\n return getDerivedStateFromError(error);\n };\n update.callback = function () {\n logCaughtError(root, fiber, errorInfo);\n };\n }\n var inst = fiber.stateNode;\n null !== inst &&\n \"function\" === typeof inst.componentDidCatch &&\n (update.callback = function () {\n logCaughtError(root, fiber, errorInfo);\n \"function\" !== typeof getDerivedStateFromError &&\n (null === legacyErrorBoundariesThatAlreadyFailed\n ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this]))\n : legacyErrorBoundariesThatAlreadyFailed.add(this));\n var stack = errorInfo.stack;\n this.componentDidCatch(errorInfo.value, {\n componentStack: null !== stack ? stack : \"\"\n });\n });\n}\nfunction throwException(\n root,\n returnFiber,\n sourceFiber,\n value,\n rootRenderLanes\n) {\n sourceFiber.flags |= 32768;\n if (\n null !== value &&\n \"object\" === typeof value &&\n \"function\" === typeof value.then\n ) {\n returnFiber = sourceFiber.alternate;\n null !== returnFiber &&\n propagateParentContextChanges(\n returnFiber,\n sourceFiber,\n rootRenderLanes,\n !0\n );\n sourceFiber = suspenseHandlerStackCursor.current;\n if (null !== sourceFiber) {\n switch (sourceFiber.tag) {\n case 31:\n case 13:\n return (\n null === shellBoundary\n ? renderDidSuspendDelayIfPossible()\n : null === sourceFiber.alternate &&\n 0 === workInProgressRootExitStatus &&\n (workInProgressRootExitStatus = 3),\n (sourceFiber.flags &= -257),\n (sourceFiber.flags |= 65536),\n (sourceFiber.lanes = rootRenderLanes),\n value === noopSuspenseyCommitThenable\n ? (sourceFiber.flags |= 16384)\n : ((returnFiber = sourceFiber.updateQueue),\n null === returnFiber\n ? (sourceFiber.updateQueue = new Set([value]))\n : returnFiber.add(value),\n attachPingListener(root, value, rootRenderLanes)),\n !1\n );\n case 22:\n return (\n (sourceFiber.flags |= 65536),\n value === noopSuspenseyCommitThenable\n ? (sourceFiber.flags |= 16384)\n : ((returnFiber = sourceFiber.updateQueue),\n null === returnFiber\n ? ((returnFiber = {\n transitions: null,\n markerInstances: null,\n retryQueue: new Set([value])\n }),\n (sourceFiber.updateQueue = returnFiber))\n : ((sourceFiber = returnFiber.retryQueue),\n null === sourceFiber\n ? (returnFiber.retryQueue = new Set([value]))\n : sourceFiber.add(value)),\n attachPingListener(root, value, rootRenderLanes)),\n !1\n );\n }\n throw Error(formatProdErrorMessage(435, sourceFiber.tag));\n }\n attachPingListener(root, value, rootRenderLanes);\n renderDidSuspendDelayIfPossible();\n return !1;\n }\n if (isHydrating)\n return (\n (returnFiber = suspenseHandlerStackCursor.current),\n null !== returnFiber\n ? (0 === (returnFiber.flags & 65536) && (returnFiber.flags |= 256),\n (returnFiber.flags |= 65536),\n (returnFiber.lanes = rootRenderLanes),\n value !== HydrationMismatchException &&\n ((root = Error(formatProdErrorMessage(422), { cause: value })),\n queueHydrationError(createCapturedValueAtFiber(root, sourceFiber))))\n : (value !== HydrationMismatchException &&\n ((returnFiber = Error(formatProdErrorMessage(423), {\n cause: value\n })),\n queueHydrationError(\n createCapturedValueAtFiber(returnFiber, sourceFiber)\n )),\n (root = root.current.alternate),\n (root.flags |= 65536),\n (rootRenderLanes &= -rootRenderLanes),\n (root.lanes |= rootRenderLanes),\n (value = createCapturedValueAtFiber(value, sourceFiber)),\n (rootRenderLanes = createRootErrorUpdate(\n root.stateNode,\n value,\n rootRenderLanes\n )),\n enqueueCapturedUpdate(root, rootRenderLanes),\n 4 !== workInProgressRootExitStatus &&\n (workInProgressRootExitStatus = 2)),\n !1\n );\n var wrapperError = Error(formatProdErrorMessage(520), { cause: value });\n wrapperError = createCapturedValueAtFiber(wrapperError, sourceFiber);\n null === workInProgressRootConcurrentErrors\n ? (workInProgressRootConcurrentErrors = [wrapperError])\n : workInProgressRootConcurrentErrors.push(wrapperError);\n 4 !== workInProgressRootExitStatus && (workInProgressRootExitStatus = 2);\n if (null === returnFiber) return !0;\n value = createCapturedValueAtFiber(value, sourceFiber);\n sourceFiber = returnFiber;\n do {\n switch (sourceFiber.tag) {\n case 3:\n return (\n (sourceFiber.flags |= 65536),\n (root = rootRenderLanes & -rootRenderLanes),\n (sourceFiber.lanes |= root),\n (root = createRootErrorUpdate(sourceFiber.stateNode, value, root)),\n enqueueCapturedUpdate(sourceFiber, root),\n !1\n );\n case 1:\n if (\n ((returnFiber = sourceFiber.type),\n (wrapperError = sourceFiber.stateNode),\n 0 === (sourceFiber.flags & 128) &&\n (\"function\" === typeof returnFiber.getDerivedStateFromError ||\n (null !== wrapperError &&\n \"function\" === typeof wrapperError.componentDidCatch &&\n (null === legacyErrorBoundariesThatAlreadyFailed ||\n !legacyErrorBoundariesThatAlreadyFailed.has(wrapperError)))))\n )\n return (\n (sourceFiber.flags |= 65536),\n (rootRenderLanes &= -rootRenderLanes),\n (sourceFiber.lanes |= rootRenderLanes),\n (rootRenderLanes = createClassErrorUpdate(rootRenderLanes)),\n initializeClassErrorUpdate(\n rootRenderLanes,\n root,\n sourceFiber,\n value\n ),\n enqueueCapturedUpdate(sourceFiber, rootRenderLanes),\n !1\n );\n }\n sourceFiber = sourceFiber.return;\n } while (null !== sourceFiber);\n return !1;\n}\nvar SelectiveHydrationException = Error(formatProdErrorMessage(461)),\n didReceiveUpdate = !1;\nfunction reconcileChildren(current, workInProgress, nextChildren, renderLanes) {\n workInProgress.child =\n null === current\n ? mountChildFibers(workInProgress, null, nextChildren, renderLanes)\n : reconcileChildFibers(\n workInProgress,\n current.child,\n nextChildren,\n renderLanes\n );\n}\nfunction updateForwardRef(\n current,\n workInProgress,\n Component,\n nextProps,\n renderLanes\n) {\n Component = Component.render;\n var ref = workInProgress.ref;\n if (\"ref\" in nextProps) {\n var propsWithoutRef = {};\n for (var key in nextProps)\n \"ref\" !== key && (propsWithoutRef[key] = nextProps[key]);\n } else propsWithoutRef = nextProps;\n prepareToReadContext(workInProgress);\n nextProps = renderWithHooks(\n current,\n workInProgress,\n Component,\n propsWithoutRef,\n ref,\n renderLanes\n );\n key = checkDidRenderIdHook();\n if (null !== current && !didReceiveUpdate)\n return (\n bailoutHooks(current, workInProgress, renderLanes),\n bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes)\n );\n isHydrating && key && pushMaterializedTreeId(workInProgress);\n workInProgress.flags |= 1;\n reconcileChildren(current, workInProgress, nextProps, renderLanes);\n return workInProgress.child;\n}\nfunction updateMemoComponent(\n current,\n workInProgress,\n Component,\n nextProps,\n renderLanes\n) {\n if (null === current) {\n var type = Component.type;\n if (\n \"function\" === typeof type &&\n !shouldConstruct(type) &&\n void 0 === type.defaultProps &&\n null === Component.compare\n )\n return (\n (workInProgress.tag = 15),\n (workInProgress.type = type),\n updateSimpleMemoComponent(\n current,\n workInProgress,\n type,\n nextProps,\n renderLanes\n )\n );\n current = createFiberFromTypeAndProps(\n Component.type,\n null,\n nextProps,\n workInProgress,\n workInProgress.mode,\n renderLanes\n );\n current.ref = workInProgress.ref;\n current.return = workInProgress;\n return (workInProgress.child = current);\n }\n type = current.child;\n if (!checkScheduledUpdateOrContext(current, renderLanes)) {\n var prevProps = type.memoizedProps;\n Component = Component.compare;\n Component = null !== Component ? Component : shallowEqual;\n if (Component(prevProps, nextProps) && current.ref === workInProgress.ref)\n return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n }\n workInProgress.flags |= 1;\n current = createWorkInProgress(type, nextProps);\n current.ref = workInProgress.ref;\n current.return = workInProgress;\n return (workInProgress.child = current);\n}\nfunction updateSimpleMemoComponent(\n current,\n workInProgress,\n Component,\n nextProps,\n renderLanes\n) {\n if (null !== current) {\n var prevProps = current.memoizedProps;\n if (\n shallowEqual(prevProps, nextProps) &&\n current.ref === workInProgress.ref\n )\n if (\n ((didReceiveUpdate = !1),\n (workInProgress.pendingProps = nextProps = prevProps),\n checkScheduledUpdateOrContext(current, renderLanes))\n )\n 0 !== (current.flags & 131072) && (didReceiveUpdate = !0);\n else\n return (\n (workInProgress.lanes = current.lanes),\n bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes)\n );\n }\n return updateFunctionComponent(\n current,\n workInProgress,\n Component,\n nextProps,\n renderLanes\n );\n}\nfunction updateOffscreenComponent(\n current,\n workInProgress,\n renderLanes,\n nextProps\n) {\n var nextChildren = nextProps.children,\n prevState = null !== current ? current.memoizedState : null;\n null === current &&\n null === workInProgress.stateNode &&\n (workInProgress.stateNode = {\n _visibility: 1,\n _pendingMarkers: null,\n _retryCache: null,\n _transitions: null\n });\n if (\"hidden\" === nextProps.mode) {\n if (0 !== (workInProgress.flags & 128)) {\n prevState =\n null !== prevState ? prevState.baseLanes | renderLanes : renderLanes;\n if (null !== current) {\n nextProps = workInProgress.child = current.child;\n for (nextChildren = 0; null !== nextProps; )\n (nextChildren =\n nextChildren | nextProps.lanes | nextProps.childLanes),\n (nextProps = nextProps.sibling);\n nextProps = nextChildren & ~prevState;\n } else (nextProps = 0), (workInProgress.child = null);\n return deferHiddenOffscreenComponent(\n current,\n workInProgress,\n prevState,\n renderLanes,\n nextProps\n );\n }\n if (0 !== (renderLanes & 536870912))\n (workInProgress.memoizedState = { baseLanes: 0, cachePool: null }),\n null !== current &&\n pushTransition(\n workInProgress,\n null !== prevState ? prevState.cachePool : null\n ),\n null !== prevState\n ? pushHiddenContext(workInProgress, prevState)\n : reuseHiddenContextOnStack(),\n pushOffscreenSuspenseHandler(workInProgress);\n else\n return (\n (nextProps = workInProgress.lanes = 536870912),\n deferHiddenOffscreenComponent(\n current,\n workInProgress,\n null !== prevState ? prevState.baseLanes | renderLanes : renderLanes,\n renderLanes,\n nextProps\n )\n );\n } else\n null !== prevState\n ? (pushTransition(workInProgress, prevState.cachePool),\n pushHiddenContext(workInProgress, prevState),\n reuseSuspenseHandlerOnStack(workInProgress),\n (workInProgress.memoizedState = null))\n : (null !== current && pushTransition(workInProgress, null),\n reuseHiddenContextOnStack(),\n reuseSuspenseHandlerOnStack(workInProgress));\n reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n return workInProgress.child;\n}\nfunction bailoutOffscreenComponent(current, workInProgress) {\n (null !== current && 22 === current.tag) ||\n null !== workInProgress.stateNode ||\n (workInProgress.stateNode = {\n _visibility: 1,\n _pendingMarkers: null,\n _retryCache: null,\n _transitions: null\n });\n return workInProgress.sibling;\n}\nfunction deferHiddenOffscreenComponent(\n current,\n workInProgress,\n nextBaseLanes,\n renderLanes,\n remainingChildLanes\n) {\n var JSCompiler_inline_result = peekCacheFromPool();\n JSCompiler_inline_result =\n null === JSCompiler_inline_result\n ? null\n : { parent: CacheContext._currentValue, pool: JSCompiler_inline_result };\n workInProgress.memoizedState = {\n baseLanes: nextBaseLanes,\n cachePool: JSCompiler_inline_result\n };\n null !== current && pushTransition(workInProgress, null);\n reuseHiddenContextOnStack();\n pushOffscreenSuspenseHandler(workInProgress);\n null !== current &&\n propagateParentContextChanges(current, workInProgress, renderLanes, !0);\n workInProgress.childLanes = remainingChildLanes;\n return null;\n}\nfunction mountActivityChildren(workInProgress, nextProps) {\n nextProps = mountWorkInProgressOffscreenFiber(\n { mode: nextProps.mode, children: nextProps.children },\n workInProgress.mode\n );\n nextProps.ref = workInProgress.ref;\n workInProgress.child = nextProps;\n nextProps.return = workInProgress;\n return nextProps;\n}\nfunction retryActivityComponentWithoutHydrating(\n current,\n workInProgress,\n renderLanes\n) {\n reconcileChildFibers(workInProgress, current.child, null, renderLanes);\n current = mountActivityChildren(workInProgress, workInProgress.pendingProps);\n current.flags |= 2;\n popSuspenseHandler(workInProgress);\n workInProgress.memoizedState = null;\n return current;\n}\nfunction updateActivityComponent(current, workInProgress, renderLanes) {\n var nextProps = workInProgress.pendingProps,\n didSuspend = 0 !== (workInProgress.flags & 128);\n workInProgress.flags &= -129;\n if (null === current) {\n if (isHydrating) {\n if (\"hidden\" === nextProps.mode)\n return (\n (current = mountActivityChildren(workInProgress, nextProps)),\n (workInProgress.lanes = 536870912),\n bailoutOffscreenComponent(null, current)\n );\n pushDehydratedActivitySuspenseHandler(workInProgress);\n (current = nextHydratableInstance)\n ? ((current = canHydrateHydrationBoundary(\n current,\n rootOrSingletonContext\n )),\n (current = null !== current && \"&\" === current.data ? current : null),\n null !== current &&\n ((workInProgress.memoizedState = {\n dehydrated: current,\n treeContext:\n null !== treeContextProvider\n ? { id: treeContextId, overflow: treeContextOverflow }\n : null,\n retryLane: 536870912,\n hydrationErrors: null\n }),\n (renderLanes = createFiberFromDehydratedFragment(current)),\n (renderLanes.return = workInProgress),\n (workInProgress.child = renderLanes),\n (hydrationParentFiber = workInProgress),\n (nextHydratableInstance = null)))\n : (current = null);\n if (null === current) throw throwOnHydrationMismatch(workInProgress);\n workInProgress.lanes = 536870912;\n return null;\n }\n return mountActivityChildren(workInProgress, nextProps);\n }\n var prevState = current.memoizedState;\n if (null !== prevState) {\n var dehydrated = prevState.dehydrated;\n pushDehydratedActivitySuspenseHandler(workInProgress);\n if (didSuspend)\n if (workInProgress.flags & 256)\n (workInProgress.flags &= -257),\n (workInProgress = retryActivityComponentWithoutHydrating(\n current,\n workInProgress,\n renderLanes\n ));\n else if (null !== workInProgress.memoizedState)\n (workInProgress.child = current.child),\n (workInProgress.flags |= 128),\n (workInProgress = null);\n else throw Error(formatProdErrorMessage(558));\n else if (\n (didReceiveUpdate ||\n propagateParentContextChanges(current, workInProgress, renderLanes, !1),\n (didSuspend = 0 !== (renderLanes & current.childLanes)),\n didReceiveUpdate || didSuspend)\n ) {\n nextProps = workInProgressRoot;\n if (\n null !== nextProps &&\n ((dehydrated = getBumpedLaneForHydration(nextProps, renderLanes)),\n 0 !== dehydrated && dehydrated !== prevState.retryLane)\n )\n throw (\n ((prevState.retryLane = dehydrated),\n enqueueConcurrentRenderForLane(current, dehydrated),\n scheduleUpdateOnFiber(nextProps, current, dehydrated),\n SelectiveHydrationException)\n );\n renderDidSuspendDelayIfPossible();\n workInProgress = retryActivityComponentWithoutHydrating(\n current,\n workInProgress,\n renderLanes\n );\n } else\n (current = prevState.treeContext),\n (nextHydratableInstance = getNextHydratable(dehydrated.nextSibling)),\n (hydrationParentFiber = workInProgress),\n (isHydrating = !0),\n (hydrationErrors = null),\n (rootOrSingletonContext = !1),\n null !== current &&\n restoreSuspendedTreeContext(workInProgress, current),\n (workInProgress = mountActivityChildren(workInProgress, nextProps)),\n (workInProgress.flags |= 4096);\n return workInProgress;\n }\n current = createWorkInProgress(current.child, {\n mode: nextProps.mode,\n children: nextProps.children\n });\n current.ref = workInProgress.ref;\n workInProgress.child = current;\n current.return = workInProgress;\n return current;\n}\nfunction markRef(current, workInProgress) {\n var ref = workInProgress.ref;\n if (null === ref)\n null !== current &&\n null !== current.ref &&\n (workInProgress.flags |= 4194816);\n else {\n if (\"function\" !== typeof ref && \"object\" !== typeof ref)\n throw Error(formatProdErrorMessage(284));\n if (null === current || current.ref !== ref)\n workInProgress.flags |= 4194816;\n }\n}\nfunction updateFunctionComponent(\n current,\n workInProgress,\n Component,\n nextProps,\n renderLanes\n) {\n prepareToReadContext(workInProgress);\n Component = renderWithHooks(\n current,\n workInProgress,\n Component,\n nextProps,\n void 0,\n renderLanes\n );\n nextProps = checkDidRenderIdHook();\n if (null !== current && !didReceiveUpdate)\n return (\n bailoutHooks(current, workInProgress, renderLanes),\n bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes)\n );\n isHydrating && nextProps && pushMaterializedTreeId(workInProgress);\n workInProgress.flags |= 1;\n reconcileChildren(current, workInProgress, Component, renderLanes);\n return workInProgress.child;\n}\nfunction replayFunctionComponent(\n current,\n workInProgress,\n nextProps,\n Component,\n secondArg,\n renderLanes\n) {\n prepareToReadContext(workInProgress);\n workInProgress.updateQueue = null;\n nextProps = renderWithHooksAgain(\n workInProgress,\n Component,\n nextProps,\n secondArg\n );\n finishRenderingHooks(current);\n Component = checkDidRenderIdHook();\n if (null !== current && !didReceiveUpdate)\n return (\n bailoutHooks(current, workInProgress, renderLanes),\n bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes)\n );\n isHydrating && Component && pushMaterializedTreeId(workInProgress);\n workInProgress.flags |= 1;\n reconcileChildren(current, workInProgress, nextProps, renderLanes);\n return workInProgress.child;\n}\nfunction updateClassComponent(\n current,\n workInProgress,\n Component,\n nextProps,\n renderLanes\n) {\n prepareToReadContext(workInProgress);\n if (null === workInProgress.stateNode) {\n var context = emptyContextObject,\n contextType = Component.contextType;\n \"object\" === typeof contextType &&\n null !== contextType &&\n (context = readContext(contextType));\n context = new Component(nextProps, context);\n workInProgress.memoizedState =\n null !== context.state && void 0 !== context.state ? context.state : null;\n context.updater = classComponentUpdater;\n workInProgress.stateNode = context;\n context._reactInternals = workInProgress;\n context = workInProgress.stateNode;\n context.props = nextProps;\n context.state = workInProgress.memoizedState;\n context.refs = {};\n initializeUpdateQueue(workInProgress);\n contextType = Component.contextType;\n context.context =\n \"object\" === typeof contextType && null !== contextType\n ? readContext(contextType)\n : emptyContextObject;\n context.state = workInProgress.memoizedState;\n contextType = Component.getDerivedStateFromProps;\n \"function\" === typeof contextType &&\n (applyDerivedStateFromProps(\n workInProgress,\n Component,\n contextType,\n nextProps\n ),\n (context.state = workInProgress.memoizedState));\n \"function\" === typeof Component.getDerivedStateFromProps ||\n \"function\" === typeof context.getSnapshotBeforeUpdate ||\n (\"function\" !== typeof context.UNSAFE_componentWillMount &&\n \"function\" !== typeof context.componentWillMount) ||\n ((contextType = context.state),\n \"function\" === typeof context.componentWillMount &&\n context.componentWillMount(),\n \"function\" === typeof context.UNSAFE_componentWillMount &&\n context.UNSAFE_componentWillMount(),\n contextType !== context.state &&\n classComponentUpdater.enqueueReplaceState(context, context.state, null),\n processUpdateQueue(workInProgress, nextProps, context, renderLanes),\n suspendIfUpdateReadFromEntangledAsyncAction(),\n (context.state = workInProgress.memoizedState));\n \"function\" === typeof context.componentDidMount &&\n (workInProgress.flags |= 4194308);\n nextProps = !0;\n } else if (null === current) {\n context = workInProgress.stateNode;\n var unresolvedOldProps = workInProgress.memoizedProps,\n oldProps = resolveClassComponentProps(Component, unresolvedOldProps);\n context.props = oldProps;\n var oldContext = context.context,\n contextType$jscomp$0 = Component.contextType;\n contextType = emptyContextObject;\n \"object\" === typeof contextType$jscomp$0 &&\n null !== contextType$jscomp$0 &&\n (contextType = readContext(contextType$jscomp$0));\n var getDerivedStateFromProps = Component.getDerivedStateFromProps;\n contextType$jscomp$0 =\n \"function\" === typeof getDerivedStateFromProps ||\n \"function\" === typeof context.getSnapshotBeforeUpdate;\n unresolvedOldProps = workInProgress.pendingProps !== unresolvedOldProps;\n contextType$jscomp$0 ||\n (\"function\" !== typeof context.UNSAFE_componentWillReceiveProps &&\n \"function\" !== typeof context.componentWillReceiveProps) ||\n ((unresolvedOldProps || oldContext !== contextType) &&\n callComponentWillReceiveProps(\n workInProgress,\n context,\n nextProps,\n contextType\n ));\n hasForceUpdate = !1;\n var oldState = workInProgress.memoizedState;\n context.state = oldState;\n processUpdateQueue(workInProgress, nextProps, context, renderLanes);\n suspendIfUpdateReadFromEntangledAsyncAction();\n oldContext = workInProgress.memoizedState;\n unresolvedOldProps || oldState !== oldContext || hasForceUpdate\n ? (\"function\" === typeof getDerivedStateFromProps &&\n (applyDerivedStateFromProps(\n workInProgress,\n Component,\n getDerivedStateFromProps,\n nextProps\n ),\n (oldContext = workInProgress.memoizedState)),\n (oldProps =\n hasForceUpdate ||\n checkShouldComponentUpdate(\n workInProgress,\n Component,\n oldProps,\n nextProps,\n oldState,\n oldContext,\n contextType\n ))\n ? (contextType$jscomp$0 ||\n (\"function\" !== typeof context.UNSAFE_componentWillMount &&\n \"function\" !== typeof context.componentWillMount) ||\n (\"function\" === typeof context.componentWillMount &&\n context.componentWillMount(),\n \"function\" === typeof context.UNSAFE_componentWillMount &&\n context.UNSAFE_componentWillMount()),\n \"function\" === typeof context.componentDidMount &&\n (workInProgress.flags |= 4194308))\n : (\"function\" === typeof context.componentDidMount &&\n (workInProgress.flags |= 4194308),\n (workInProgress.memoizedProps = nextProps),\n (workInProgress.memoizedState = oldContext)),\n (context.props = nextProps),\n (context.state = oldContext),\n (context.context = contextType),\n (nextProps = oldProps))\n : (\"function\" === typeof context.componentDidMount &&\n (workInProgress.flags |= 4194308),\n (nextProps = !1));\n } else {\n context = workInProgress.stateNode;\n cloneUpdateQueue(current, workInProgress);\n contextType = workInProgress.memoizedProps;\n contextType$jscomp$0 = resolveClassComponentProps(Component, contextType);\n context.props = contextType$jscomp$0;\n getDerivedStateFromProps = workInProgress.pendingProps;\n oldState = context.context;\n oldContext = Component.contextType;\n oldProps = emptyContextObject;\n \"object\" === typeof oldContext &&\n null !== oldContext &&\n (oldProps = readContext(oldContext));\n unresolvedOldProps = Component.getDerivedStateFromProps;\n (oldContext =\n \"function\" === typeof unresolvedOldProps ||\n \"function\" === typeof context.getSnapshotBeforeUpdate) ||\n (\"function\" !== typeof context.UNSAFE_componentWillReceiveProps &&\n \"function\" !== typeof context.componentWillReceiveProps) ||\n ((contextType !== getDerivedStateFromProps || oldState !== oldProps) &&\n callComponentWillReceiveProps(\n workInProgress,\n context,\n nextProps,\n oldProps\n ));\n hasForceUpdate = !1;\n oldState = workInProgress.memoizedState;\n context.state = oldState;\n processUpdateQueue(workInProgress, nextProps, context, renderLanes);\n suspendIfUpdateReadFromEntangledAsyncAction();\n var newState = workInProgress.memoizedState;\n contextType !== getDerivedStateFromProps ||\n oldState !== newState ||\n hasForceUpdate ||\n (null !== current &&\n null !== current.dependencies &&\n checkIfContextChanged(current.dependencies))\n ? (\"function\" === typeof unresolvedOldProps &&\n (applyDerivedStateFromProps(\n workInProgress,\n Component,\n unresolvedOldProps,\n nextProps\n ),\n (newState = workInProgress.memoizedState)),\n (contextType$jscomp$0 =\n hasForceUpdate ||\n checkShouldComponentUpdate(\n workInProgress,\n Component,\n contextType$jscomp$0,\n nextProps,\n oldState,\n newState,\n oldProps\n ) ||\n (null !== current &&\n null !== current.dependencies &&\n checkIfContextChanged(current.dependencies)))\n ? (oldContext ||\n (\"function\" !== typeof context.UNSAFE_componentWillUpdate &&\n \"function\" !== typeof context.componentWillUpdate) ||\n (\"function\" === typeof context.componentWillUpdate &&\n context.componentWillUpdate(nextProps, newState, oldProps),\n \"function\" === typeof context.UNSAFE_componentWillUpdate &&\n context.UNSAFE_componentWillUpdate(\n nextProps,\n newState,\n oldProps\n )),\n \"function\" === typeof context.componentDidUpdate &&\n (workInProgress.flags |= 4),\n \"function\" === typeof context.getSnapshotBeforeUpdate &&\n (workInProgress.flags |= 1024))\n : (\"function\" !== typeof context.componentDidUpdate ||\n (contextType === current.memoizedProps &&\n oldState === current.memoizedState) ||\n (workInProgress.flags |= 4),\n \"function\" !== typeof context.getSnapshotBeforeUpdate ||\n (contextType === current.memoizedProps &&\n oldState === current.memoizedState) ||\n (workInProgress.flags |= 1024),\n (workInProgress.memoizedProps = nextProps),\n (workInProgress.memoizedState = newState)),\n (context.props = nextProps),\n (context.state = newState),\n (context.context = oldProps),\n (nextProps = contextType$jscomp$0))\n : (\"function\" !== typeof context.componentDidUpdate ||\n (contextType === current.memoizedProps &&\n oldState === current.memoizedState) ||\n (workInProgress.flags |= 4),\n \"function\" !== typeof context.getSnapshotBeforeUpdate ||\n (contextType === current.memoizedProps &&\n oldState === current.memoizedState) ||\n (workInProgress.flags |= 1024),\n (nextProps = !1));\n }\n context = nextProps;\n markRef(current, workInProgress);\n nextProps = 0 !== (workInProgress.flags & 128);\n context || nextProps\n ? ((context = workInProgress.stateNode),\n (Component =\n nextProps && \"function\" !== typeof Component.getDerivedStateFromError\n ? null\n : context.render()),\n (workInProgress.flags |= 1),\n null !== current && nextProps\n ? ((workInProgress.child = reconcileChildFibers(\n workInProgress,\n current.child,\n null,\n renderLanes\n )),\n (workInProgress.child = reconcileChildFibers(\n workInProgress,\n null,\n Component,\n renderLanes\n )))\n : reconcileChildren(current, workInProgress, Component, renderLanes),\n (workInProgress.memoizedState = context.state),\n (current = workInProgress.child))\n : (current = bailoutOnAlreadyFinishedWork(\n current,\n workInProgress,\n renderLanes\n ));\n return current;\n}\nfunction mountHostRootWithoutHydrating(\n current,\n workInProgress,\n nextChildren,\n renderLanes\n) {\n resetHydrationState();\n workInProgress.flags |= 256;\n reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n return workInProgress.child;\n}\nvar SUSPENDED_MARKER = {\n dehydrated: null,\n treeContext: null,\n retryLane: 0,\n hydrationErrors: null\n};\nfunction mountSuspenseOffscreenState(renderLanes) {\n return { baseLanes: renderLanes, cachePool: getSuspendedCache() };\n}\nfunction getRemainingWorkInPrimaryTree(\n current,\n primaryTreeDidDefer,\n renderLanes\n) {\n current = null !== current ? current.childLanes & ~renderLanes : 0;\n primaryTreeDidDefer && (current |= workInProgressDeferredLane);\n return current;\n}\nfunction updateSuspenseComponent(current, workInProgress, renderLanes) {\n var nextProps = workInProgress.pendingProps,\n showFallback = !1,\n didSuspend = 0 !== (workInProgress.flags & 128),\n JSCompiler_temp;\n (JSCompiler_temp = didSuspend) ||\n (JSCompiler_temp =\n null !== current && null === current.memoizedState\n ? !1\n : 0 !== (suspenseStackCursor.current & 2));\n JSCompiler_temp && ((showFallback = !0), (workInProgress.flags &= -129));\n JSCompiler_temp = 0 !== (workInProgress.flags & 32);\n workInProgress.flags &= -33;\n if (null === current) {\n if (isHydrating) {\n showFallback\n ? pushPrimaryTreeSuspenseHandler(workInProgress)\n : reuseSuspenseHandlerOnStack(workInProgress);\n (current = nextHydratableInstance)\n ? ((current = canHydrateHydrationBoundary(\n current,\n rootOrSingletonContext\n )),\n (current = null !== current && \"&\" !== current.data ? current : null),\n null !== current &&\n ((workInProgress.memoizedState = {\n dehydrated: current,\n treeContext:\n null !== treeContextProvider\n ? { id: treeContextId, overflow: treeContextOverflow }\n : null,\n retryLane: 536870912,\n hydrationErrors: null\n }),\n (renderLanes = createFiberFromDehydratedFragment(current)),\n (renderLanes.return = workInProgress),\n (workInProgress.child = renderLanes),\n (hydrationParentFiber = workInProgress),\n (nextHydratableInstance = null)))\n : (current = null);\n if (null === current) throw throwOnHydrationMismatch(workInProgress);\n isSuspenseInstanceFallback(current)\n ? (workInProgress.lanes = 32)\n : (workInProgress.lanes = 536870912);\n return null;\n }\n var nextPrimaryChildren = nextProps.children;\n nextProps = nextProps.fallback;\n if (showFallback)\n return (\n reuseSuspenseHandlerOnStack(workInProgress),\n (showFallback = workInProgress.mode),\n (nextPrimaryChildren = mountWorkInProgressOffscreenFiber(\n { mode: \"hidden\", children: nextPrimaryChildren },\n showFallback\n )),\n (nextProps = createFiberFromFragment(\n nextProps,\n showFallback,\n renderLanes,\n null\n )),\n (nextPrimaryChildren.return = workInProgress),\n (nextProps.return = workInProgress),\n (nextPrimaryChildren.sibling = nextProps),\n (workInProgress.child = nextPrimaryChildren),\n (nextProps = workInProgress.child),\n (nextProps.memoizedState = mountSuspenseOffscreenState(renderLanes)),\n (nextProps.childLanes = getRemainingWorkInPrimaryTree(\n current,\n JSCompiler_temp,\n renderLanes\n )),\n (workInProgress.memoizedState = SUSPENDED_MARKER),\n bailoutOffscreenComponent(null, nextProps)\n );\n pushPrimaryTreeSuspenseHandler(workInProgress);\n return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren);\n }\n var prevState = current.memoizedState;\n if (\n null !== prevState &&\n ((nextPrimaryChildren = prevState.dehydrated), null !== nextPrimaryChildren)\n ) {\n if (didSuspend)\n workInProgress.flags & 256\n ? (pushPrimaryTreeSuspenseHandler(workInProgress),\n (workInProgress.flags &= -257),\n (workInProgress = retrySuspenseComponentWithoutHydrating(\n current,\n workInProgress,\n renderLanes\n )))\n : null !== workInProgress.memoizedState\n ? (reuseSuspenseHandlerOnStack(workInProgress),\n (workInProgress.child = current.child),\n (workInProgress.flags |= 128),\n (workInProgress = null))\n : (reuseSuspenseHandlerOnStack(workInProgress),\n (nextPrimaryChildren = nextProps.fallback),\n (showFallback = workInProgress.mode),\n (nextProps = mountWorkInProgressOffscreenFiber(\n { mode: \"visible\", children: nextProps.children },\n showFallback\n )),\n (nextPrimaryChildren = createFiberFromFragment(\n nextPrimaryChildren,\n showFallback,\n renderLanes,\n null\n )),\n (nextPrimaryChildren.flags |= 2),\n (nextProps.return = workInProgress),\n (nextPrimaryChildren.return = workInProgress),\n (nextProps.sibling = nextPrimaryChildren),\n (workInProgress.child = nextProps),\n reconcileChildFibers(\n workInProgress,\n current.child,\n null,\n renderLanes\n ),\n (nextProps = workInProgress.child),\n (nextProps.memoizedState =\n mountSuspenseOffscreenState(renderLanes)),\n (nextProps.childLanes = getRemainingWorkInPrimaryTree(\n current,\n JSCompiler_temp,\n renderLanes\n )),\n (workInProgress.memoizedState = SUSPENDED_MARKER),\n (workInProgress = bailoutOffscreenComponent(null, nextProps)));\n else if (\n (pushPrimaryTreeSuspenseHandler(workInProgress),\n isSuspenseInstanceFallback(nextPrimaryChildren))\n ) {\n JSCompiler_temp =\n nextPrimaryChildren.nextSibling &&\n nextPrimaryChildren.nextSibling.dataset;\n if (JSCompiler_temp) var digest = JSCompiler_temp.dgst;\n JSCompiler_temp = digest;\n nextProps = Error(formatProdErrorMessage(419));\n nextProps.stack = \"\";\n nextProps.digest = JSCompiler_temp;\n queueHydrationError({ value: nextProps, source: null, stack: null });\n workInProgress = retrySuspenseComponentWithoutHydrating(\n current,\n workInProgress,\n renderLanes\n );\n } else if (\n (didReceiveUpdate ||\n propagateParentContextChanges(current, workInProgress, renderLanes, !1),\n (JSCompiler_temp = 0 !== (renderLanes & current.childLanes)),\n didReceiveUpdate || JSCompiler_temp)\n ) {\n JSCompiler_temp = workInProgressRoot;\n if (\n null !== JSCompiler_temp &&\n ((nextProps = getBumpedLaneForHydration(JSCompiler_temp, renderLanes)),\n 0 !== nextProps && nextProps !== prevState.retryLane)\n )\n throw (\n ((prevState.retryLane = nextProps),\n enqueueConcurrentRenderForLane(current, nextProps),\n scheduleUpdateOnFiber(JSCompiler_temp, current, nextProps),\n SelectiveHydrationException)\n );\n isSuspenseInstancePending(nextPrimaryChildren) ||\n renderDidSuspendDelayIfPossible();\n workInProgress = retrySuspenseComponentWithoutHydrating(\n current,\n workInProgress,\n renderLanes\n );\n } else\n isSuspenseInstancePending(nextPrimaryChildren)\n ? ((workInProgress.flags |= 192),\n (workInProgress.child = current.child),\n (workInProgress = null))\n : ((current = prevState.treeContext),\n (nextHydratableInstance = getNextHydratable(\n nextPrimaryChildren.nextSibling\n )),\n (hydrationParentFiber = workInProgress),\n (isHydrating = !0),\n (hydrationErrors = null),\n (rootOrSingletonContext = !1),\n null !== current &&\n restoreSuspendedTreeContext(workInProgress, current),\n (workInProgress = mountSuspensePrimaryChildren(\n workInProgress,\n nextProps.children\n )),\n (workInProgress.flags |= 4096));\n return workInProgress;\n }\n if (showFallback)\n return (\n reuseSuspenseHandlerOnStack(workInProgress),\n (nextPrimaryChildren = nextProps.fallback),\n (showFallback = workInProgress.mode),\n (prevState = current.child),\n (digest = prevState.sibling),\n (nextProps = createWorkInProgress(prevState, {\n mode: \"hidden\",\n children: nextProps.children\n })),\n (nextProps.subtreeFlags = prevState.subtreeFlags & 65011712),\n null !== digest\n ? (nextPrimaryChildren = createWorkInProgress(\n digest,\n nextPrimaryChildren\n ))\n : ((nextPrimaryChildren = createFiberFromFragment(\n nextPrimaryChildren,\n showFallback,\n renderLanes,\n null\n )),\n (nextPrimaryChildren.flags |= 2)),\n (nextPrimaryChildren.return = workInProgress),\n (nextProps.return = workInProgress),\n (nextProps.sibling = nextPrimaryChildren),\n (workInProgress.child = nextProps),\n bailoutOffscreenComponent(null, nextProps),\n (nextProps = workInProgress.child),\n (nextPrimaryChildren = current.child.memoizedState),\n null === nextPrimaryChildren\n ? (nextPrimaryChildren = mountSuspenseOffscreenState(renderLanes))\n : ((showFallback = nextPrimaryChildren.cachePool),\n null !== showFallback\n ? ((prevState = CacheContext._currentValue),\n (showFallback =\n showFallback.parent !== prevState\n ? { parent: prevState, pool: prevState }\n : showFallback))\n : (showFallback = getSuspendedCache()),\n (nextPrimaryChildren = {\n baseLanes: nextPrimaryChildren.baseLanes | renderLanes,\n cachePool: showFallback\n })),\n (nextProps.memoizedState = nextPrimaryChildren),\n (nextProps.childLanes = getRemainingWorkInPrimaryTree(\n current,\n JSCompiler_temp,\n renderLanes\n )),\n (workInProgress.memoizedState = SUSPENDED_MARKER),\n bailoutOffscreenComponent(current.child, nextProps)\n );\n pushPrimaryTreeSuspenseHandler(workInProgress);\n renderLanes = current.child;\n current = renderLanes.sibling;\n renderLanes = createWorkInProgress(renderLanes, {\n mode: \"visible\",\n children: nextProps.children\n });\n renderLanes.return = workInProgress;\n renderLanes.sibling = null;\n null !== current &&\n ((JSCompiler_temp = workInProgress.deletions),\n null === JSCompiler_temp\n ? ((workInProgress.deletions = [current]), (workInProgress.flags |= 16))\n : JSCompiler_temp.push(current));\n workInProgress.child = renderLanes;\n workInProgress.memoizedState = null;\n return renderLanes;\n}\nfunction mountSuspensePrimaryChildren(workInProgress, primaryChildren) {\n primaryChildren = mountWorkInProgressOffscreenFiber(\n { mode: \"visible\", children: primaryChildren },\n workInProgress.mode\n );\n primaryChildren.return = workInProgress;\n return (workInProgress.child = primaryChildren);\n}\nfunction mountWorkInProgressOffscreenFiber(offscreenProps, mode) {\n offscreenProps = createFiberImplClass(22, offscreenProps, null, mode);\n offscreenProps.lanes = 0;\n return offscreenProps;\n}\nfunction retrySuspenseComponentWithoutHydrating(\n current,\n workInProgress,\n renderLanes\n) {\n reconcileChildFibers(workInProgress, current.child, null, renderLanes);\n current = mountSuspensePrimaryChildren(\n workInProgress,\n workInProgress.pendingProps.children\n );\n current.flags |= 2;\n workInProgress.memoizedState = null;\n return current;\n}\nfunction scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) {\n fiber.lanes |= renderLanes;\n var alternate = fiber.alternate;\n null !== alternate && (alternate.lanes |= renderLanes);\n scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot);\n}\nfunction initSuspenseListRenderState(\n workInProgress,\n isBackwards,\n tail,\n lastContentRow,\n tailMode,\n treeForkCount\n) {\n var renderState = workInProgress.memoizedState;\n null === renderState\n ? (workInProgress.memoizedState = {\n isBackwards: isBackwards,\n rendering: null,\n renderingStartTime: 0,\n last: lastContentRow,\n tail: tail,\n tailMode: tailMode,\n treeForkCount: treeForkCount\n })\n : ((renderState.isBackwards = isBackwards),\n (renderState.rendering = null),\n (renderState.renderingStartTime = 0),\n (renderState.last = lastContentRow),\n (renderState.tail = tail),\n (renderState.tailMode = tailMode),\n (renderState.treeForkCount = treeForkCount));\n}\nfunction updateSuspenseListComponent(current, workInProgress, renderLanes) {\n var nextProps = workInProgress.pendingProps,\n revealOrder = nextProps.revealOrder,\n tailMode = nextProps.tail;\n nextProps = nextProps.children;\n var suspenseContext = suspenseStackCursor.current,\n shouldForceFallback = 0 !== (suspenseContext & 2);\n shouldForceFallback\n ? ((suspenseContext = (suspenseContext & 1) | 2),\n (workInProgress.flags |= 128))\n : (suspenseContext &= 1);\n push(suspenseStackCursor, suspenseContext);\n reconcileChildren(current, workInProgress, nextProps, renderLanes);\n nextProps = isHydrating ? treeForkCount : 0;\n if (!shouldForceFallback && null !== current && 0 !== (current.flags & 128))\n a: for (current = workInProgress.child; null !== current; ) {\n if (13 === current.tag)\n null !== current.memoizedState &&\n scheduleSuspenseWorkOnFiber(current, renderLanes, workInProgress);\n else if (19 === current.tag)\n scheduleSuspenseWorkOnFiber(current, renderLanes, workInProgress);\n else if (null !== current.child) {\n current.child.return = current;\n current = current.child;\n continue;\n }\n if (current === workInProgress) break a;\n for (; null === current.sibling; ) {\n if (null === current.return || current.return === workInProgress)\n break a;\n current = current.return;\n }\n current.sibling.return = current.return;\n current = current.sibling;\n }\n switch (revealOrder) {\n case \"forwards\":\n renderLanes = workInProgress.child;\n for (revealOrder = null; null !== renderLanes; )\n (current = renderLanes.alternate),\n null !== current &&\n null === findFirstSuspended(current) &&\n (revealOrder = renderLanes),\n (renderLanes = renderLanes.sibling);\n renderLanes = revealOrder;\n null === renderLanes\n ? ((revealOrder = workInProgress.child), (workInProgress.child = null))\n : ((revealOrder = renderLanes.sibling), (renderLanes.sibling = null));\n initSuspenseListRenderState(\n workInProgress,\n !1,\n revealOrder,\n renderLanes,\n tailMode,\n nextProps\n );\n break;\n case \"backwards\":\n case \"unstable_legacy-backwards\":\n renderLanes = null;\n revealOrder = workInProgress.child;\n for (workInProgress.child = null; null !== revealOrder; ) {\n current = revealOrder.alternate;\n if (null !== current && null === findFirstSuspended(current)) {\n workInProgress.child = revealOrder;\n break;\n }\n current = revealOrder.sibling;\n revealOrder.sibling = renderLanes;\n renderLanes = revealOrder;\n revealOrder = current;\n }\n initSuspenseListRenderState(\n workInProgress,\n !0,\n renderLanes,\n null,\n tailMode,\n nextProps\n );\n break;\n case \"together\":\n initSuspenseListRenderState(\n workInProgress,\n !1,\n null,\n null,\n void 0,\n nextProps\n );\n break;\n default:\n workInProgress.memoizedState = null;\n }\n return workInProgress.child;\n}\nfunction bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) {\n null !== current && (workInProgress.dependencies = current.dependencies);\n workInProgressRootSkippedLanes |= workInProgress.lanes;\n if (0 === (renderLanes & workInProgress.childLanes))\n if (null !== current) {\n if (\n (propagateParentContextChanges(\n current,\n workInProgress,\n renderLanes,\n !1\n ),\n 0 === (renderLanes & workInProgress.childLanes))\n )\n return null;\n } else return null;\n if (null !== current && workInProgress.child !== current.child)\n throw Error(formatProdErrorMessage(153));\n if (null !== workInProgress.child) {\n current = workInProgress.child;\n renderLanes = createWorkInProgress(current, current.pendingProps);\n workInProgress.child = renderLanes;\n for (renderLanes.return = workInProgress; null !== current.sibling; )\n (current = current.sibling),\n (renderLanes = renderLanes.sibling =\n createWorkInProgress(current, current.pendingProps)),\n (renderLanes.return = workInProgress);\n renderLanes.sibling = null;\n }\n return workInProgress.child;\n}\nfunction checkScheduledUpdateOrContext(current, renderLanes) {\n if (0 !== (current.lanes & renderLanes)) return !0;\n current = current.dependencies;\n return null !== current && checkIfContextChanged(current) ? !0 : !1;\n}\nfunction attemptEarlyBailoutIfNoScheduledUpdate(\n current,\n workInProgress,\n renderLanes\n) {\n switch (workInProgress.tag) {\n case 3:\n pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);\n pushProvider(workInProgress, CacheContext, current.memoizedState.cache);\n resetHydrationState();\n break;\n case 27:\n case 5:\n pushHostContext(workInProgress);\n break;\n case 4:\n pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);\n break;\n case 10:\n pushProvider(\n workInProgress,\n workInProgress.type,\n workInProgress.memoizedProps.value\n );\n break;\n case 31:\n if (null !== workInProgress.memoizedState)\n return (\n (workInProgress.flags |= 128),\n pushDehydratedActivitySuspenseHandler(workInProgress),\n null\n );\n break;\n case 13:\n var state$102 = workInProgress.memoizedState;\n if (null !== state$102) {\n if (null !== state$102.dehydrated)\n return (\n pushPrimaryTreeSuspenseHandler(workInProgress),\n (workInProgress.flags |= 128),\n null\n );\n if (0 !== (renderLanes & workInProgress.child.childLanes))\n return updateSuspenseComponent(current, workInProgress, renderLanes);\n pushPrimaryTreeSuspenseHandler(workInProgress);\n current = bailoutOnAlreadyFinishedWork(\n current,\n workInProgress,\n renderLanes\n );\n return null !== current ? current.sibling : null;\n }\n pushPrimaryTreeSuspenseHandler(workInProgress);\n break;\n case 19:\n var didSuspendBefore = 0 !== (current.flags & 128);\n state$102 = 0 !== (renderLanes & workInProgress.childLanes);\n state$102 ||\n (propagateParentContextChanges(\n current,\n workInProgress,\n renderLanes,\n !1\n ),\n (state$102 = 0 !== (renderLanes & workInProgress.childLanes)));\n if (didSuspendBefore) {\n if (state$102)\n return updateSuspenseListComponent(\n current,\n workInProgress,\n renderLanes\n );\n workInProgress.flags |= 128;\n }\n didSuspendBefore = workInProgress.memoizedState;\n null !== didSuspendBefore &&\n ((didSuspendBefore.rendering = null),\n (didSuspendBefore.tail = null),\n (didSuspendBefore.lastEffect = null));\n push(suspenseStackCursor, suspenseStackCursor.current);\n if (state$102) break;\n else return null;\n case 22:\n return (\n (workInProgress.lanes = 0),\n updateOffscreenComponent(\n current,\n workInProgress,\n renderLanes,\n workInProgress.pendingProps\n )\n );\n case 24:\n pushProvider(workInProgress, CacheContext, current.memoizedState.cache);\n }\n return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n}\nfunction beginWork(current, workInProgress, renderLanes) {\n if (null !== current)\n if (current.memoizedProps !== workInProgress.pendingProps)\n didReceiveUpdate = !0;\n else {\n if (\n !checkScheduledUpdateOrContext(current, renderLanes) &&\n 0 === (workInProgress.flags & 128)\n )\n return (\n (didReceiveUpdate = !1),\n attemptEarlyBailoutIfNoScheduledUpdate(\n current,\n workInProgress,\n renderLanes\n )\n );\n didReceiveUpdate = 0 !== (current.flags & 131072) ? !0 : !1;\n }\n else\n (didReceiveUpdate = !1),\n isHydrating &&\n 0 !== (workInProgress.flags & 1048576) &&\n pushTreeId(workInProgress, treeForkCount, workInProgress.index);\n workInProgress.lanes = 0;\n switch (workInProgress.tag) {\n case 16:\n a: {\n var props = workInProgress.pendingProps;\n current = resolveLazy(workInProgress.elementType);\n workInProgress.type = current;\n if (\"function\" === typeof current)\n shouldConstruct(current)\n ? ((props = resolveClassComponentProps(current, props)),\n (workInProgress.tag = 1),\n (workInProgress = updateClassComponent(\n null,\n workInProgress,\n current,\n props,\n renderLanes\n )))\n : ((workInProgress.tag = 0),\n (workInProgress = updateFunctionComponent(\n null,\n workInProgress,\n current,\n props,\n renderLanes\n )));\n else {\n if (void 0 !== current && null !== current) {\n var $$typeof = current.$$typeof;\n if ($$typeof === REACT_FORWARD_REF_TYPE) {\n workInProgress.tag = 11;\n workInProgress = updateForwardRef(\n null,\n workInProgress,\n current,\n props,\n renderLanes\n );\n break a;\n } else if ($$typeof === REACT_MEMO_TYPE) {\n workInProgress.tag = 14;\n workInProgress = updateMemoComponent(\n null,\n workInProgress,\n current,\n props,\n renderLanes\n );\n break a;\n }\n }\n workInProgress = getComponentNameFromType(current) || current;\n throw Error(formatProdErrorMessage(306, workInProgress, \"\"));\n }\n }\n return workInProgress;\n case 0:\n return updateFunctionComponent(\n current,\n workInProgress,\n workInProgress.type,\n workInProgress.pendingProps,\n renderLanes\n );\n case 1:\n return (\n (props = workInProgress.type),\n ($$typeof = resolveClassComponentProps(\n props,\n workInProgress.pendingProps\n )),\n updateClassComponent(\n current,\n workInProgress,\n props,\n $$typeof,\n renderLanes\n )\n );\n case 3:\n a: {\n pushHostContainer(\n workInProgress,\n workInProgress.stateNode.containerInfo\n );\n if (null === current) throw Error(formatProdErrorMessage(387));\n props = workInProgress.pendingProps;\n var prevState = workInProgress.memoizedState;\n $$typeof = prevState.element;\n cloneUpdateQueue(current, workInProgress);\n processUpdateQueue(workInProgress, props, null, renderLanes);\n var nextState = workInProgress.memoizedState;\n props = nextState.cache;\n pushProvider(workInProgress, CacheContext, props);\n props !== prevState.cache &&\n propagateContextChanges(\n workInProgress,\n [CacheContext],\n renderLanes,\n !0\n );\n suspendIfUpdateReadFromEntangledAsyncAction();\n props = nextState.element;\n if (prevState.isDehydrated)\n if (\n ((prevState = {\n element: props,\n isDehydrated: !1,\n cache: nextState.cache\n }),\n (workInProgress.updateQueue.baseState = prevState),\n (workInProgress.memoizedState = prevState),\n workInProgress.flags & 256)\n ) {\n workInProgress = mountHostRootWithoutHydrating(\n current,\n workInProgress,\n props,\n renderLanes\n );\n break a;\n } else if (props !== $$typeof) {\n $$typeof = createCapturedValueAtFiber(\n Error(formatProdErrorMessage(424)),\n workInProgress\n );\n queueHydrationError($$typeof);\n workInProgress = mountHostRootWithoutHydrating(\n current,\n workInProgress,\n props,\n renderLanes\n );\n break a;\n } else {\n current = workInProgress.stateNode.containerInfo;\n switch (current.nodeType) {\n case 9:\n current = current.body;\n break;\n default:\n current =\n \"HTML\" === current.nodeName\n ? current.ownerDocument.body\n : current;\n }\n nextHydratableInstance = getNextHydratable(current.firstChild);\n hydrationParentFiber = workInProgress;\n isHydrating = !0;\n hydrationErrors = null;\n rootOrSingletonContext = !0;\n renderLanes = mountChildFibers(\n workInProgress,\n null,\n props,\n renderLanes\n );\n for (workInProgress.child = renderLanes; renderLanes; )\n (renderLanes.flags = (renderLanes.flags & -3) | 4096),\n (renderLanes = renderLanes.sibling);\n }\n else {\n resetHydrationState();\n if (props === $$typeof) {\n workInProgress = bailoutOnAlreadyFinishedWork(\n current,\n workInProgress,\n renderLanes\n );\n break a;\n }\n reconcileChildren(current, workInProgress, props, renderLanes);\n }\n workInProgress = workInProgress.child;\n }\n return workInProgress;\n case 26:\n return (\n markRef(current, workInProgress),\n null === current\n ? (renderLanes = getResource(\n workInProgress.type,\n null,\n workInProgress.pendingProps,\n null\n ))\n ? (workInProgress.memoizedState = renderLanes)\n : isHydrating ||\n ((renderLanes = workInProgress.type),\n (current = workInProgress.pendingProps),\n (props = getOwnerDocumentFromRootContainer(\n rootInstanceStackCursor.current\n ).createElement(renderLanes)),\n (props[internalInstanceKey] = workInProgress),\n (props[internalPropsKey] = current),\n setInitialProperties(props, renderLanes, current),\n markNodeAsHoistable(props),\n (workInProgress.stateNode = props))\n : (workInProgress.memoizedState = getResource(\n workInProgress.type,\n current.memoizedProps,\n workInProgress.pendingProps,\n current.memoizedState\n )),\n null\n );\n case 27:\n return (\n pushHostContext(workInProgress),\n null === current &&\n isHydrating &&\n ((props = workInProgress.stateNode =\n resolveSingletonInstance(\n workInProgress.type,\n workInProgress.pendingProps,\n rootInstanceStackCursor.current\n )),\n (hydrationParentFiber = workInProgress),\n (rootOrSingletonContext = !0),\n ($$typeof = nextHydratableInstance),\n isSingletonScope(workInProgress.type)\n ? ((previousHydratableOnEnteringScopedSingleton = $$typeof),\n (nextHydratableInstance = getNextHydratable(props.firstChild)))\n : (nextHydratableInstance = $$typeof)),\n reconcileChildren(\n current,\n workInProgress,\n workInProgress.pendingProps.children,\n renderLanes\n ),\n markRef(current, workInProgress),\n null === current && (workInProgress.flags |= 4194304),\n workInProgress.child\n );\n case 5:\n if (null === current && isHydrating) {\n if (($$typeof = props = nextHydratableInstance))\n (props = canHydrateInstance(\n props,\n workInProgress.type,\n workInProgress.pendingProps,\n rootOrSingletonContext\n )),\n null !== props\n ? ((workInProgress.stateNode = props),\n (hydrationParentFiber = workInProgress),\n (nextHydratableInstance = getNextHydratable(props.firstChild)),\n (rootOrSingletonContext = !1),\n ($$typeof = !0))\n : ($$typeof = !1);\n $$typeof || throwOnHydrationMismatch(workInProgress);\n }\n pushHostContext(workInProgress);\n $$typeof = workInProgress.type;\n prevState = workInProgress.pendingProps;\n nextState = null !== current ? current.memoizedProps : null;\n props = prevState.children;\n shouldSetTextContent($$typeof, prevState)\n ? (props = null)\n : null !== nextState &&\n shouldSetTextContent($$typeof, nextState) &&\n (workInProgress.flags |= 32);\n null !== workInProgress.memoizedState &&\n (($$typeof = renderWithHooks(\n current,\n workInProgress,\n TransitionAwareHostComponent,\n null,\n null,\n renderLanes\n )),\n (HostTransitionContext._currentValue = $$typeof));\n markRef(current, workInProgress);\n reconcileChildren(current, workInProgress, props, renderLanes);\n return workInProgress.child;\n case 6:\n if (null === current && isHydrating) {\n if ((current = renderLanes = nextHydratableInstance))\n (renderLanes = canHydrateTextInstance(\n renderLanes,\n workInProgress.pendingProps,\n rootOrSingletonContext\n )),\n null !== renderLanes\n ? ((workInProgress.stateNode = renderLanes),\n (hydrationParentFiber = workInProgress),\n (nextHydratableInstance = null),\n (current = !0))\n : (current = !1);\n current || throwOnHydrationMismatch(workInProgress);\n }\n return null;\n case 13:\n return updateSuspenseComponent(current, workInProgress, renderLanes);\n case 4:\n return (\n pushHostContainer(\n workInProgress,\n workInProgress.stateNode.containerInfo\n ),\n (props = workInProgress.pendingProps),\n null === current\n ? (workInProgress.child = reconcileChildFibers(\n workInProgress,\n null,\n props,\n renderLanes\n ))\n : reconcileChildren(current, workInProgress, props, renderLanes),\n workInProgress.child\n );\n case 11:\n return updateForwardRef(\n current,\n workInProgress,\n workInProgress.type,\n workInProgress.pendingProps,\n renderLanes\n );\n case 7:\n return (\n reconcileChildren(\n current,\n workInProgress,\n workInProgress.pendingProps,\n renderLanes\n ),\n workInProgress.child\n );\n case 8:\n return (\n reconcileChildren(\n current,\n workInProgress,\n workInProgress.pendingProps.children,\n renderLanes\n ),\n workInProgress.child\n );\n case 12:\n return (\n reconcileChildren(\n current,\n workInProgress,\n workInProgress.pendingProps.children,\n renderLanes\n ),\n workInProgress.child\n );\n case 10:\n return (\n (props = workInProgress.pendingProps),\n pushProvider(workInProgress, workInProgress.type, props.value),\n reconcileChildren(current, workInProgress, props.children, renderLanes),\n workInProgress.child\n );\n case 9:\n return (\n ($$typeof = workInProgress.type._context),\n (props = workInProgress.pendingProps.children),\n prepareToReadContext(workInProgress),\n ($$typeof = readContext($$typeof)),\n (props = props($$typeof)),\n (workInProgress.flags |= 1),\n reconcileChildren(current, workInProgress, props, renderLanes),\n workInProgress.child\n );\n case 14:\n return updateMemoComponent(\n current,\n workInProgress,\n workInProgress.type,\n workInProgress.pendingProps,\n renderLanes\n );\n case 15:\n return updateSimpleMemoComponent(\n current,\n workInProgress,\n workInProgress.type,\n workInProgress.pendingProps,\n renderLanes\n );\n case 19:\n return updateSuspenseListComponent(current, workInProgress, renderLanes);\n case 31:\n return updateActivityComponent(current, workInProgress, renderLanes);\n case 22:\n return updateOffscreenComponent(\n current,\n workInProgress,\n renderLanes,\n workInProgress.pendingProps\n );\n case 24:\n return (\n prepareToReadContext(workInProgress),\n (props = readContext(CacheContext)),\n null === current\n ? (($$typeof = peekCacheFromPool()),\n null === $$typeof &&\n (($$typeof = workInProgressRoot),\n (prevState = createCache()),\n ($$typeof.pooledCache = prevState),\n prevState.refCount++,\n null !== prevState && ($$typeof.pooledCacheLanes |= renderLanes),\n ($$typeof = prevState)),\n (workInProgress.memoizedState = { parent: props, cache: $$typeof }),\n initializeUpdateQueue(workInProgress),\n pushProvider(workInProgress, CacheContext, $$typeof))\n : (0 !== (current.lanes & renderLanes) &&\n (cloneUpdateQueue(current, workInProgress),\n processUpdateQueue(workInProgress, null, null, renderLanes),\n suspendIfUpdateReadFromEntangledAsyncAction()),\n ($$typeof = current.memoizedState),\n (prevState = workInProgress.memoizedState),\n $$typeof.parent !== props\n ? (($$typeof = { parent: props, cache: props }),\n (workInProgress.memoizedState = $$typeof),\n 0 === workInProgress.lanes &&\n (workInProgress.memoizedState =\n workInProgress.updateQueue.baseState =\n $$typeof),\n pushProvider(workInProgress, CacheContext, props))\n : ((props = prevState.cache),\n pushProvider(workInProgress, CacheContext, props),\n props !== $$typeof.cache &&\n propagateContextChanges(\n workInProgress,\n [CacheContext],\n renderLanes,\n !0\n ))),\n reconcileChildren(\n current,\n workInProgress,\n workInProgress.pendingProps.children,\n renderLanes\n ),\n workInProgress.child\n );\n case 29:\n throw workInProgress.pendingProps;\n }\n throw Error(formatProdErrorMessage(156, workInProgress.tag));\n}\nfunction markUpdate(workInProgress) {\n workInProgress.flags |= 4;\n}\nfunction preloadInstanceAndSuspendIfNeeded(\n workInProgress,\n type,\n oldProps,\n newProps,\n renderLanes\n) {\n if ((type = 0 !== (workInProgress.mode & 32))) type = !1;\n if (type) {\n if (\n ((workInProgress.flags |= 16777216),\n (renderLanes & 335544128) === renderLanes)\n )\n if (workInProgress.stateNode.complete) workInProgress.flags |= 8192;\n else if (shouldRemainOnPreviousScreen()) workInProgress.flags |= 8192;\n else\n throw (\n ((suspendedThenable = noopSuspenseyCommitThenable),\n SuspenseyCommitException)\n );\n } else workInProgress.flags &= -16777217;\n}\nfunction preloadResourceAndSuspendIfNeeded(workInProgress, resource) {\n if (\"stylesheet\" !== resource.type || 0 !== (resource.state.loading & 4))\n workInProgress.flags &= -16777217;\n else if (((workInProgress.flags |= 16777216), !preloadResource(resource)))\n if (shouldRemainOnPreviousScreen()) workInProgress.flags |= 8192;\n else\n throw (\n ((suspendedThenable = noopSuspenseyCommitThenable),\n SuspenseyCommitException)\n );\n}\nfunction scheduleRetryEffect(workInProgress, retryQueue) {\n null !== retryQueue && (workInProgress.flags |= 4);\n workInProgress.flags & 16384 &&\n ((retryQueue =\n 22 !== workInProgress.tag ? claimNextRetryLane() : 536870912),\n (workInProgress.lanes |= retryQueue),\n (workInProgressSuspendedRetryLanes |= retryQueue));\n}\nfunction cutOffTailIfNeeded(renderState, hasRenderedATailFallback) {\n if (!isHydrating)\n switch (renderState.tailMode) {\n case \"hidden\":\n hasRenderedATailFallback = renderState.tail;\n for (var lastTailNode = null; null !== hasRenderedATailFallback; )\n null !== hasRenderedATailFallback.alternate &&\n (lastTailNode = hasRenderedATailFallback),\n (hasRenderedATailFallback = hasRenderedATailFallback.sibling);\n null === lastTailNode\n ? (renderState.tail = null)\n : (lastTailNode.sibling = null);\n break;\n case \"collapsed\":\n lastTailNode = renderState.tail;\n for (var lastTailNode$106 = null; null !== lastTailNode; )\n null !== lastTailNode.alternate && (lastTailNode$106 = lastTailNode),\n (lastTailNode = lastTailNode.sibling);\n null === lastTailNode$106\n ? hasRenderedATailFallback || null === renderState.tail\n ? (renderState.tail = null)\n : (renderState.tail.sibling = null)\n : (lastTailNode$106.sibling = null);\n }\n}\nfunction bubbleProperties(completedWork) {\n var didBailout =\n null !== completedWork.alternate &&\n completedWork.alternate.child === completedWork.child,\n newChildLanes = 0,\n subtreeFlags = 0;\n if (didBailout)\n for (var child$107 = completedWork.child; null !== child$107; )\n (newChildLanes |= child$107.lanes | child$107.childLanes),\n (subtreeFlags |= child$107.subtreeFlags & 65011712),\n (subtreeFlags |= child$107.flags & 65011712),\n (child$107.return = completedWork),\n (child$107 = child$107.sibling);\n else\n for (child$107 = completedWork.child; null !== child$107; )\n (newChildLanes |= child$107.lanes | child$107.childLanes),\n (subtreeFlags |= child$107.subtreeFlags),\n (subtreeFlags |= child$107.flags),\n (child$107.return = completedWork),\n (child$107 = child$107.sibling);\n completedWork.subtreeFlags |= subtreeFlags;\n completedWork.childLanes = newChildLanes;\n return didBailout;\n}\nfunction completeWork(current, workInProgress, renderLanes) {\n var newProps = workInProgress.pendingProps;\n popTreeContext(workInProgress);\n switch (workInProgress.tag) {\n case 16:\n case 15:\n case 0:\n case 11:\n case 7:\n case 8:\n case 12:\n case 9:\n case 14:\n return bubbleProperties(workInProgress), null;\n case 1:\n return bubbleProperties(workInProgress), null;\n case 3:\n renderLanes = workInProgress.stateNode;\n newProps = null;\n null !== current && (newProps = current.memoizedState.cache);\n workInProgress.memoizedState.cache !== newProps &&\n (workInProgress.flags |= 2048);\n popProvider(CacheContext);\n popHostContainer();\n renderLanes.pendingContext &&\n ((renderLanes.context = renderLanes.pendingContext),\n (renderLanes.pendingContext = null));\n if (null === current || null === current.child)\n popHydrationState(workInProgress)\n ? markUpdate(workInProgress)\n : null === current ||\n (current.memoizedState.isDehydrated &&\n 0 === (workInProgress.flags & 256)) ||\n ((workInProgress.flags |= 1024),\n upgradeHydrationErrorsToRecoverable());\n bubbleProperties(workInProgress);\n return null;\n case 26:\n var type = workInProgress.type,\n nextResource = workInProgress.memoizedState;\n null === current\n ? (markUpdate(workInProgress),\n null !== nextResource\n ? (bubbleProperties(workInProgress),\n preloadResourceAndSuspendIfNeeded(workInProgress, nextResource))\n : (bubbleProperties(workInProgress),\n preloadInstanceAndSuspendIfNeeded(\n workInProgress,\n type,\n null,\n newProps,\n renderLanes\n )))\n : nextResource\n ? nextResource !== current.memoizedState\n ? (markUpdate(workInProgress),\n bubbleProperties(workInProgress),\n preloadResourceAndSuspendIfNeeded(workInProgress, nextResource))\n : (bubbleProperties(workInProgress),\n (workInProgress.flags &= -16777217))\n : ((current = current.memoizedProps),\n current !== newProps && markUpdate(workInProgress),\n bubbleProperties(workInProgress),\n preloadInstanceAndSuspendIfNeeded(\n workInProgress,\n type,\n current,\n newProps,\n renderLanes\n ));\n return null;\n case 27:\n popHostContext(workInProgress);\n renderLanes = rootInstanceStackCursor.current;\n type = workInProgress.type;\n if (null !== current && null != workInProgress.stateNode)\n current.memoizedProps !== newProps && markUpdate(workInProgress);\n else {\n if (!newProps) {\n if (null === workInProgress.stateNode)\n throw Error(formatProdErrorMessage(166));\n bubbleProperties(workInProgress);\n return null;\n }\n current = contextStackCursor.current;\n popHydrationState(workInProgress)\n ? prepareToHydrateHostInstance(workInProgress, current)\n : ((current = resolveSingletonInstance(type, newProps, renderLanes)),\n (workInProgress.stateNode = current),\n markUpdate(workInProgress));\n }\n bubbleProperties(workInProgress);\n return null;\n case 5:\n popHostContext(workInProgress);\n type = workInProgress.type;\n if (null !== current && null != workInProgress.stateNode)\n current.memoizedProps !== newProps && markUpdate(workInProgress);\n else {\n if (!newProps) {\n if (null === workInProgress.stateNode)\n throw Error(formatProdErrorMessage(166));\n bubbleProperties(workInProgress);\n return null;\n }\n nextResource = contextStackCursor.current;\n if (popHydrationState(workInProgress))\n prepareToHydrateHostInstance(workInProgress, nextResource);\n else {\n var ownerDocument = getOwnerDocumentFromRootContainer(\n rootInstanceStackCursor.current\n );\n switch (nextResource) {\n case 1:\n nextResource = ownerDocument.createElementNS(\n \"http://www.w3.org/2000/svg\",\n type\n );\n break;\n case 2:\n nextResource = ownerDocument.createElementNS(\n \"http://www.w3.org/1998/Math/MathML\",\n type\n );\n break;\n default:\n switch (type) {\n case \"svg\":\n nextResource = ownerDocument.createElementNS(\n \"http://www.w3.org/2000/svg\",\n type\n );\n break;\n case \"math\":\n nextResource = ownerDocument.createElementNS(\n \"http://www.w3.org/1998/Math/MathML\",\n type\n );\n break;\n case \"script\":\n nextResource = ownerDocument.createElement(\"div\");\n nextResource.innerHTML = \" + + + + +
            + + + diff --git a/suites-experimental/chat-room/dist/resources.txt b/suites-experimental/chat-room/dist/resources.txt new file mode 100644 index 000000000..231ae760d --- /dev/null +++ b/suites-experimental/chat-room/dist/resources.txt @@ -0,0 +1,4 @@ +assets/index-158fa97f.css +assets/index-381effb6.js +assets/index-381effb6.js.map +index.html