diff --git a/.astro/settings.json b/.astro/settings.json new file mode 100644 index 000000000000..97ac9af5770e --- /dev/null +++ b/.astro/settings.json @@ -0,0 +1,8 @@ +{ + "devToolbar": { + "enabled": false + }, + "_variables": { + "lastUpdateCheck": 1763378528944 + } +} \ No newline at end of file diff --git a/.astro/types.d.ts b/.astro/types.d.ts new file mode 100644 index 000000000000..03d7cc43f117 --- /dev/null +++ b/.astro/types.d.ts @@ -0,0 +1,2 @@ +/// +/// \ No newline at end of file diff --git a/.cursor/rules/content-migration.mdc b/.cursor/rules/content-migration.mdc new file mode 100644 index 000000000000..b2fd03e6f5eb --- /dev/null +++ b/.cursor/rules/content-migration.mdc @@ -0,0 +1,155 @@ +--- +description: When user requests migrating old roadmap content to new folder from content-old to content folder +globs: +alwaysApply: false +--- +# Content Migration Rule + +## Rule Name: content-migration + +## Description +This rule provides a complete process for migrating roadmap content from old structure to new structure using migration mapping files. + +## When to Use +Use this rule when you need to: +- Migrate content from content-old directories to content directories +- Use a migration-mapping.json file to map topic paths to content IDs +- Populate empty content files with existing content from legacy structure + +## Process + +### 1. Prerequisites Check +- Verify the roadmap directory has a `migration-mapping.json` file +- Confirm `content-old/` directory exists with source content +- Confirm `content/` directory exists with target files + +### 2. Migration Script Creation +Create a Node.js script with the following functionality: + +```javascript +const fs = require('fs'); +const path = require('path'); + +// Load the migration mapping +const migrationMapping = JSON.parse(fs.readFileSync('migration-mapping.json', 'utf8')); + +// Function to find old content file based on topic path +function findOldContentFile(topicPath) { + const parts = topicPath.split(':'); + + if (parts.length === 1) { + // Top level file like "introduction" + return path.join('content-old', parts[0], 'index.md'); + } else if (parts.length === 2) { + // Like "introduction:what-is-rust" + const [folder, filename] = parts; + return path.join('content-old', folder, `${filename}.md`); + } else if (parts.length === 3) { + // Like "language-basics:syntax:variables" + const [folder, subfolder, filename] = parts; + return path.join('content-old', folder, subfolder, `${filename}.md`); + } + + return null; +} + +// Function to find new content file based on content ID +function findNewContentFile(contentId) { + const contentDir = 'content'; + const files = fs.readdirSync(contentDir); + + // Find file that ends with the content ID + const matchingFile = files.find(file => file.includes(`@${contentId}.md`)); + + if (matchingFile) { + return path.join(contentDir, matchingFile); + } + + return null; +} + +// Process each mapping +console.log('Starting content migration...\n'); + +let migratedCount = 0; +let skippedCount = 0; + +for (const [topicPath, contentId] of Object.entries(migrationMapping)) { + const oldFilePath = findOldContentFile(topicPath); + const newFilePath = findNewContentFile(contentId); + + if (!oldFilePath) { + console.log(`❌ Could not determine old file path for: ${topicPath}`); + skippedCount++; + continue; + } + + if (!newFilePath) { + console.log(`❌ Could not find new file for content ID: ${contentId} (topic: ${topicPath})`); + skippedCount++; + continue; + } + + if (!fs.existsSync(oldFilePath)) { + console.log(`❌ Old file does not exist: ${oldFilePath} (topic: ${topicPath})`); + skippedCount++; + continue; + } + + try { + // Read old content + const oldContent = fs.readFileSync(oldFilePath, 'utf8'); + + // Write to new file + fs.writeFileSync(newFilePath, oldContent); + + console.log(`✅ Migrated: ${topicPath} -> ${path.basename(newFilePath)}`); + migratedCount++; + } catch (error) { + console.log(`❌ Error migrating ${topicPath}: ${error.message}`); + skippedCount++; + } +} + +console.log(`\n📊 Migration complete:`); +console.log(` Migrated: ${migratedCount} files`); +console.log(` Skipped: ${skippedCount} files`); +console.log(` Total: ${Object.keys(migrationMapping).length} mappings`); +``` + +### 3. Execution Steps +1. Navigate to the roadmap directory (e.g., `src/data/roadmaps/[roadmap-name]`) +2. Create the migration script as `migrate_content.cjs` +3. Run: `node migrate_content.cjs` +4. Review the migration results +5. Clean up the temporary script file + +### 4. Validation +After migration: +- Verify a few migrated files have proper content (not just titles) +- Check that the content structure matches the old content +- Ensure proper markdown formatting is preserved + +## File Structure Expected +``` +roadmap-directory/ +├── migration-mapping.json +├── content/ +│ ├── file1@contentId1.md +│ ├── file2@contentId2.md +│ └── ... +└── content-old/ + ├── section1/ + │ ├── index.md + │ ├── topic1.md + │ └── subsection1/ + │ └── subtopic1.md + └── section2/ + └── ... +``` + +## Notes +- The migration mapping uses colons (`:`) to separate nested paths +- Content files in the new structure use the pattern `filename@contentId.md` +- The script handles 1-3 levels of nesting in the old structure +- Always create the script with `.cjs` extension to avoid ES module issues diff --git a/.cursor/rules/gh-cli.mdc b/.cursor/rules/gh-cli.mdc new file mode 100644 index 000000000000..b09f4ac489e3 --- /dev/null +++ b/.cursor/rules/gh-cli.mdc @@ -0,0 +1,389 @@ +--- +description: GitHub pull requests +globs: +alwaysApply: false +--- +# gh cli + +Work seamlessly with GitHub from the command line. + +USAGE + gh [flags] + +CORE COMMANDS + auth: Authenticate gh and git with GitHub + browse: Open repositories, issues, pull requests, and more in the browser + codespace: Connect to and manage codespaces + gist: Manage gists + issue: Manage issues + org: Manage organizations + pr: Manage pull requests + project: Work with GitHub Projects. + release: Manage releases + repo: Manage repositories + +GITHUB ACTIONS COMMANDS + cache: Manage GitHub Actions caches + run: View details about workflow runs + workflow: View details about GitHub Actions workflows + +ALIAS COMMANDS + co: Alias for "pr checkout" + +ADDITIONAL COMMANDS + alias: Create command shortcuts + api: Make an authenticated GitHub API request + attestation: Work with artifact attestations + completion: Generate shell completion scripts + config: Manage configuration for gh + extension: Manage gh extensions + gpg-key: Manage GPG keys + label: Manage labels + preview: Execute previews for gh features + ruleset: View info about repo rulesets + search: Search for repositories, issues, and pull requests + secret: Manage GitHub secrets + ssh-key: Manage SSH keys + status: Print information about relevant issues, pull requests, and notifications across repositories + variable: Manage GitHub Actions variables + +HELP TOPICS + accessibility: Learn about GitHub CLI's accessibility experiences + actions: Learn about working with GitHub Actions + environment: Environment variables that can be used with gh + exit-codes: Exit codes used by gh + formatting: Formatting options for JSON data exported from gh + mintty: Information about using gh with MinTTY + reference: A comprehensive reference of all gh commands + +FLAGS + --help Show help for command + --version Show gh version + +EXAMPLES + $ gh issue create + $ gh repo clone cli/cli + $ gh pr checkout 321 + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + +## gh pr + +Work with GitHub pull requests. + +USAGE + gh pr [flags] + +GENERAL COMMANDS + create: Create a pull request + list: List pull requests in a repository + status: Show status of relevant pull requests + +TARGETED COMMANDS + checkout: Check out a pull request in git + checks: Show CI status for a single pull request + close: Close a pull request + comment: Add a comment to a pull request + diff: View changes in a pull request + edit: Edit a pull request + lock: Lock pull request conversation + merge: Merge a pull request + ready: Mark a pull request as ready for review + reopen: Reopen a pull request + review: Add a review to a pull request + unlock: Unlock pull request conversation + update-branch: Update a pull request branch + view: View a pull request + +FLAGS + -R, --repo [HOST/]OWNER/REPO Select another repository using the [HOST/]OWNER/REPO format + +INHERITED FLAGS + --help Show help for command + +ARGUMENTS + A pull request can be supplied as argument in any of the following formats: + - by number, e.g. "123"; + - by URL, e.g. "https://github.com/OWNER/REPO/pull/123"; or + - by the name of its head branch, e.g. "patch-1" or "OWNER:patch-1". + +EXAMPLES + $ gh pr checkout 353 + $ gh pr create --fill + $ gh pr view --web + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + +## gh pr list + +List pull requests in a GitHub repository. By default, this only lists open PRs. + +The search query syntax is documented here: + + +For more information about output formatting flags, see `gh help formatting`. + +USAGE + gh pr list [flags] + +ALIASES + gh pr ls + +FLAGS + --app string Filter by GitHub App author + -a, --assignee string Filter by assignee + -A, --author string Filter by author + -B, --base string Filter by base branch + -d, --draft Filter by draft state + -H, --head string Filter by head branch (":" syntax not supported) + -q, --jq expression Filter JSON output using a jq expression + --json fields Output JSON with the specified fields + -l, --label strings Filter by label + -L, --limit int Maximum number of items to fetch (default 30) + -S, --search query Search pull requests with query + -s, --state string Filter by state: {open|closed|merged|all} (default "open") + -t, --template string Format JSON output using a Go template; see "gh help formatting" + -w, --web List pull requests in the web browser + +INHERITED FLAGS + --help Show help for command + -R, --repo [HOST/]OWNER/REPO Select another repository using the [HOST/]OWNER/REPO format + +JSON FIELDS + additions, assignees, author, autoMergeRequest, baseRefName, baseRefOid, body, + changedFiles, closed, closedAt, closingIssuesReferences, comments, commits, + createdAt, deletions, files, fullDatabaseId, headRefName, headRefOid, + headRepository, headRepositoryOwner, id, isCrossRepository, isDraft, labels, + latestReviews, maintainerCanModify, mergeCommit, mergeStateStatus, mergeable, + mergedAt, mergedBy, milestone, number, potentialMergeCommit, projectCards, + projectItems, reactionGroups, reviewDecision, reviewRequests, reviews, state, + statusCheckRollup, title, updatedAt, url + +EXAMPLES + # List PRs authored by you + $ gh pr list --author "@me" + + # List PRs with a specific head branch name + $ gh pr list --head "typo" + + # List only PRs with all of the given labels + $ gh pr list --label bug --label "priority 1" + + # Filter PRs using search syntax + $ gh pr list --search "status:success review:required" + + # Find a PR that introduced a given commit + $ gh pr list --search "" --state merged + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + +## gh pr diff + +View changes in a pull request. + +Without an argument, the pull request that belongs to the current branch +is selected. + +With `--web` flag, open the pull request diff in a web browser instead. + + +USAGE + gh pr diff [ | | ] [flags] + +FLAGS + --color string Use color in diff output: {always|never|auto} (default "auto") + --name-only Display only names of changed files + --patch Display diff in patch format + -w, --web Open the pull request diff in the browser + +INHERITED FLAGS + --help Show help for command + -R, --repo [HOST/]OWNER/REPO Select another repository using the [HOST/]OWNER/REPO format + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + +## gh pr merge + +Merge a pull request on GitHub. + +Without an argument, the pull request that belongs to the current branch +is selected. + +When targeting a branch that requires a merge queue, no merge strategy is required. +If required checks have not yet passed, auto-merge will be enabled. +If required checks have passed, the pull request will be added to the merge queue. +To bypass a merge queue and merge directly, pass the `--admin` flag. + + +USAGE + gh pr merge [ | | ] [flags] + +FLAGS + --admin Use administrator privileges to merge a pull request that does not meet requirements + -A, --author-email text Email text for merge commit author + --auto Automatically merge only after necessary requirements are met + -b, --body text Body text for the merge commit + -F, --body-file file Read body text from file (use "-" to read from standard input) + -d, --delete-branch Delete the local and remote branch after merge + --disable-auto Disable auto-merge for this pull request + --match-head-commit SHA Commit SHA that the pull request head must match to allow merge + -m, --merge Merge the commits with the base branch + -r, --rebase Rebase the commits onto the base branch + -s, --squash Squash the commits into one commit and merge it into the base branch + -t, --subject text Subject text for the merge commit + +INHERITED FLAGS + --help Show help for command + -R, --repo [HOST/]OWNER/REPO Select another repository using the [HOST/]OWNER/REPO format + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + +## gh pr review + +Add a review to a pull request. + +Without an argument, the pull request that belongs to the current branch is reviewed. + + +USAGE + gh pr review [ | | ] [flags] + +FLAGS + -a, --approve Approve pull request + -b, --body string Specify the body of a review + -F, --body-file file Read body text from file (use "-" to read from standard input) + -c, --comment Comment on a pull request + -r, --request-changes Request changes on a pull request + +INHERITED FLAGS + --help Show help for command + -R, --repo [HOST/]OWNER/REPO Select another repository using the [HOST/]OWNER/REPO format + +EXAMPLES + # Approve the pull request of the current branch + $ gh pr review --approve + + # Leave a review comment for the current branch + $ gh pr review --comment -b "interesting" + + # Add a review for a specific pull request + $ gh pr review 123 + + # Request changes on a specific pull request + $ gh pr review 123 -r -b "needs more ASCII art" + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + +## gh pr checkout + +Check out a pull request in git + +USAGE + gh pr checkout [ | | ] [flags] + +FLAGS + -b, --branch string Local branch name to use (default [the name of the head branch]) + --detach Checkout PR with a detached HEAD + -f, --force Reset the existing local branch to the latest state of the pull request + --recurse-submodules Update all submodules after checkout + +INHERITED FLAGS + --help Show help for command + -R, --repo [HOST/]OWNER/REPO Select another repository using the [HOST/]OWNER/REPO format + +EXAMPLES + # Interactively select a PR from the 10 most recent to check out + $ gh pr checkout + + # Checkout a specific PR + $ gh pr checkout 32 + $ gh pr checkout https://github.com/OWNER/REPO/pull/32 + $ gh pr checkout feature + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + + ## gh pr close + + Close a pull request + +USAGE + gh pr close { | | } [flags] + +FLAGS + -c, --comment string Leave a closing comment + -d, --delete-branch Delete the local and remote branch after close + +INHERITED FLAGS + --help Show help for command + -R, --repo [HOST/]OWNER/REPO Select another repository using the [HOST/]OWNER/REPO format + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + +## gh pr comment + +Add a comment to a GitHub pull request. + +Without the body text supplied through flags, the command will interactively +prompt for the comment text. + + +USAGE + gh pr comment [ | | ] [flags] + +FLAGS + -b, --body text The comment body text + -F, --body-file file Read body text from file (use "-" to read from standard input) + --create-if-none Create a new comment if no comments are found. Can be used only with --edit-last + --delete-last Delete the last comment of the current user + --edit-last Edit the last comment of the current user + -e, --editor Skip prompts and open the text editor to write the body in + -w, --web Open the web browser to write the comment + --yes Skip the delete confirmation prompt when --delete-last is provided + +INHERITED FLAGS + --help Show help for command + -R, --repo [HOST/]OWNER/REPO Select another repository using the [HOST/]OWNER/REPO format + +EXAMPLES + $ gh pr comment 13 --body "Hi from GitHub CLI" + +LEARN MORE + Use `gh --help` for more information about a command. + Read the manual at https://cli.github.com/manual + Learn about exit codes using `gh help exit-codes` + Learn about accessibility experiences using `gh help accessibility` + + + diff --git a/.env.example b/.env.example new file mode 100644 index 000000000000..0be5a03f116f --- /dev/null +++ b/.env.example @@ -0,0 +1,12 @@ +PUBLIC_API_URL=https://api.roadmap.sh +PUBLIC_AVATAR_BASE_URL=https://dodrc8eu8m09s.cloudfront.net/avatars +PUBLIC_EDITOR_APP_URL=https://draw.roadmap.sh +PUBLIC_COURSE_APP_URL=http://localhost:5173 + +PUBLIC_STRIPE_INDIVIDUAL_MONTHLY_PRICE_ID= +PUBLIC_STRIPE_INDIVIDUAL_YEARLY_PRICE_ID= + +PUBLIC_STRIPE_INDIVIDUAL_MONTHLY_PRICE_AMOUNT=10 +PUBLIC_STRIPE_INDIVIDUAL_YEARLY_PRICE_AMOUNT=100 + +ROADMAP_API_KEY= \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000000..5854e4ab966e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +# These are supported funding model platforms +github: kamranahmedse diff --git a/.github/ISSUE_TEMPLATE/01-suggest-changes.yml b/.github/ISSUE_TEMPLATE/01-suggest-changes.yml new file mode 100644 index 000000000000..48c3a0341c54 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01-suggest-changes.yml @@ -0,0 +1,25 @@ +name: "✍️ ​ ​Missing or Deprecated Roadmap Topics" +description: Help us improve the roadmaps by suggesting changes +labels: [topic-change] +assignees: [] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to help us improve the roadmaps with your suggestions. + - type: input + id: url + attributes: + label: Roadmap URL + description: Please provide the URL of the roadmap you are suggesting changes to. + placeholder: https://roadmap.sh + validations: + required: true + - type: textarea + id: roadmap-suggestions + attributes: + label: Suggestions + description: What changes would you like to suggest? + placeholder: Enter your suggestions here. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/02-bug-report.yml b/.github/ISSUE_TEMPLATE/02-bug-report.yml new file mode 100644 index 000000000000..755fa99ce943 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02-bug-report.yml @@ -0,0 +1,42 @@ +name: "🐛 ​ ​Bug Report" +description: Report an issue or possible bug +labels: [bug] +assignees: [] +body: + - type: input + id: url + attributes: + label: What is the URL where the issue is happening + placeholder: https://roadmap.sh + validations: + required: true + - type: dropdown + id: browsers + attributes: + label: What browsers are you seeing the problem on? + multiple: true + options: + - Firefox + - Chrome + - Safari + - Microsoft Edge + - Other + - type: textarea + id: bug-description + attributes: + label: Describe the Bug + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Output from browser console (if any) + description: Please copy and paste any relevant log output. + - type: checkboxes + id: will-pr + attributes: + label: Participation + options: + - label: I am willing to submit a pull request for this issue. + required: false diff --git a/.github/ISSUE_TEMPLATE/03-feature-suggestion.yml b/.github/ISSUE_TEMPLATE/03-feature-suggestion.yml new file mode 100644 index 000000000000..54bb562f6dc7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/03-feature-suggestion.yml @@ -0,0 +1,12 @@ +name: "✨ ​ ​Feature Suggestion" +description: Is there a feature you'd like to see on Roadmap.sh? Let us know! +labels: [feature request] +assignees: [] +body: + - type: textarea + id: feature-description + attributes: + label: Feature Description + description: Please provide a detailed description of the feature you are suggesting and how it would help you/others. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/04-roadmap-contribution.yml b/.github/ISSUE_TEMPLATE/04-roadmap-contribution.yml new file mode 100644 index 000000000000..8753d54c44f7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/04-roadmap-contribution.yml @@ -0,0 +1,25 @@ +name: "🙏 ​ ​Submit a Roadmap" +description: Help us launch a new roadmap with your expertise. +labels: [roadmap contribution] +assignees: [] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to submit a roadmap! Please fill out the information below and we'll get back to you as soon as we can. + - type: input + id: roadmap-title + attributes: + label: What is the title of the roadmap you are submitting? + placeholder: e.g. Roadmap to learn Data Science + validations: + required: true + - type: textarea + id: roadmap-description + attributes: + label: Roadmap Link + description: Please create the roadmap [using our roadmap editor](https://twitter.com/kamrify/status/1708293162693767426) and submit the roadmap link. + placeholder: | + https://roadmap.sh/xyz + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/05-something-else.yml b/.github/ISSUE_TEMPLATE/05-something-else.yml new file mode 100644 index 000000000000..95341aa4001c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/05-something-else.yml @@ -0,0 +1,12 @@ +name: "🤷‍♂️ ​ ​Something else" +description: If none of the above templates fit your needs, please use this template to submit your issue. +labels: [] +assignees: [] +body: + - type: textarea + id: issue-description + attributes: + label: Detailed Description + description: Please provide a detailed description of the issue. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000000..197291f6dd51 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: false +contact_links: + - name: ✋ ​ ​Roadmap Request + url: https://roadmap.sh/discord + about: Please do not open issues with roadmap requests, hop onto the discord server for that. + - name: 📝 ​ ​Typo or Grammatical Mistake + url: https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data + about: Please submit a pull request instead of reporting it as an issue. + - name: 💬 ​ ​Chat on Discord + url: https://roadmap.sh/discord + about: Join the community on our Discord server. + - name: 🤝 ​ ​Guidance + url: https://roadmap.sh/discord + about: Join the community in our Discord server. diff --git a/.github/workflows/aws-costs.yml b/.github/workflows/aws-costs.yml new file mode 100644 index 000000000000..649f96207854 --- /dev/null +++ b/.github/workflows/aws-costs.yml @@ -0,0 +1,21 @@ +name: Sends Daily AWS Costs to Slack +on: + # Allow manual Run + workflow_dispatch: + # Run at 7:00 UTC every day + schedule: + - cron: "0 7 * * *" +jobs: + aws_costs: + runs-on: ubuntu-latest + steps: + - name: Get Costs + env: + AWS_KEY: ${{ secrets.COST_AWS_ACCESS_KEY }} + AWS_SECRET: ${{ secrets.COST_AWS_SECRET_KEY }} + AWS_REGION: ${{ secrets.COST_AWS_REGION }} + SLACK_CHANNEL: ${{ secrets.SLACK_COST_CHANNEL }} + SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }} + run: | + npm install -g aws-cost-cli + aws-cost -k $AWS_KEY -s $AWS_SECRET -r $AWS_REGION -S $SLACK_TOKEN -C $SLACK_CHANNEL diff --git a/.github/workflows/cleanup-orphaned-content.yml b/.github/workflows/cleanup-orphaned-content.yml new file mode 100644 index 000000000000..f2bbc0f6b7de --- /dev/null +++ b/.github/workflows/cleanup-orphaned-content.yml @@ -0,0 +1,80 @@ +name: Cleanup Orphaned Content + +on: + workflow_dispatch: + inputs: + roadmap_slug: + description: "The ID of the roadmap to clean up" + required: true + +jobs: + cleanup-content: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup pnpm@v9 + uses: pnpm/action-setup@v4 + with: + version: 9 + run_install: false + + - name: Setup Node.js Version 20 (LTS) + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Install Dependencies and Run Cleanup + run: | + echo "Installing Dependencies" + pnpm install + echo "Running Orphaned Content Cleanup" + npm run cleanup:orphaned-content -- --roadmap-slug=${{ inputs.roadmap_slug }} + + - name: Read cleanup summary + id: read-summary + run: | + if [ -f .cleanup-summary.md ]; then + { + echo 'summary<> $GITHUB_OUTPUT + fi + + - name: Check for changes + id: verify-changed-files + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "changed=true" >> $GITHUB_OUTPUT + else + echo "changed=false" >> $GITHUB_OUTPUT + fi + + - name: Delete summary file + if: steps.verify-changed-files.outputs.changed == 'true' + run: rm -f .cleanup-summary.md + + - name: Create PR + if: steps.verify-changed-files.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v7 + with: + delete-branch: false + branch: "chore/cleanup-orphaned-content-${{ inputs.roadmap_slug }}" + base: "master" + labels: | + automated pr + reviewers: jcanalesluna,kamranahmedse + commit-message: "chore: cleanup orphaned content files" + title: "chore: cleanup orphaned content - ${{ inputs.roadmap_slug }}" + body: | + ${{ steps.read-summary.outputs.summary }} + + > [!IMPORTANT] + > This PR removes orphaned/duplicate content files for: ${{ inputs.roadmap_slug }} + > + > Commit: ${{ github.sha }} + > Workflow Path: ${{ github.workflow_ref }} + + **Please review the changes and merge the PR if everything looks correct.** diff --git a/.github/workflows/close-feedback-pr.yml b/.github/workflows/close-feedback-pr.yml new file mode 100644 index 000000000000..bde738656581 --- /dev/null +++ b/.github/workflows/close-feedback-pr.yml @@ -0,0 +1,50 @@ +name: Close PRs with Feedback +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' +jobs: + close-pr: + runs-on: ubuntu-latest + steps: + - name: Close PR if it has label "feedback left" and no changes in 7 days + uses: actions/github-script@v3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { data: pullRequests } = await github.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + base: 'master', + }); + + for (const pullRequest of pullRequests) { + const { data: labels } = await github.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pullRequest.number, + }); + + const feedbackLabel = labels.find((label) => label.name === 'feedback left'); + if (feedbackLabel) { + const lastUpdated = new Date(pullRequest.updated_at); + const sevenDaysAgo = new Date(); + sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7); + + if (lastUpdated < sevenDaysAgo) { + await github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pullRequest.number, + body: 'Closing this PR because there has been no activity for the past 7 days. Feel free to reopen if you have any feedback.', + }); + await github.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pullRequest.number, + state: 'closed', + }); + } + } + } \ No newline at end of file diff --git a/.github/workflows/cloudfront-api-cache.yml b/.github/workflows/cloudfront-api-cache.yml new file mode 100644 index 000000000000..fc8a584c777e --- /dev/null +++ b/.github/workflows/cloudfront-api-cache.yml @@ -0,0 +1,16 @@ +name: Clears API Cloudfront Cache +on: + workflow_dispatch: +jobs: + cloudfront_api_cache: + runs-on: ubuntu-latest + steps: + - name: Clear Cloudfront Caching + run: | + curl -L \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GH_PAT }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/roadmapsh/infra-ansible/actions/workflows/playbook.yml/dispatches \ + -d '{ "ref":"master", "inputs": { "playbook": "roadmap_web.yml", "tags": "cloudfront-api", "is_verbose": false } }' diff --git a/.github/workflows/cloudfront-fe-cache.yml b/.github/workflows/cloudfront-fe-cache.yml new file mode 100644 index 000000000000..0f69e825a85d --- /dev/null +++ b/.github/workflows/cloudfront-fe-cache.yml @@ -0,0 +1,16 @@ +name: Clears Frontend Cloudfront Cache +on: + workflow_dispatch: +jobs: + cloudfront_fe_cache: + runs-on: ubuntu-latest + steps: + - name: Clear Cloudfront Caching + run: | + curl -L \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GH_PAT }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/roadmapsh/infra-ansible/actions/workflows/playbook.yml/dispatches \ + -d '{ "ref":"master", "inputs": { "playbook": "roadmap_web.yml", "tags": "cloudfront,cloudfront-course", "is_verbose": false } }' diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml new file mode 100644 index 000000000000..e9bb29fef223 --- /dev/null +++ b/.github/workflows/deployment.yml @@ -0,0 +1,75 @@ +name: Deploy to EC2 + +on: + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 2 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: pnpm/action-setup@v4.0.0 + with: + version: 9 + + # ------------------- + # Setup configuration + # ------------------- + - name: Prepare configuration files + run: | + git clone https://${{ secrets.GH_PAT }}@github.com/roadmapsh/infra-config.git configuration --depth 1 + - name: Copy configuration files + run: | + cp configuration/dist/github/developer-roadmap.env .env + + # ----------------- + # Prepare the Build + # ----------------- + - name: Install Dependencies + run: | + pnpm install + + - name: Generate Production Build + run: | + git clone https://${{ secrets.GH_PAT }}@github.com/roadmapsh/web-draw.git .temp/web-draw --depth 1 + npm run generate-renderer + npm run compress:images + npm run build + + # -------------------- + # Deploy to EC2 + # -------------------- + - uses: webfactory/ssh-agent@v0.7.0 + with: + ssh-private-key: ${{ secrets.EC2_PRIVATE_KEY }} + - name: Deploy Application to EC2 + run: | + rsync -apvz --delete --no-times --exclude "configuration" -e "ssh -o StrictHostKeyChecking=no" -p ./ ${{ secrets.EC2_USERNAME }}@${{ secrets.EC2_HOST }}:/var/www/roadmap.sh/ + - name: Restart PM2 + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.EC2_HOST }} + username: ${{ secrets.EC2_USERNAME }} + key: ${{ secrets.EC2_PRIVATE_KEY }} + script: | + cd /var/www/roadmap.sh + sudo pm2 restart web-roadmap + + # ---------------------- + # Clear cloudfront cache + # ---------------------- + - name: Clear Cloudfront Caching + run: | + curl -L \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GH_PAT }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/roadmapsh/infra-ansible/actions/workflows/playbook.yml/dispatches \ + -d '{ "ref":"master", "inputs": { "playbook": "roadmap_web.yml", "tags": "cloudfront", "is_verbose": false } }' \ No newline at end of file diff --git a/.github/workflows/label-issue.yml b/.github/workflows/label-issue.yml new file mode 100644 index 000000000000..7250e25ef3a1 --- /dev/null +++ b/.github/workflows/label-issue.yml @@ -0,0 +1,40 @@ +name: Label Issue + +on: + issues: + types: [ opened, edited ] + +jobs: + label-topic-change-issue: + runs-on: ubuntu-latest + steps: + - name: Add Labels To Issue + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issue = context.payload.issue; + const roadmapUrl = issue.body.match(/https?:\/\/roadmap.sh\/[^ ]+/); + + // if the issue is labeled as a topic-change, add the roadmap slug as a label + if (issue.labels.some(label => label.name === 'topic-change')) { + if (roadmapUrl) { + const roadmapSlug = new URL(roadmapUrl[0]).pathname.replace(/\//, ''); + github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: [roadmapSlug] + }); + } + + // Close the issue if it has no roadmap URL + if (!roadmapUrl) { + github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + state: 'closed' + }); + } + } \ No newline at end of file diff --git a/.github/workflows/sync-content-to-repo.yml b/.github/workflows/sync-content-to-repo.yml new file mode 100644 index 000000000000..8b39a7d714f6 --- /dev/null +++ b/.github/workflows/sync-content-to-repo.yml @@ -0,0 +1,66 @@ +name: Sync Content to Repo + +on: + workflow_dispatch: + inputs: + roadmap_slug: + description: "The ID of the roadmap to sync" + required: true + default: "__default__" + +jobs: + sync-content: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup pnpm@v9 + uses: pnpm/action-setup@v4 + with: + version: 9 + run_install: false + + - name: Setup Node.js Version 20 (LTS) + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Install Dependencies and Sync Content + run: | + echo "Installing Dependencies" + pnpm install + echo "Syncing Content to Repo" + npm run sync:content-to-repo -- --roadmap-slug=${{ inputs.roadmap_slug }} --secret=${{ secrets.GH_SYNC_SECRET }} + + - name: Check for changes + id: verify-changed-files + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "changed=true" >> $GITHUB_OUTPUT + else + echo "changed=false" >> $GITHUB_OUTPUT + fi + + - name: Create PR + if: steps.verify-changed-files.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v7 + with: + delete-branch: false + branch: "chore/sync-content-to-repo-${{ inputs.roadmap_slug }}" + base: "master" + labels: | + automated pr + reviewers: jcanalesluna,kamranahmedse + commit-message: "chore: sync content to repo" + title: "chore: sync content to repository - ${{ inputs.roadmap_slug }}" + body: | + ## Sync Content to Repo + + > [!IMPORTANT] + > This PR Syncs the Content to the Repo for the Roadmap: ${{ inputs.roadmap_slug }} + > + > Commit: ${{ github.sha }} + > Workflow Path: ${{ github.workflow_ref }} + + **Please Review the Changes and Merge the PR if everything is fine.** diff --git a/.github/workflows/sync-repo-to-database.yml b/.github/workflows/sync-repo-to-database.yml new file mode 100644 index 000000000000..1355646411b3 --- /dev/null +++ b/.github/workflows/sync-repo-to-database.yml @@ -0,0 +1,57 @@ +name: Sync Repo to Database + +on: + workflow_dispatch: + inputs: + roadmap_slug: + description: "The slug of the roadmap to sync (e.g., frontend, backend)" + required: true + +jobs: + sync-roadmap: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup pnpm@v9 + uses: pnpm/action-setup@v4 + with: + version: 9 + run_install: false + + - name: Setup Node.js Version 20 (LTS) + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Get all roadmap files + id: roadmap-files + run: | + ROADMAP_DIR="src/data/roadmaps/${{ inputs.roadmap_slug }}" + + if [ ! -d "$ROADMAP_DIR" ]; then + echo "Error: Roadmap directory '$ROADMAP_DIR' does not exist" + exit 1 + fi + + echo "Getting all files in $ROADMAP_DIR" + + ALL_FILES=$(find "$ROADMAP_DIR" -type f | tr '\n' ',') + + echo "Files to sync:" + echo "$ALL_FILES" + + echo "files=$ALL_FILES" >> $GITHUB_OUTPUT + + - name: Install Dependencies + run: | + echo "Installing Dependencies" + pnpm install + + - name: Run sync script + run: | + echo "Running sync script for roadmap: ${{ inputs.roadmap_slug }}" + echo "Files: ${{ steps.roadmap-files.outputs.files }}" + + npm run sync:repo-to-database -- --files="${{ steps.roadmap-files.outputs.files }}" --secret=${{ secrets.GH_SYNC_SECRET }} diff --git a/.github/workflows/upgrade-dependencies.yml b/.github/workflows/upgrade-dependencies.yml new file mode 100644 index 000000000000..339ae5214d2b --- /dev/null +++ b/.github/workflows/upgrade-dependencies.yml @@ -0,0 +1,51 @@ +name: Upgrade Dependencies + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * 0' + +jobs: + upgrade-deps: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js Version 20 (LTS) + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup pnpm@v9 + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Install & Upgrade Dependencies + run: | + pnpm install + npm run upgrade + pnpm install --lockfile-only + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + delete-branch: false + branch: "update-deps" + base: "master" + labels: | + dependencies + automated pr + reviewers: kamranahmedse + commit-message: "chore: update dependencies to latest" + title: "Upgrade Dependencies To Latest - Automated" + body: | + ## Updated all Dependencies to Latest Versions. + + > [!IMPORTANT] + > This PR Upgrades the Dependencies to the their latest versions. + > + > Commit: ${{ github.sha }} + > Workflow Path: ${{ github.workflow_ref }} + + **Please Review the Changes and Merge the PR if everything is fine.** \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..d301d3cdf289 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +.idea +.temp +.astro + +# build output +dist/ +.output/ + +# dependencies +node_modules/ + +scripts/developer-roadmap + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store +/test-results/ +/playwright-report/ +/playwright/.cache/ +tests-examples +*.csveditor/ + +packages/editor \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000000..8051a481eac8 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +auto-install-peers=true +strict-peer-dependencies=false \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000000..fcfe9d86d381 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +app-dist +dist +.idea +.github +public +node_modules +pnpm-lock.yaml diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 000000000000..d19eee95c721 --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,18 @@ +module.exports = { + semi: true, + singleQuote: true, + overrides: [ + { + files: '*.astro', + options: { + parser: 'astro', + singleQuote: true, + jsxSingleQuote: true, + }, + }, + ], + plugins: [ + require.resolve('prettier-plugin-astro'), + 'prettier-plugin-tailwindcss', + ], +}; diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000000..22a15055d638 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode"], + "unwantedRecommendations": [] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000000..d6422097621f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..6827afd401ec --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "prettier.documentSelectors": ["**/*.astro"], + "[astro]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "tailwindCSS.experimental.classRegex": [ + ["\\b\\w+[cC]lassName\\s*=\\s*[\"']([^\"']*)[\"']"], + ["\\b\\w+[cC]lassName\\s*=\\s*`([^`]*)`"], + ["[\\w]+[cC]lassName[\"']?\\s*:\\s*[\"']([^\"']*)[\"']"], + ["[\\w]+[cC]lassName[\"']?\\s*:\\s*`([^`]*)`"], + ["cva\\(((?:[^()]|\\([^()]*\\))*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], + ["cx\\(((?:[^()]|\\([^()]*\\))*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] + ] +} diff --git a/README.md b/README.md deleted file mode 100644 index 8771e861a757..000000000000 --- a/README.md +++ /dev/null @@ -1,63 +0,0 @@ -![Web Developer Roadmap](http://i.imgur.com/GyvcunJ.png) - -> Roadmap to becoming a web developer in 2017 - -Below you find a set of charts demonstrating the paths that you can take and the technologies that you would want to adopt in order to become a frontend, backend or a devops. I made these charts for an old professor of mine who wanted something to share with his college students to give them a perspective. - -If you think that these can be improved in anyway, please do suggest. - -*** - -

Did you like this guide and want more of the similar content?
We are releasing Hugobots soon. Make sure to subscribe!

- -*** - - -## 🚀 Introduction - -![](https://i.imgur.com/MWkeM18.png) - -## 🎨 Front-end Roadmap - -![](https://i.imgur.com/qx54HvK.png) - -## 👽 Back-end Roadmap - -For the backend, personally I would prefer Node.js and PHP 7 for the full time. Plus, I have been experimenting lately with Go and I quite like it. Apart from these, if I have to choose another one, I would go for Ruby. However this is just my personal preference, you can choose any of the shown languages and you will be good. - -![](https://i.imgur.com/jz4xrlQ.png) - -## 👷 DevOps Roadmap - -![](https://i.imgur.com/z23zTH3.png) - -
- -## 🚦 Wrap Up - -If you think any of the roadmaps can be improved, please do open a PR with any updates and submit any issues. Also, I will continue to improve this, so you might want to watch/star this repository to revisit. - -## ☑ TODO - -- [X] Add Frontend Roadmap -- [X] Add Backend Roadmap -- [X] Add DevOps Roadmap -- [ ] Add relevant resources for each - -## 👬 Contribution - -The roadmaps are built using [Balsamiq](https://balsamiq.com/products/mockups/). Project file can be found at `/project-files` directory. To modify any of the roadmaps, open Balsamiq, click **Project > Import > Mockup JSON**, it will open the roadmap for you, update it, upload and update the images in readme and create a PR. - -- Open pull request with improvements -- Discuss ideas in issues -- Spread the word -- Reach out to me directly at kamranahmed.se@gmail.com or [![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/kamranahmedse.svg?style=social&label=Follow%20%40kamranahmedse)](https://twitter.com/kamranahmedse) - -## Sponsored By - -- [Hackr.io - Find & Share the Best Online Programming Courses & Tutorials](https://hackr.io) -- [FancyGrid - JavaScript grid library with charts integration and server communication.](http://fancygrid.com) - -## License - -[![License: CC BY 4.0](https://img.shields.io/badge/License-CC%20BY%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by/4.0/) diff --git a/astro.config.mjs b/astro.config.mjs new file mode 100644 index 000000000000..ecd628f5dce2 --- /dev/null +++ b/astro.config.mjs @@ -0,0 +1,98 @@ +// https://astro.build/config +import sitemap from '@astrojs/sitemap'; +import node from '@astrojs/node'; +import { defineConfig } from 'astro/config'; +import rehypeExternalLinks from 'rehype-external-links'; +import { serializeSitemap, shouldIndexPage } from './sitemap.mjs'; +import tailwindcss from '@tailwindcss/vite'; + +import react from '@astrojs/react'; + +// https://astro.build/config +export default defineConfig({ + site: 'https://roadmap.sh/', + redirects: { + '/devops/devops-engineer': { + status: 301, + destination: '/devops', + }, + '/ai-tutor': { + status: 301, + destination: '/ai', + }, + '/best-practices': { + status: 301, + destination: '/roadmaps', + }, + '/best-practices/aws': { + status: 301, + destination: '/aws-best-practices', + }, + '/best-practices/backend-performance': { + status: 301, + destination: '/backend-performance-best-practices', + }, + '/best-practices/frontend-performance': { + status: 301, + destination: '/frontend-performance-best-practices', + }, + '/best-practices/api-security': { + status: 301, + destination: '/api-security-best-practices', + }, + '/best-practices/code-review': { + status: 301, + destination: '/code-review-best-practices', + }, + }, + markdown: { + shikiConfig: { + theme: 'dracula', + }, + rehypePlugins: [ + [ + rehypeExternalLinks, + { + target: '_blank', + rel: function (element) { + const href = element.properties.href; + const whiteListedStarts = [ + '/', + '#', + 'mailto:', + 'https://github.com/kamranahmedse', + 'https://thenewstack.io', + 'https://kamranahmed.info', + 'https://roadmap.sh', + ]; + if (whiteListedStarts.some((start) => href.startsWith(start))) { + return []; + } + return 'noopener noreferrer nofollow'; + }, + }, + ], + ], + }, + output: 'server', + adapter: node({ + mode: 'standalone', + }), + trailingSlash: 'never', + integrations: [ + sitemap({ + filter: shouldIndexPage, + serialize: serializeSitemap, + }), + react(), + ], + vite: { + plugins: [tailwindcss()], + ssr: { + noExternal: [/^@roadmapsh\/editor.*$/], + }, + server: { + allowedHosts: ['roadmap.sh', 'port3k.kamranahmed.info'], + }, + }, +}); diff --git a/code_of_conduct.md b/code_of_conduct.md new file mode 100644 index 000000000000..73f0f7e88ec7 --- /dev/null +++ b/code_of_conduct.md @@ -0,0 +1,76 @@ +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/contributing.md b/contributing.md new file mode 100644 index 000000000000..1e3f480afdd7 --- /dev/null +++ b/contributing.md @@ -0,0 +1,150 @@ +# ✨ Contribution Guidelines ✨ + +First of all, thank you for considering to contribute. Please look at the details below: + +- [New Roadmaps](#new-roadmaps) +- [Existing Roadmaps](#existing-roadmaps) +- [Adding Projects](#adding-projects) +- [Adding Content](#adding-content) + - [How To Structure Content](#how-to-structure-content) +- [Guidelines](#guidelines) +- [Good vs. Not So Good Contributions](#good-vs-not-so-good-contributions) +- [Local Development](#local-development) + +## New Roadmaps + +For new roadmaps, you can either: + +- Submit a roadmap by providing [a textual roadmap similar to this roadmap](https://gist.github.com/kamranahmedse/98758d2c73799b3a6ce17385e4c548a5) in an [issue](https://github.com/kamranahmedse/developer-roadmap/issues). +- Create an interactive roadmap yourself using [our roadmap editor](https://draw.roadmap.sh/) & submit the link to that roadmap in an [issue](https://github.com/kamranahmedse/developer-roadmap/issues). + +## Existing Roadmaps + +For the existing roadmaps, please follow the details listed for the nature of contribution: + +- **Fixing Typos** — Make your changes in the [roadmap markdown file](https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/roadmaps) and submit a [PR](https://github.com/kamranahmedse/developer-roadmap/pulls). +- **Adding/Removing Nodes and Modifying Node Titles** — Please open an [issue](https://github.com/kamranahmedse/developer-roadmap/issues) with your suggestion. + +**Note:** Please note that our goal is **not to have the biggest list of items**. Our goal is to list items or skills most relevant today. + +## Adding Projects + +If you have a project idea that you think we should add to the roadmap, feel free to open an issue with as many details about the project as possible and the roadmap you think it should be added to. + +The detailed format for the issue should be as follows: + +```md +## What is this project about? + +(Add an introduction to the project.) + +## Skills this Project Covers + +(Comma separated list of skills, e.g. Programming Knowledge, Database, etc.) + +## Requirements + +( Detailed list of requirements, i.e. input, output, hints to help build this, etc.) +``` + +Have a look at this project to get an idea of [what we are looking for](https://roadmap.sh/projects/github-user-activity). + +## Adding Content + +Find [the content directory inside the relevant roadmap](https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/roadmaps). Please keep the following guidelines in mind when submitting content: + +- Content must be in English. +- Maximum of 8 links per topic. +- **No GeeksforGeeks links** — Links to geeksforgeeks.org are not accepted. +- Follow the below style guide for content. + +Please note that we are intentionally keeping the content under the topic popup concise. You MUST always aim to explain the topic simply in a **single paragraph** or so and provide external resources where users can learn more about the topic. + +### How To Structure Content + +Please adhere to the following style when adding content to a topic: + +```md +# Topic Title + +(Content) + +Visit the following resources to learn more: + +- [@type@Title/Description of Link](Link) +``` + +`@type@` must be one of the following and describe the type of content you are adding: + +- `@official@` +- `@opensource@` +- `@article@` +- `@course@` +- `@podcast@` +- `@video@` +- `@book@` + +It's important to add a valid type, this will help us categorize the content and display it properly on the roadmap. The order of the links based on type is same as above. + +## Guidelines + +-

Please don't use the project for self-promotion!
+ + We believe this project is a valuable asset to the developer community, and it includes numerous helpful resources. We kindly ask you to avoid submitting pull requests for the sole purpose of self-promotion. We appreciate contributions that genuinely add value, such as guides from maintainers of well-known frameworks, and will consider accepting these even if they're self authored. Thank you for your understanding and cooperation! + +-

Adding everything available out there is not the goal!
+ + The roadmaps represent the skillset most valuable today, i.e., if you were to enter any of the listed fields today, what would you learn? There might be things that are of-course being used today, but prioritize the things that are most in demand today, e.g., agree that lots of people are using angular.js today, but you wouldn't want to learn that instead of React, Angular, or Vue. Use your critical thinking to filter out non-essential stuff. Give honest arguments for why the resource should be included.

+ +-

Do not add things you have not evaluated personally!
+ + Use your critical thinking to filter out non-essential stuff. Give honest arguments for why the resource should be included. Have you read this book? Can you give a short article?

+ +-

Create a Single PR for Content Additions

+ + If you are planning to contribute by adding content to the roadmaps, I recommend you to clone the repository, add content to the [content directory of the roadmap](./src/data/roadmaps/) and create a single PR to make it easier for me to review and merge the PR. + +-

Write meaningful commit messages
+ + Meaningful commit messages help speed up the review process as well as help other contributors gain a good overview of the repositories commit history without having to dive into every commit. + +

+-

Look at the existing issues/pull requests before opening new ones

+ +## Good vs. Not So Good Contributions + +Good + +- New Roadmaps. +- Engaging and fresh content links. +- Typos and grammatical fixes. +- Enhanced Existing Content. +- Content copy in topics that do not have any (or minimal copy exists). + +Not So Good + +- Adding whitespace that doesn't add to the readability of the content. +- Rewriting content in a way that doesn't add any value. +- Non-English content. +- PR's that don't follow our style guide, have no description, and a default title. +- Links to your own blog articles. + +## Local Development + +For local development, you can use the following commands: + +```bash +git clone git@github.com:kamranahmedse/developer-roadmap.git --depth 1 +cd developer-roadmap +pnpm add @roadmapsh/editor@npm:@roadmapsh/dummy-editor -w +pnpm install +``` +Run the development server with: + +```bash +pnpm dev +``` + +*** + +Have a look at the [License](./license) file. diff --git a/license b/license new file mode 100644 index 000000000000..e90d2561bfa4 --- /dev/null +++ b/license @@ -0,0 +1,12 @@ +Everything including text and images in this project are protected by the copyright laws. +You are allowed to use this material for personal use but are not allowed to use it for +any other purpose including publishing the images, the project files or the content in +the images in any form either digital, non-digital, textual, graphical or written formats. +You are allowed to share the links to the repository or the website roadmap.sh but not +the content for any sort of usage that involves the content of this repository taken out +of the repository and be shared from any other medium including but not limited to blog +posts, articles, newsletters, you must get prior consent from the understated. These +conditions do not apply to the readonly GitHub forks created using the Fork button on +GitHub with the whole purpose of contributing to the project. + +Copyright © 2017 - Present. Kamran Ahmed diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000000..64936bd1062d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9512 @@ +{ + "name": "roadmap.sh", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "roadmap.sh", + "version": "1.0.0", + "dependencies": { + "@astrojs/node": "^8.3.3", + "@astrojs/react": "^3.6.2", + "@astrojs/sitemap": "^3.1.6", + "@astrojs/tailwind": "^5.1.0", + "@fingerprintjs/fingerprintjs": "^4.4.3", + "@nanostores/react": "^0.7.2", + "@napi-rs/image": "^1.9.2", + "@resvg/resvg-js": "^2.6.2", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "astro": "^4.15.4", + "clsx": "^2.1.1", + "dayjs": "^1.11.12", + "dom-to-image": "^2.6.0", + "dracula-prism": "^2.1.16", + "gray-matter": "^4.0.3", + "htm": "^3.1.1", + "image-size": "^1.1.1", + "jose": "^5.6.3", + "js-cookie": "^3.0.5", + "lucide-react": "^0.419.0", + "luxon": "^3.5.0", + "nanoid": "^5.0.7", + "nanostores": "^0.10.3", + "node-html-parser": "^6.1.13", + "npm-check-updates": "^17.0.0", + "playwright": "^1.47.1", + "prismjs": "^1.29.0", + "react": "^18.3.1", + "react-calendar-heatmap": "^1.9.0", + "react-confetti": "^6.1.0", + "react-dom": "^18.3.1", + "react-slick": "^0.30.2", + "react-tooltip": "^5.27.1", + "reactflow": "^11.11.4", + "rehype-external-links": "^3.0.0", + "remark-parse": "^11.0.0", + "roadmap-renderer": "^1.0.6", + "satori": "^0.10.14", + "satori-html": "^0.3.2", + "sharp": "^0.33.4", + "slick-carousel": "^1.8.1", + "slugify": "^1.6.6", + "tailwind-merge": "^2.4.0", + "tailwindcss": "^3.4.7", + "turndown": "^7.2.0", + "unified": "^11.0.5", + "zustand": "^4.5.4" + }, + "devDependencies": { + "@playwright/test": "^1.45.3", + "@tailwindcss/typography": "^0.5.13", + "@types/dom-to-image": "^2.6.7", + "@types/js-cookie": "^3.0.6", + "@types/luxon": "^3.4.2", + "@types/prismjs": "^1.26.4", + "@types/react-calendar-heatmap": "^1.6.7", + "@types/react-slick": "^0.23.13", + "@types/turndown": "^5.0.5", + "csv-parser": "^3.0.0", + "gh-pages": "^6.1.1", + "js-yaml": "^4.1.0", + "markdown-it": "^14.1.0", + "openai": "^4.53.2", + "prettier": "^3.3.3", + "prettier-plugin-astro": "^0.14.1", + "prettier-plugin-tailwindcss": "^0.6.5", + "tsx": "^4.16.5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@astrojs/compiler": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.10.3.tgz", + "integrity": "sha512-bL/O7YBxsFt55YHU021oL+xz+B/9HvGNId3F9xURN16aeqDK9juHGktdkCSXz+U4nqFACq6ZFvWomOzhV+zfPw==" + }, + "node_modules/@astrojs/internal-helpers": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.4.1.tgz", + "integrity": "sha512-bMf9jFihO8YP940uD70SI/RDzIhUHJAolWVcO1v5PUivxGKvfLZTLTVVxEYzGYyPsA3ivdLNqMnL5VgmQySa+g==" + }, + "node_modules/@astrojs/markdown-remark": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-5.2.0.tgz", + "integrity": "sha512-vWGM24KZXz11jR3JO+oqYU3T2qpuOi4uGivJ9SQLCAI01+vEkHC60YJMRvHPc+hwd60F7euNs1PeOEixIIiNQw==", + "dependencies": { + "@astrojs/prism": "3.1.0", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.1", + "hast-util-to-text": "^4.0.2", + "import-meta-resolve": "^4.1.0", + "mdast-util-definitions": "^6.0.0", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.0", + "remark-gfm": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.0", + "remark-smartypants": "^3.0.2", + "shiki": "^1.10.3", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.1", + "vfile": "^6.0.2" + } + }, + "node_modules/@astrojs/node": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/@astrojs/node/-/node-8.3.3.tgz", + "integrity": "sha512-idrKhnnPSi0ABV+PCQsRQqVNwpOvVDF/+fkwcIiE8sr9J8EMvW9g/oyAt8T4X2OBJ8FUzYPL8klfCdG7r0eB5g==", + "dependencies": { + "send": "^0.18.0", + "server-destroy": "^1.0.1" + }, + "peerDependencies": { + "astro": "^4.2.0" + } + }, + "node_modules/@astrojs/prism": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.1.0.tgz", + "integrity": "sha512-Z9IYjuXSArkAUx3N6xj6+Bnvx8OdUSHA8YoOgyepp3+zJmtVYJIl/I18GozdJVW1p5u/CNpl3Km7/gwTJK85cw==", + "dependencies": { + "prismjs": "^1.29.0" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" + } + }, + "node_modules/@astrojs/react": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-3.6.2.tgz", + "integrity": "sha512-fK29lYI7zK/KG4ZBy956x4dmauZcZ18osFkuyGa8r3gmmCQa2NZ9XNu9WaVYEUm0j89f4Gii4tbxLoyM8nk2MA==", + "dependencies": { + "@vitejs/plugin-react": "^4.3.1", + "ultrahtml": "^1.5.3" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" + }, + "peerDependencies": { + "@types/react": "^17.0.50 || ^18.0.21", + "@types/react-dom": "^17.0.17 || ^18.0.6", + "react": "^17.0.2 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-beta" + } + }, + "node_modules/@astrojs/sitemap": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.1.6.tgz", + "integrity": "sha512-1Qp2NvAzVImqA6y+LubKi1DVhve/hXXgFvB0szxiipzh7BvtuKe4oJJ9dXSqaubaTkt4nMa6dv6RCCAYeB6xaQ==", + "dependencies": { + "sitemap": "^7.1.2", + "stream-replace-string": "^2.0.0", + "zod": "^3.23.8" + } + }, + "node_modules/@astrojs/tailwind": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/tailwind/-/tailwind-5.1.0.tgz", + "integrity": "sha512-BJoCDKuWhU9FT2qYg+fr6Nfb3qP4ShtyjXGHKA/4mHN94z7BGcmauQK23iy+YH5qWvTnhqkd6mQPQ1yTZTe9Ig==", + "dependencies": { + "autoprefixer": "^10.4.15", + "postcss": "^8.4.28", + "postcss-load-config": "^4.0.2" + }, + "peerDependencies": { + "astro": "^3.0.0 || ^4.0.0", + "tailwindcss": "^3.0.24" + } + }, + "node_modules/@astrojs/telemetry": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.1.0.tgz", + "integrity": "sha512-/ca/+D8MIKEC8/A9cSaPUqQNZm+Es/ZinRv0ZAzvu2ios7POQSsVD+VOj7/hypWNsNM3T7RpfgNq7H2TU1KEHA==", + "dependencies": { + "ci-info": "^4.0.0", + "debug": "^4.3.4", + "dlv": "^1.1.3", + "dset": "^3.1.3", + "is-docker": "^3.0.0", + "is-wsl": "^3.0.0", + "which-pm-runs": "^1.1.0" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "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.25.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", + "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", + "dependencies": { + "@babel/types": "^7.25.4", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", + "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", + "dependencies": { + "@babel/types": "^7.25.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.2.tgz", + "integrity": "sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz", + "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz", + "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", + "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.4", + "@babel/parser": "^7.25.4", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.4", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.2.0.tgz", + "integrity": "sha512-E7Vgw78I93we4ZWdYCb4DGAwRROGkMIXk7/y87UmANR+J6qsWusmC3gLt0H+O0KOt5e6O38U8oJamgbudrES/w==", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", + "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", + "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fingerprintjs/fingerprintjs": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-4.4.3.tgz", + "integrity": "sha512-sm0ZmDp5Oeq8hQTf+bAHKsuuteVAYme/YOY9UPP/GrUBrR5Fzl1P5oOv6F5LvyBrO7qLjU5HQkfU0MmFte/8xA==", + "dependencies": { + "tslib": "^2.4.1" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz", + "integrity": "sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==", + "dependencies": { + "@floating-ui/utils": "^0.2.4" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz", + "integrity": "sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.4" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", + "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", + "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=11", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz", + "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=10.13", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz", + "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz", + "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz", + "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz", + "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz", + "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz", + "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", + "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", + "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", + "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.31", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", + "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", + "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", + "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", + "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.1.1" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", + "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", + "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==" + }, + "node_modules/@nanostores/react": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@nanostores/react/-/react-0.7.2.tgz", + "integrity": "sha512-e3OhHJFv3NMSFYDgREdlAQqkyBTHJM91s31kOZ4OvZwJKdFk5BLk0MLbh51EOGUz9QGX2aCHfy1RvweSi7fgwA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "nanostores": "^0.9.0 || ^0.10.0", + "react": ">=18.0.0" + } + }, + "node_modules/@napi-rs/image": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image/-/image-1.9.2.tgz", + "integrity": "sha512-CvTC3XL5/BzHaVkJOZy31xOJLNSY3rBuUIQixaE/LwEQNSUdaxWa9gUyUkC9lUekkUp26CzaLLj2w7l7bxB1ag==", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/image-android-arm64": "1.9.2", + "@napi-rs/image-darwin-arm64": "1.9.2", + "@napi-rs/image-darwin-x64": "1.9.2", + "@napi-rs/image-freebsd-x64": "1.9.2", + "@napi-rs/image-linux-arm-gnueabihf": "1.9.2", + "@napi-rs/image-linux-arm64-gnu": "1.9.2", + "@napi-rs/image-linux-arm64-musl": "1.9.2", + "@napi-rs/image-linux-x64-gnu": "1.9.2", + "@napi-rs/image-linux-x64-musl": "1.9.2", + "@napi-rs/image-wasm32-wasi": "1.9.2", + "@napi-rs/image-win32-ia32-msvc": "1.9.2", + "@napi-rs/image-win32-x64-msvc": "1.9.2" + } + }, + "node_modules/@napi-rs/image-android-arm64": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-android-arm64/-/image-android-arm64-1.9.2.tgz", + "integrity": "sha512-DQNI06ukKqpF4eogz9zyxfU+GYp11TfDqSNWKmk/IRU2oiB0DEgskuj7ZzaKMPJWFRZjI86V233UrrNRh76h2Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-darwin-arm64": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-darwin-arm64/-/image-darwin-arm64-1.9.2.tgz", + "integrity": "sha512-w+0X87sORbC2uDpH7NAdELOnvzhu3dB19h2oMaD+YIv/+CVXV5eK2PS3zkRgMLCinVtFOZFZK3dFbHU3kncCRw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-darwin-x64": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-darwin-x64/-/image-darwin-x64-1.9.2.tgz", + "integrity": "sha512-8SnFDcgUSoL6Y38lstXi5FYECD1f4dJqQe2UCTwciED8gZnpC8Pju7JYJWcYgHHXn1JnKP9T1lPlSaX+L56EgA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-freebsd-x64": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-freebsd-x64/-/image-freebsd-x64-1.9.2.tgz", + "integrity": "sha512-oS0+iSb8AekjaHgTZdARKceqTPxSokByLzNQ9vGf2lZlTwlRFmXGq4XYutyzqzRuLT3BATLwtGMXiguMEYMuUw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-linux-arm-gnueabihf": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-linux-arm-gnueabihf/-/image-linux-arm-gnueabihf-1.9.2.tgz", + "integrity": "sha512-bsbZSvw3wa7yaLVvz4M5VhJaB9LmgjAL3W7rnmXaX5BgpaQImNDm9MrxPG8ennr9Pbn6qDtCSioOz53ZgWUtgg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-linux-arm64-gnu": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-linux-arm64-gnu/-/image-linux-arm64-gnu-1.9.2.tgz", + "integrity": "sha512-tiN9RMwEIcA8TodvmxdeJqsRdUGKAmxQ2aa0FkYjshdkmChG/sqUtUoL9LdmDf1tw1IACrSuT2Wj4LevxBdIJA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-linux-arm64-musl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-linux-arm64-musl/-/image-linux-arm64-musl-1.9.2.tgz", + "integrity": "sha512-w6Sx1j9PtqO2bP3Jl6nuMryzxA3zsoc1U8u1H7AZketyhxXIxqVm0oGomZGs5Bgshzau45bcWinp6GWrlSwt6A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-linux-x64-gnu": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-linux-x64-gnu/-/image-linux-x64-gnu-1.9.2.tgz", + "integrity": "sha512-yB/s9wNB/9YHpQ4TwN8NWMA1tEK1gPLQwtysa68yMdHczb+7BTCKCIYIHD9rUulyT1Q/VgLIJCUMoxve0pIoeg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-linux-x64-musl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-linux-x64-musl/-/image-linux-x64-musl-1.9.2.tgz", + "integrity": "sha512-x9dRlo27xYXonh+gZZTqQL4lAfi/lhi8K8LE2hczbZffqmXvWU7NuHSgPVVeU/nvcMMqw1Cjzn81h7ny44SLbQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-wasm32-wasi": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-wasm32-wasi/-/image-wasm32-wasi-1.9.2.tgz", + "integrity": "sha512-BeA1wzzIG4+tdAwXWaAjObBOC6SzIbq0IhykSQ1xCGvYwd8stsn7ktPRz5b55PDo+Doj65PCT4H/xUgFcSiLCw==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@napi-rs/image-win32-ia32-msvc": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-win32-ia32-msvc/-/image-win32-ia32-msvc-1.9.2.tgz", + "integrity": "sha512-JDJP04Hg9Qru5Pth4gfBkXz9hZd/otx6ymi2VTuSKDFjpJIjk4tyUr9+BIE1ghFCHDzeJGVe7CDGdF/NTA1xrg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/image-win32-x64-msvc": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@napi-rs/image-win32-x64-msvc/-/image-win32-x64-msvc-1.9.2.tgz", + "integrity": "sha512-baRyTED6FkTsPliSOH7x8TV/cyAST9y6L1ClSgSCVEx7+W8MKKig90fF302kEa2PwMAyrXM3Ytq9KuIC7xJ+eA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", + "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.1.0", + "@emnapi/runtime": "^1.1.0", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@oslojs/encoding": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-0.4.1.tgz", + "integrity": "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q==" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@playwright/test": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.0.tgz", + "integrity": "sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w==", + "dev": true, + "dependencies": { + "playwright": "1.46.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@playwright/test/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/@playwright/test/node_modules/playwright": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.0.tgz", + "integrity": "sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==", + "dev": true, + "dependencies": { + "playwright-core": "1.46.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/@playwright/test/node_modules/playwright-core": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.0.tgz", + "integrity": "sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@reactflow/background": { + "version": "11.3.14", + "resolved": "https://registry.npmjs.org/@reactflow/background/-/background-11.3.14.tgz", + "integrity": "sha512-Gewd7blEVT5Lh6jqrvOgd4G6Qk17eGKQfsDXgyRSqM+CTwDqRldG2LsWN4sNeno6sbqVIC2fZ+rAUBFA9ZEUDA==", + "dependencies": { + "@reactflow/core": "11.11.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/controls": { + "version": "11.2.14", + "resolved": "https://registry.npmjs.org/@reactflow/controls/-/controls-11.2.14.tgz", + "integrity": "sha512-MiJp5VldFD7FrqaBNIrQ85dxChrG6ivuZ+dcFhPQUwOK3HfYgX2RHdBua+gx+40p5Vw5It3dVNp/my4Z3jF0dw==", + "dependencies": { + "@reactflow/core": "11.11.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/core": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@reactflow/core/-/core-11.11.4.tgz", + "integrity": "sha512-H4vODklsjAq3AMq6Np4LE12i1I4Ta9PrDHuBR9GmL8uzTt2l2jh4CiQbEMpvMDcp7xi4be0hgXj+Ysodde/i7Q==", + "dependencies": { + "@types/d3": "^7.4.0", + "@types/d3-drag": "^3.0.1", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/minimap": { + "version": "11.7.14", + "resolved": "https://registry.npmjs.org/@reactflow/minimap/-/minimap-11.7.14.tgz", + "integrity": "sha512-mpwLKKrEAofgFJdkhwR5UQ1JYWlcAAL/ZU/bctBkuNTT1yqV+y0buoNVImsRehVYhJwffSWeSHaBR5/GJjlCSQ==", + "dependencies": { + "@reactflow/core": "11.11.4", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-resizer": { + "version": "2.2.14", + "resolved": "https://registry.npmjs.org/@reactflow/node-resizer/-/node-resizer-2.2.14.tgz", + "integrity": "sha512-fwqnks83jUlYr6OHcdFEedumWKChTHRGw/kbCxj0oqBd+ekfs+SIp4ddyNU0pdx96JIm5iNFS0oNrmEiJbbSaA==", + "dependencies": { + "@reactflow/core": "11.11.4", + "classcat": "^5.0.4", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-toolbar": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@reactflow/node-toolbar/-/node-toolbar-1.3.14.tgz", + "integrity": "sha512-rbynXQnH/xFNu4P9H+hVqlEUafDCkEoCy0Dg9mG22Sg+rY/0ck6KkrAQrYrTgXusd+cEJOMK0uOOFCK2/5rSGQ==", + "dependencies": { + "@reactflow/core": "11.11.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@resvg/resvg-js": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.6.2.tgz", + "integrity": "sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@resvg/resvg-js-android-arm-eabi": "2.6.2", + "@resvg/resvg-js-android-arm64": "2.6.2", + "@resvg/resvg-js-darwin-arm64": "2.6.2", + "@resvg/resvg-js-darwin-x64": "2.6.2", + "@resvg/resvg-js-linux-arm-gnueabihf": "2.6.2", + "@resvg/resvg-js-linux-arm64-gnu": "2.6.2", + "@resvg/resvg-js-linux-arm64-musl": "2.6.2", + "@resvg/resvg-js-linux-x64-gnu": "2.6.2", + "@resvg/resvg-js-linux-x64-musl": "2.6.2", + "@resvg/resvg-js-win32-arm64-msvc": "2.6.2", + "@resvg/resvg-js-win32-ia32-msvc": "2.6.2", + "@resvg/resvg-js-win32-x64-msvc": "2.6.2" + } + }, + "node_modules/@resvg/resvg-js-android-arm-eabi": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.2.tgz", + "integrity": "sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-android-arm64": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.2.tgz", + "integrity": "sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-darwin-arm64": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.2.tgz", + "integrity": "sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-darwin-x64": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.2.tgz", + "integrity": "sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm-gnueabihf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.2.tgz", + "integrity": "sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm64-gnu": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.2.tgz", + "integrity": "sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm64-musl": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.2.tgz", + "integrity": "sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-x64-gnu": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.2.tgz", + "integrity": "sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-x64-musl": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.2.tgz", + "integrity": "sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-arm64-msvc": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.2.tgz", + "integrity": "sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-ia32-msvc": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.2.tgz", + "integrity": "sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-x64-msvc": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.2.tgz", + "integrity": "sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz", + "integrity": "sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz", + "integrity": "sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz", + "integrity": "sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz", + "integrity": "sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz", + "integrity": "sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz", + "integrity": "sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz", + "integrity": "sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz", + "integrity": "sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz", + "integrity": "sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz", + "integrity": "sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz", + "integrity": "sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz", + "integrity": "sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz", + "integrity": "sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz", + "integrity": "sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz", + "integrity": "sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz", + "integrity": "sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.16.3.tgz", + "integrity": "sha512-yETIvrETCeC39gSPIiSADmjri9FwKmxz0QvONMtTIUYlKZe90CJkvcjPksayC2VQOtzOJonEiULUa8v8crUQvA==", + "dependencies": { + "@shikijs/vscode-textmate": "^9.2.0", + "@types/hast": "^3.0.4", + "oniguruma-to-js": "0.3.3", + "regex": "4.3.2" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.2.2.tgz", + "integrity": "sha512-TMp15K+GGYrWlZM8+Lnj9EaHEFmOen0WJBrfa17hF7taDOYthuPPV0GWzfd/9iMij0akS/8Yw2ikquH7uVi/fg==" + }, + "node_modules/@shuding/opentype.js": { + "version": "1.4.0-beta.0", + "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", + "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==", + "dependencies": { + "fflate": "^0.7.3", + "string.prototype.codepointat": "^0.2.1" + }, + "bin": { + "ot": "bin/ot" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.13.tgz", + "integrity": "sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==", + "dev": true, + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", + "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "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==", + "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.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "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==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz", + "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", + "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/dom-to-image": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/@types/dom-to-image/-/dom-to-image-2.6.7.tgz", + "integrity": "sha512-me5VbCv+fcXozblWwG13krNBvuEOm6kA5xoa4RrjDJCNFOZSWR3/QLtOXimBHk1Fisq69Gx3JtOoXtg1N1tijg==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/geojson": { + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", + "dev": true + }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==", + "dev": true + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/node": { + "version": "18.19.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.41.tgz", + "integrity": "sha512-LX84pRJ+evD2e2nrgYCHObGWkiQJ1mL+meAgbvnwk/US6vmMY7S2ygBTGV2Jw91s9vUsLSXeDEkUHZIJGLrhsg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/prismjs": { + "version": "1.26.4", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.4.tgz", + "integrity": "sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-calendar-heatmap": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/react-calendar-heatmap/-/react-calendar-heatmap-1.6.7.tgz", + "integrity": "sha512-xWBS9iOvw+aCidPk8QwCH69OCO7jnj6/9TjooqGQ9W+rA5m1aw36GjQMlSYKAg86otDeg9dzA+hSAIcvw/y9Rg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-slick": { + "version": "0.23.13", + "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.13.tgz", + "integrity": "sha512-bNZfDhe/L8t5OQzIyhrRhBr/61pfBcWaYJoq6UDqFtv5LMwfg4NsVDD2J8N01JqdAdxLjOt66OZEp6PX+dGs/A==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/turndown": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.5.tgz", + "integrity": "sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==", + "dev": true + }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", + "integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==", + "dependencies": { + "@babel/core": "^7.24.5", + "@babel/plugin-transform-react-jsx-self": "^7.24.5", + "@babel/plugin-transform-react-jsx-source": "^7.24.1", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/astro": { + "version": "4.15.4", + "resolved": "https://registry.npmjs.org/astro/-/astro-4.15.4.tgz", + "integrity": "sha512-wqy+m3qygt9DmCSqMsckxyK4ccCUFtti2d/WlLkEpAlqHgyDIg20zRTLHO2v/H4YeSlJ8sAcN0RW2FhOeYbINg==", + "dependencies": { + "@astrojs/compiler": "^2.10.3", + "@astrojs/internal-helpers": "0.4.1", + "@astrojs/markdown-remark": "5.2.0", + "@astrojs/telemetry": "3.1.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-react-jsx": "^7.25.2", + "@babel/types": "^7.25.6", + "@oslojs/encoding": "^0.4.1", + "@rollup/pluginutils": "^5.1.0", + "@types/babel__core": "^7.20.5", + "@types/cookie": "^0.6.0", + "acorn": "^8.12.1", + "aria-query": "^5.3.0", + "axobject-query": "^4.1.0", + "boxen": "7.1.1", + "ci-info": "^4.0.0", + "clsx": "^2.1.1", + "common-ancestor-path": "^1.0.1", + "cookie": "^0.6.0", + "cssesc": "^3.0.0", + "debug": "^4.3.6", + "deterministic-object-hash": "^2.0.2", + "devalue": "^5.0.0", + "diff": "^5.2.0", + "dlv": "^1.1.3", + "dset": "^3.1.3", + "es-module-lexer": "^1.5.4", + "esbuild": "^0.21.5", + "estree-walker": "^3.0.3", + "fast-glob": "^3.3.2", + "fastq": "^1.17.1", + "flattie": "^1.1.1", + "github-slugger": "^2.0.0", + "gray-matter": "^4.0.3", + "html-escaper": "^3.0.3", + "http-cache-semantics": "^4.1.1", + "js-yaml": "^4.1.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.11", + "magicast": "^0.3.5", + "micromatch": "^4.0.8", + "mrmime": "^2.0.0", + "neotraverse": "^0.6.18", + "ora": "^8.1.0", + "p-limit": "^6.1.0", + "p-queue": "^8.0.1", + "path-to-regexp": "^6.2.2", + "preferred-pm": "^4.0.0", + "prompts": "^2.4.2", + "rehype": "^13.0.1", + "semver": "^7.6.3", + "shiki": "^1.16.1", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "tinyexec": "^0.3.0", + "tsconfck": "^3.1.3", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.3", + "vite": "^5.4.2", + "vitefu": "^1.0.2", + "which-pm": "^3.0.0", + "xxhash-wasm": "^1.0.2", + "yargs-parser": "^21.1.1", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.23.2", + "zod-to-ts": "^1.2.0" + }, + "bin": { + "astro": "astro.js" + }, + "engines": { + "node": "^18.17.1 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" + }, + "optionalDependencies": { + "sharp": "^0.33.3" + } + }, + "node_modules/astro/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base-64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==" + }, + "node_modules/base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/boxen/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "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" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "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" + } + ] + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", + "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/classcat": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", + "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==" + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "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==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-background-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz", + "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==" + }, + "node_modules/css-box-shadow": { + "version": "1.0.0-3", + "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz", + "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==" + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/csv-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/csv-parser/-/csv-parser-3.0.0.tgz", + "integrity": "sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "csv-parser": "bin/csv-parser" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dayjs": { + "version": "1.11.12", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", + "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==" + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/deterministic-object-hash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", + "integrity": "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==", + "dependencies": { + "base-64": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/devalue": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.0.0.tgz", + "integrity": "sha512-gO+/OMXF7488D+u3ue+G7Y4AA3ZmUnB3eHJXmBTgNHvr4ZNzl36A0ZtG+XCRNYCkYx/bFmw4qtkoFLa+wSrwAA==" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-to-image": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/dom-to-image/-/dom-to-image-2.6.0.tgz", + "integrity": "sha512-Dt0QdaHmLpjURjU7Tnu3AgYSF2LuOmksSGsUcE6ItvJoCWTBEmiMXcqBdNSAm9+QbbwD7JMoVsuuKX6ZVQv1qA==" + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dracula-prism": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/dracula-prism/-/dracula-prism-2.1.16.tgz", + "integrity": "sha512-fNZU8sMYOFYq/K8WFtsVUJEHemYlQJy7E3wm+Lndp3hTWG+Hp3+sCcbQdWVvQTfw+xIJeI+mIrjfUWHb9Q/s2Q==" + }, + "node_modules/dset": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", + "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.830", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.830.tgz", + "integrity": "sha512-TrPKKH20HeN0J1LHzsYLs2qwXrp8TF4nHdu4sq61ozGbzMpWhI7iIOPYPPkxeq1azMT9PZ8enPFcftbs/Npcjg==" + }, + "node_modules/email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/enquire.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz", + "integrity": "sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw==" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fflate": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", + "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==" + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", + "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "dependencies": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "node_modules/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "dev": true + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dev": true, + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/formdata-node/node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", + "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/gh-pages": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.1.1.tgz", + "integrity": "sha512-upnohfjBwN5hBP9w2dPE7HO5JJTHzSGMV1JrLrHvNuqmjoYHg6TBrCcnEoorjG/e0ejbuvnwyKMdTyM40PEByw==", + "dev": true, + "dependencies": { + "async": "^3.2.4", + "commander": "^11.0.0", + "email-addresses": "^5.0.0", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^11.1.1", + "globby": "^6.1.0" + }, + "bin": { + "gh-pages": "bin/gh-pages.js", + "gh-pages-clean": "bin/gh-pages-clean.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gray-matter/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz", + "integrity": "sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.4.tgz", + "integrity": "sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.1.tgz", + "integrity": "sha512-hZOofyZANbyWo+9RP75xIDV/gq+OUKx+T46IlwERnKmfpwp81XBFbT9mi26ws+SJchA4RVUQwIBJpqEOBhMzEQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-raw": "^9.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hex-rgb": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz", + "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/htm": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/htm/-/htm-3.1.1.tgz", + "integrity": "sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==" + }, + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/image-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", + "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", + "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jose": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.6.3.tgz", + "integrity": "sha512-1Jh//hEEwMhNYPDDLwXHa2ePWgWiFNNUadVmguAAw2IJ6sj9mNxV5tGXJNqlMkJAybF6Lgw1mISDxTePP/187g==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "peer": true + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "engines": { + "node": ">=14" + } + }, + "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==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "dependencies": { + "string-convert": "^0.2.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/linebreak": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", + "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", + "dependencies": { + "base64-js": "0.0.8", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/load-yaml-file": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/load-yaml-file/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/load-yaml-file/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/load-yaml-file/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/load-yaml-file/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "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==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.419.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.419.0.tgz", + "integrity": "sha512-YkOHuc1uGH2A4G0NRZyeCW6mMFGb8z3amep0fARuKIri68nveAT5C8OuXOPJXpb/iIgSfsjdMjjII7bnEtGkvw==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/luxon": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-definitions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", + "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", + "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", + "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz", + "integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/nanostores": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.10.3.tgz", + "integrity": "sha512-Nii8O1XqmawqSCf9o2aWqVxhKRN01+iue9/VEd1TiJCr9VT5XxgPFbF1Edl1XN6pwJcZRsl8Ki+z01yb/T/C2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/neotraverse": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-html-parser": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", + "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.17.tgz", + "integrity": "sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-check-updates": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.0.6.tgz", + "integrity": "sha512-KCiaJH1cfnh/RyzKiDNjNfXgcKFyQs550Uf1OF/Yzb8xO56w+RLpP/OKRUx23/GyP/mLYwEpOO65qjmVdh6j0A==", + "bin": { + "ncu": "build/cli.js", + "npm-check-updates": "build/cli.js" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0", + "npm": ">=8.12.1" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/oniguruma-to-js": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.3.3.tgz", + "integrity": "sha512-m90/WEhgs8g4BxG37+Nu3YrMfJDs2YXtYtIllhsEPR+wP3+K4EZk6dDUvy2v2K4MNFDDOYKL4/yqYPXDqyozTQ==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/openai": { + "version": "4.55.7", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.55.7.tgz", + "integrity": "sha512-I2dpHTINt0Zk+Wlns6KzkKu77MmNW3VfIIQf5qYziEUI6t7WciG1zTobfKqdPzBmZi3TTM+3DtjPumxQdcvzwA==", + "dev": true, + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/ora": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.1.0.tgz", + "integrity": "sha512-GQEkNkH/GHOhPFXcqZs3IDahXEQcQxsSjEkK4KvEEST4t7eNzoMjxTzef+EZ+JluDEV+Raoi3WQ2CflnRdSVnQ==", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/p-limit": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.1.0.tgz", + "integrity": "sha512-H0jc0q1vOzlEk0TqAKXKZxdl7kX3OFUzCnNVUnq5Pc3DGo0kpeaMuPqxQn235HibwBEb0/pm9dgKTjXy66fBkg==", + "dependencies": { + "yocto-queue": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.0.1.tgz", + "integrity": "sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz", + "integrity": "sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" + }, + "node_modules/parse-css-color": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/parse-css-color/-/parse-css-color-0.2.1.tgz", + "integrity": "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==", + "dependencies": { + "color-name": "^1.1.4", + "hex-rgb": "^4.1.0" + } + }, + "node_modules/parse-css-color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/parse-latin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "dependencies": { + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/path-to-regexp": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/playwright": { + "version": "1.47.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.2.tgz", + "integrity": "sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==", + "dependencies": { + "playwright-core": "1.47.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.47.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.2.tgz", + "integrity": "sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/postcss": { + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "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" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/preferred-pm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-4.0.0.tgz", + "integrity": "sha512-gYBeFTZLu055D8Vv3cSPox/0iTPtkzxpLroSYYA7WXgRi31WCJ51Uyl8ZiPeUUjyvs2MBzK+S8v9JVUgHU/Sqw==", + "dependencies": { + "find-up-simple": "^1.0.0", + "find-yarn-workspace-root2": "1.2.16", + "which-pm": "^3.0.0" + }, + "engines": { + "node": ">=18.12" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-astro": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.14.1.tgz", + "integrity": "sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==", + "dev": true, + "dependencies": { + "@astrojs/compiler": "^2.9.1", + "prettier": "^3.0.0", + "sass-formatter": "^0.7.6" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" + } + }, + "node_modules/prettier-plugin-tailwindcss": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.5.tgz", + "integrity": "sha512-axfeOArc/RiGHjOIy9HytehlC0ZLeMaqY09mm8YCkMzznKiDkwFzOpBvtuhuv3xG5qB73+Mj7OCe2j/L1ryfuQ==", + "dev": true, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "@ianvs/prettier-plugin-sort-imports": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "@zackad/prettier-plugin-twig-melody": "*", + "prettier": "^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-marko": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-sort-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*" + }, + "peerDependenciesMeta": { + "@ianvs/prettier-plugin-sort-imports": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "@zackad/prettier-plugin-twig-melody": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-marko": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + } + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-calendar-heatmap": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/react-calendar-heatmap/-/react-calendar-heatmap-1.9.0.tgz", + "integrity": "sha512-mGed9any6QLOVckxwxC/eeP9s9wE8mTUW/FCE0V27xF9WOaCGuOftGSRH8DSDoSwgzMSVF6uuH7M1xvc+aZ8sg==", + "dependencies": { + "memoize-one": "^5.0.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-confetti": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", + "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-slick": { + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.30.2.tgz", + "integrity": "sha512-XvQJi7mRHuiU3b9irsqS9SGIgftIfdV5/tNcURTb5LdIokRA5kIIx3l4rlq2XYHfxcSntXapoRg/GxaVOM1yfg==", + "dependencies": { + "classnames": "^2.2.5", + "enquire.js": "^2.1.6", + "json2mq": "^0.2.0", + "lodash.debounce": "^4.0.8", + "resize-observer-polyfill": "^1.5.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-tooltip": { + "version": "5.27.1", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.27.1.tgz", + "integrity": "sha512-a+micPXcMOMt11CYlwJD4XShcqGziasHco4NPe1OFw298WBTILMyzUgNC1LAFViAe791JdHNVSJIpzhZm2MvDA==", + "dependencies": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/reactflow": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/reactflow/-/reactflow-11.11.4.tgz", + "integrity": "sha512-70FOtJkUWH3BAOsN+LU9lCrKoKbtOPnz2uq0CV2PLdNSwxTXOhCbsZr50GmZ+Rtw3jx8Uv7/vBFtCGixLfd4Og==", + "dependencies": { + "@reactflow/background": "11.3.14", + "@reactflow/controls": "11.2.14", + "@reactflow/core": "11.11.4", + "@reactflow/minimap": "11.7.14", + "@reactflow/node-resizer": "2.2.14", + "@reactflow/node-toolbar": "1.3.14" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regex": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/regex/-/regex-4.3.2.tgz", + "integrity": "sha512-kK/AA3A9K6q2js89+VMymcboLOlF5lZRCYJv3gzszXFHBr6kO6qLGzbm+UIugBEV8SMMKCTR59txoY6ctRHYVw==" + }, + "node_modules/rehype": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.1.tgz", + "integrity": "sha512-AcSLS2mItY+0fYu9xKxOu1LhUZeBZZBx8//5HKzF+0XP+eP8+6a5MXn2+DW2kfXR6Dtp1FEXMVrjyKAcvcU8vg==", + "dependencies": { + "@types/hast": "^3.0.0", + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.0.tgz", + "integrity": "sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.0.tgz", + "integrity": "sha512-1TX1i048LooI9QoecrXy7nGFFbFSufxVRAfc6Y9YMRAi56l+oB0zP51mLSV312uRuvVLPV1opSlJmslozR1XHQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", + "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-smartypants": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", + "dependencies": { + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retext": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "dependencies": { + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-latin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "dependencies": { + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-smartypants": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.1.0.tgz", + "integrity": "sha512-LDPXg95346bqFZnDMHo0S7Rq5p64+B+N8Vz733+wPMDtwb9rCOs9LIdIEhrUOU+TAywX9St+ocQWJt8wrzivcQ==", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/roadmap-renderer": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/roadmap-renderer/-/roadmap-renderer-1.0.6.tgz", + "integrity": "sha512-IQejjIfr9RIvesNwp3SyhEq1DMQ2RdJfJhgsb1AyPuKXsfJgOG8F++Cz1p3SIcY0bnB57Q16Ke2VJLjiUVwI3Q==" + }, + "node_modules/rollup": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.1.tgz", + "integrity": "sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.21.1", + "@rollup/rollup-android-arm64": "4.21.1", + "@rollup/rollup-darwin-arm64": "4.21.1", + "@rollup/rollup-darwin-x64": "4.21.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.1", + "@rollup/rollup-linux-arm-musleabihf": "4.21.1", + "@rollup/rollup-linux-arm64-gnu": "4.21.1", + "@rollup/rollup-linux-arm64-musl": "4.21.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.1", + "@rollup/rollup-linux-riscv64-gnu": "4.21.1", + "@rollup/rollup-linux-s390x-gnu": "4.21.1", + "@rollup/rollup-linux-x64-gnu": "4.21.1", + "@rollup/rollup-linux-x64-musl": "4.21.1", + "@rollup/rollup-win32-arm64-msvc": "4.21.1", + "@rollup/rollup-win32-ia32-msvc": "4.21.1", + "@rollup/rollup-win32-x64-msvc": "4.21.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/s.color": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz", + "integrity": "sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/sass-formatter": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz", + "integrity": "sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==", + "dev": true, + "dependencies": { + "suf-log": "^2.5.3" + } + }, + "node_modules/satori": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/satori/-/satori-0.10.14.tgz", + "integrity": "sha512-abovcqmwl97WKioxpkfuMeZmndB1TuDFY/R+FymrZyiGP+pMYomvgSzVPnbNMWHHESOPosVHGL352oFbdAnJcA==", + "dependencies": { + "@shuding/opentype.js": "1.4.0-beta.0", + "css-background-parser": "^0.1.0", + "css-box-shadow": "1.0.0-3", + "css-to-react-native": "^3.0.0", + "emoji-regex": "^10.2.1", + "escape-html": "^1.0.3", + "linebreak": "^1.1.0", + "parse-css-color": "^0.2.1", + "postcss-value-parser": "^4.2.0", + "yoga-wasm-web": "^0.3.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/satori-html": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/satori-html/-/satori-html-0.3.2.tgz", + "integrity": "sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==", + "dependencies": { + "ultrahtml": "^1.2.0" + } + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/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==" + }, + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/sharp": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", + "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.0" + }, + "engines": { + "libvips": ">=8.15.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", + "@img/sharp-libvips-darwin-arm64": "1.0.2", + "@img/sharp-libvips-darwin-x64": "1.0.2", + "@img/sharp-libvips-linux-arm": "1.0.2", + "@img/sharp-libvips-linux-arm64": "1.0.2", + "@img/sharp-libvips-linux-s390x": "1.0.2", + "@img/sharp-libvips-linux-x64": "1.0.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", + "@img/sharp-libvips-linuxmusl-x64": "1.0.2", + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-s390x": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-wasm32": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.16.3.tgz", + "integrity": "sha512-GypUE+fEd06FqDs63LSAVlmq7WsahhPQU62cgZxGF+TJT5LjD2k7HTxXj4/CKOVuMM3+wWQ1t4Y5oooeJFRRBQ==", + "dependencies": { + "@shikijs/core": "1.16.3", + "@shikijs/vscode-textmate": "^9.2.0", + "@types/hast": "^3.0.4" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/sitemap": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.2.tgz", + "integrity": "sha512-ARCqzHJ0p4gWt+j7NlU5eDlIO9+Rkr/JhPFZKKQ1l5GCus7rJH4UdrlVAh0xC/gDS/Qir2UMxqYNHtsKr2rpCw==", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, + "node_modules/slick-carousel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/slick-carousel/-/slick-carousel-1.8.1.tgz", + "integrity": "sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA==", + "peerDependencies": { + "jquery": ">=1.8.0" + } + }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stream-replace-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", + "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==" + }, + "node_modules/string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/suf-log": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz", + "integrity": "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==", + "dev": true, + "dependencies": { + "s.color": "0.0.15" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.4.0.tgz", + "integrity": "sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz", + "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, + "node_modules/tinyexec": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz", + "integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/tsconfck": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.3.tgz", + "integrity": "sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ==", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/tsx": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.17.0.tgz", + "integrity": "sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==", + "dev": true, + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" + } + }, + "node_modules/turndown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz", + "integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + } + }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==" + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, + "node_modules/ultrahtml": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.3.tgz", + "integrity": "sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-modify-children": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "dependencies": { + "@types/unist": "^3.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-children": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "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" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", + "integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.41", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.2.tgz", + "integrity": "sha512-0/iAvbXyM3RiPPJ4lyD4w6Mjgtf4ejTK6TPvTNG3H32PLwuT0N/ZjJLiXug7ETE/LWtTeHw9WRv7uX/tIKYyKg==", + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-pm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-3.0.0.tgz", + "integrity": "sha512-ysVYmw6+ZBhx3+ZkcPwRuJi38ZOTLJJ33PSHaitLxSKUMsh0LkKd0nC69zZCwt5D+AYUcMK2hhw4yWny20vSGg==", + "dependencies": { + "load-yaml-file": "^0.2.0" + }, + "engines": { + "node": ">=18.12" + } + }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xxhash-wasm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", + "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoga-wasm-web": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", + "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==" + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.2.tgz", + "integrity": "sha512-uSt90Gzc/tUfyNqxnjlfBs8W6WSGpNBv0rVsNxP/BVSMHMKGdthPYff4xtCHYloJGM0CFxFsb3NbC0eqPhfImw==", + "peerDependencies": { + "zod": "^3.23.3" + } + }, + "node_modules/zod-to-ts": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", + "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", + "peerDependencies": { + "typescript": "^4.9.4 || ^5.0.2", + "zod": "^3" + } + }, + "node_modules/zustand": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.4.tgz", + "integrity": "sha512-/BPMyLKJPtFEvVL0E9E9BTUM63MNyhPGlvxk1XjrfWTUlV+BR8jufjsovHzrtR6YNcBEcL7cMHovL1n9xHawEg==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000000..e22f5dc3d4d0 --- /dev/null +++ b/package.json @@ -0,0 +1,142 @@ +{ + "name": "roadmap.sh", + "type": "module", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "astro dev --port 3000", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview", + "format": "prettier --write .", + "gh-labels": "./scripts/create-roadmap-labels.sh", + "astro": "astro", + "deploy": "NODE_DEBUG=gh-pages gh-pages -d dist -t", + "upgrade": "ncu -u", + "roadmap-links": "node scripts/roadmap-links.cjs", + "roadmap-dirs": "node scripts/roadmap-dirs.cjs", + "roadmap-assets": "tsx scripts/editor-roadmap-assets.ts", + "refresh-assets": "tsx scripts/refresh-assets.ts", + "editor-roadmap-dirs": "tsx scripts/editor-roadmap-dirs.ts", + "editor-roadmap-content": "tsx scripts/editor-roadmap-content.ts", + "roadmap-content": "node scripts/roadmap-content.cjs", + "generate-renderer": "sh scripts/generate-renderer.sh", + "generate-renderer-dummy": "sh scripts/generate-renderer-dummy.sh", + "best-practice-dirs": "node scripts/best-practice-dirs.cjs", + "best-practice-content": "node scripts/best-practice-content.cjs", + "generate:og": "node ./scripts/generate-og-images.mjs", + "warm:urls": "sh ./scripts/warm-urls.sh https://roadmap.sh/sitemap-0.xml", + "compress:images": "tsx ./scripts/compress-images.ts", + "generate:roadmap-content-json": "tsx ./scripts/editor-roadmap-content-json.ts", + "migrate:editor-roadmaps": "tsx ./scripts/migrate-editor-roadmap.ts", + "sync:content-to-repo": "tsx ./scripts/sync-content-to-repo.ts", + "sync:repo-to-database": "tsx ./scripts/sync-repo-to-database.ts", + "sync:roadmap": "tsx ./scripts/sync-roadmap-to-database.ts", + "migrate:content-repo-to-database": "tsx ./scripts/migrate-content-repo-to-database.ts", + "cleanup:orphaned-content": "tsx ./scripts/cleanup-orphaned-content.ts", + "official:roadmap-assets": "tsx ./scripts/official-roadmap-assets.ts", + "test:e2e": "playwright test" + }, + "dependencies": { + "@ai-sdk/react": "2.0.0-beta.34", + "@astrojs/node": "^9.2.1", + "@astrojs/react": "^4.2.7", + "@astrojs/sitemap": "^3.4.0", + "@fingerprintjs/fingerprintjs": "^4.6.2", + "@microsoft/clarity": "^1.0.0", + "@nanostores/react": "^1.0.0", + "@napi-rs/image": "^1.9.2", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-popover": "^1.1.14", + "@resvg/resvg-js": "^2.6.2", + "@roadmapsh/editor": "workspace:*", + "@shikijs/transformers": "^3.9.2", + "@tailwindcss/vite": "^4.1.7", + "@tanstack/react-query": "^5.76.1", + "@tiptap/core": "^2.12.0", + "@tiptap/extension-document": "^2.12.0", + "@tiptap/extension-paragraph": "^2.12.0", + "@tiptap/extension-placeholder": "^2.12.0", + "@tiptap/extension-text": "^2.12.0", + "@tiptap/pm": "^2.12.0", + "@tiptap/react": "^2.12.0", + "@tiptap/suggestion": "^2.12.0", + "@types/react": "^19.1.4", + "@types/react-dom": "^19.1.5", + "astro": "^5.7.13", + "clsx": "^2.1.1", + "dayjs": "^1.11.13", + "dom-to-image": "^2.6.0", + "dracula-prism": "^2.1.16", + "gray-matter": "^4.0.3", + "htm": "^3.1.1", + "image-size": "^2.0.2", + "jose": "^6.0.11", + "js-cookie": "^3.0.5", + "katex": "^0.16.22", + "lucide-react": "^0.511.0", + "luxon": "^3.6.1", + "markdown-it-async": "^2.2.0", + "nanoid": "^5.1.5", + "nanostores": "^1.0.1", + "node-html-parser": "^7.0.1", + "npm-check-updates": "^18.0.1", + "playwright": "^1.52.0", + "prismjs": "^1.30.0", + "radix-ui": "^1.4.2", + "react": "^19.1.0", + "react-calendar-heatmap": "^1.10.0", + "react-confetti": "^6.4.0", + "react-dom": "^19.1.0", + "react-dropzone": "^14.3.8", + "react-markdown": "^10.1.0", + "react-resizable-panels": "^3.0.2", + "react-textarea-autosize": "^8.5.9", + "react-tooltip": "^5.28.1", + "rehype-external-links": "^3.0.0", + "rehype-katex": "^7.0.1", + "remark-gfm": "^4.0.1", + "remark-math": "^6.0.0", + "remark-parse": "^11.0.0", + "roadmap-renderer": "^1.0.7", + "sanitize-html": "^2.17.0", + "satori": "^0.13.1", + "satori-html": "^0.3.2", + "sharp": "^0.34.1", + "shiki": "^3.4.2", + "slugify": "^1.6.6", + "tailwind-merge": "^3.3.0", + "tailwindcss": "^4.1.7", + "tippy.js": "^6.3.7", + "tiptap-markdown": "^0.8.10", + "turndown": "^7.2.0", + "unified": "^11.0.5", + "zod": "^4.0.17", + "zustand": "^5.0.4" + }, + "devDependencies": { + "@ai-sdk/google": "^1.2.18", + "@playwright/test": "^1.52.0", + "@tailwindcss/typography": "^0.5.16", + "@types/dom-to-image": "^2.6.7", + "@types/js-cookie": "^3.0.6", + "@types/luxon": "^3.6.2", + "@types/markdown-it": "^14.1.2", + "@types/prismjs": "^1.26.5", + "@types/react-calendar-heatmap": "^1.9.0", + "@types/react-slick": "^0.23.13", + "@types/sanitize-html": "^2.16.0", + "@types/turndown": "^5.0.5", + "ai": "5.0.0-beta.34", + "csv-parser": "^3.2.0", + "gh-pages": "^6.3.0", + "js-yaml": "^4.1.0", + "markdown-it": "^14.1.0", + "openai": "^4.100.0", + "prettier": "^3.5.3", + "prettier-plugin-astro": "^0.14.1", + "prettier-plugin-tailwindcss": "^0.6.11", + "tailwind-scrollbar": "^4.0.2", + "tsx": "^4.19.4" + } +} diff --git a/packages/.gitkeep b/packages/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 000000000000..4f4d780b037a --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,108 @@ +import type { PlaywrightTestConfig } from '@playwright/test'; +import { devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +const config: PlaywrightTestConfig = { + testDir: './tests', + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000, + }, + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: 'http://localhost:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + }, + }, + + // { + // name: 'firefox', + // use: { + // ...devices['Desktop Firefox'], + // }, + // }, + + // { + // name: 'webkit', + // use: { + // ...devices['Desktop Safari'], + // }, + // }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { + // ...devices['Pixel 5'], + // }, + // }, + // { + // name: 'Mobile Safari', + // use: { + // ...devices['iPhone 12'], + // }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { + // channel: 'msedge', + // }, + // }, + // { + // name: 'Google Chrome', + // use: { + // channel: 'chrome', + // }, + // }, + ], + + /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + // outputDir: 'test-results/', + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npm run dev', + url: 'http://localhost:3000', + reuseExistingServer: !process.env.CI, + }, +}; + +export default config; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 000000000000..53642fb35ce1 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,9900 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@ai-sdk/react': + specifier: 2.0.0-beta.34 + version: 2.0.0-beta.34(react@19.1.0)(zod@4.0.17) + '@astrojs/node': + specifier: ^9.2.1 + version: 9.2.1(astro@5.7.13(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.40.2)(tsx@4.19.4)(typescript@5.8.3)) + '@astrojs/react': + specifier: ^4.2.7 + version: 4.2.7(@types/node@22.15.17)(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(jiti@2.4.2)(lightningcss@1.30.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tsx@4.19.4) + '@astrojs/sitemap': + specifier: ^3.4.0 + version: 3.4.0 + '@fingerprintjs/fingerprintjs': + specifier: ^4.6.2 + version: 4.6.2 + '@microsoft/clarity': + specifier: ^1.0.0 + version: 1.0.0 + '@nanostores/react': + specifier: ^1.0.0 + version: 1.0.0(nanostores@1.0.1)(react@19.1.0) + '@napi-rs/image': + specifier: ^1.9.2 + version: 1.9.2 + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.15 + version: 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popover': + specifier: ^1.1.14 + version: 1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@resvg/resvg-js': + specifier: ^2.6.2 + version: 2.6.2 + '@roadmapsh/editor': + specifier: workspace:* + version: link:packages/editor + '@shikijs/transformers': + specifier: ^3.9.2 + version: 3.9.2 + '@tailwindcss/vite': + specifier: ^4.1.7 + version: 4.1.7(vite@6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)) + '@tanstack/react-query': + specifier: ^5.76.1 + version: 5.76.1(react@19.1.0) + '@tiptap/core': + specifier: ^2.12.0 + version: 2.12.0(@tiptap/pm@2.12.0) + '@tiptap/extension-document': + specifier: ^2.12.0 + version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)) + '@tiptap/extension-paragraph': + specifier: ^2.12.0 + version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)) + '@tiptap/extension-placeholder': + specifier: ^2.12.0 + version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0) + '@tiptap/extension-text': + specifier: ^2.12.0 + version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)) + '@tiptap/pm': + specifier: ^2.12.0 + version: 2.12.0 + '@tiptap/react': + specifier: ^2.12.0 + version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@tiptap/suggestion': + specifier: ^2.12.0 + version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0) + '@types/react': + specifier: ^19.1.4 + version: 19.1.4 + '@types/react-dom': + specifier: ^19.1.5 + version: 19.1.5(@types/react@19.1.4) + astro: + specifier: ^5.7.13 + version: 5.7.13(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.40.2)(tsx@4.19.4)(typescript@5.8.3) + clsx: + specifier: ^2.1.1 + version: 2.1.1 + dayjs: + specifier: ^1.11.13 + version: 1.11.13 + dom-to-image: + specifier: ^2.6.0 + version: 2.6.0 + dracula-prism: + specifier: ^2.1.16 + version: 2.1.16 + gray-matter: + specifier: ^4.0.3 + version: 4.0.3 + htm: + specifier: ^3.1.1 + version: 3.1.1 + image-size: + specifier: ^2.0.2 + version: 2.0.2 + jose: + specifier: ^6.0.11 + version: 6.0.11 + js-cookie: + specifier: ^3.0.5 + version: 3.0.5 + katex: + specifier: ^0.16.22 + version: 0.16.22 + lucide-react: + specifier: ^0.511.0 + version: 0.511.0(react@19.1.0) + luxon: + specifier: ^3.6.1 + version: 3.6.1 + markdown-it-async: + specifier: ^2.2.0 + version: 2.2.0 + nanoid: + specifier: ^5.1.5 + version: 5.1.5 + nanostores: + specifier: ^1.0.1 + version: 1.0.1 + node-html-parser: + specifier: ^7.0.1 + version: 7.0.1 + npm-check-updates: + specifier: ^18.0.1 + version: 18.0.1 + playwright: + specifier: ^1.52.0 + version: 1.52.0 + prismjs: + specifier: ^1.30.0 + version: 1.30.0 + radix-ui: + specifier: ^1.4.2 + version: 1.4.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: + specifier: ^19.1.0 + version: 19.1.0 + react-calendar-heatmap: + specifier: ^1.10.0 + version: 1.10.0(react@19.1.0) + react-confetti: + specifier: ^6.4.0 + version: 6.4.0(react@19.1.0) + react-dom: + specifier: ^19.1.0 + version: 19.1.0(react@19.1.0) + react-dropzone: + specifier: ^14.3.8 + version: 14.3.8(react@19.1.0) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.1.4)(react@19.1.0) + react-resizable-panels: + specifier: ^3.0.2 + version: 3.0.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react-textarea-autosize: + specifier: ^8.5.9 + version: 8.5.9(@types/react@19.1.4)(react@19.1.0) + react-tooltip: + specifier: ^5.28.1 + version: 5.28.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + rehype-external-links: + specifier: ^3.0.0 + version: 3.0.0 + rehype-katex: + specifier: ^7.0.1 + version: 7.0.1 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + remark-math: + specifier: ^6.0.0 + version: 6.0.0 + remark-parse: + specifier: ^11.0.0 + version: 11.0.0 + roadmap-renderer: + specifier: ^1.0.7 + version: 1.0.7 + sanitize-html: + specifier: ^2.17.0 + version: 2.17.0 + satori: + specifier: ^0.13.1 + version: 0.13.1 + satori-html: + specifier: ^0.3.2 + version: 0.3.2 + sharp: + specifier: ^0.34.1 + version: 0.34.1 + shiki: + specifier: ^3.4.2 + version: 3.4.2 + slugify: + specifier: ^1.6.6 + version: 1.6.6 + tailwind-merge: + specifier: ^3.3.0 + version: 3.3.0 + tailwindcss: + specifier: ^4.1.7 + version: 4.1.7 + tippy.js: + specifier: ^6.3.7 + version: 6.3.7 + tiptap-markdown: + specifier: ^0.8.10 + version: 0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)) + turndown: + specifier: ^7.2.0 + version: 7.2.0 + unified: + specifier: ^11.0.5 + version: 11.0.5 + zod: + specifier: ^4.0.17 + version: 4.0.17 + zustand: + specifier: ^5.0.4 + version: 5.0.4(@types/react@19.1.4)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)) + devDependencies: + '@ai-sdk/google': + specifier: ^1.2.18 + version: 1.2.18(zod@4.0.17) + '@playwright/test': + specifier: ^1.52.0 + version: 1.52.0 + '@tailwindcss/typography': + specifier: ^0.5.16 + version: 0.5.16(tailwindcss@4.1.7) + '@types/dom-to-image': + specifier: ^2.6.7 + version: 2.6.7 + '@types/js-cookie': + specifier: ^3.0.6 + version: 3.0.6 + '@types/luxon': + specifier: ^3.6.2 + version: 3.6.2 + '@types/markdown-it': + specifier: ^14.1.2 + version: 14.1.2 + '@types/prismjs': + specifier: ^1.26.5 + version: 1.26.5 + '@types/react-calendar-heatmap': + specifier: ^1.9.0 + version: 1.9.0 + '@types/react-slick': + specifier: ^0.23.13 + version: 0.23.13 + '@types/sanitize-html': + specifier: ^2.16.0 + version: 2.16.0 + '@types/turndown': + specifier: ^5.0.5 + version: 5.0.5 + ai: + specifier: 5.0.0-beta.34 + version: 5.0.0-beta.34(zod@4.0.17) + csv-parser: + specifier: ^3.2.0 + version: 3.2.0 + gh-pages: + specifier: ^6.3.0 + version: 6.3.0 + js-yaml: + specifier: ^4.1.0 + version: 4.1.0 + markdown-it: + specifier: ^14.1.0 + version: 14.1.0 + openai: + specifier: ^4.100.0 + version: 4.100.0(zod@4.0.17) + prettier: + specifier: ^3.5.3 + version: 3.5.3 + prettier-plugin-astro: + specifier: ^0.14.1 + version: 0.14.1 + prettier-plugin-tailwindcss: + specifier: ^0.6.11 + version: 0.6.11(prettier-plugin-astro@0.14.1)(prettier@3.5.3) + tailwind-scrollbar: + specifier: ^4.0.2 + version: 4.0.2(react@19.1.0)(tailwindcss@4.1.7) + tsx: + specifier: ^4.19.4 + version: 4.19.4 + + packages/editor: + dependencies: + '@xyflow/react': + specifier: ^12.6.0 + version: 12.6.0(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-react: + specifier: ^0.503.0 + version: 0.503.0(react@19.1.0) + nanoid: + specifier: ^5.1.5 + version: 5.1.5 + react: + specifier: ^19.1.0 + version: 19.1.0 + remark-parse: + specifier: ^11.0.0 + version: 11.0.0 + tailwind-merge: + specifier: ^3.2.0 + version: 3.3.0 + unified: + specifier: ^11.0.5 + version: 11.0.5 + zustand: + specifier: ^5.0.3 + version: 5.0.4(@types/react@19.1.4)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.1.4 + version: 4.1.5 + '@types/react': + specifier: ^19.1.2 + version: 19.1.4 + postcss: + specifier: ^8.5.3 + version: 8.5.3 + postcss-replace: + specifier: ^2.0.1 + version: 2.0.1(postcss@8.5.3) + tailwindcss: + specifier: ^4.1.4 + version: 4.1.7 + tsup: + specifier: ^8.4.0 + version: 8.4.0(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(typescript@5.8.3) + typescript: + specifier: ^5.8.3 + version: 5.8.3 + +packages: + + '@ai-sdk/gateway@1.0.0-beta.19': + resolution: {integrity: sha512-felWPMuECZRGx8xnmvH5dW3jywKTkGnw/tXN8szphGzEDr/BfxywuXijfPBG2WBUS6frPXsvSLDRdCm5W38PXA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4 + + '@ai-sdk/google@1.2.18': + resolution: {integrity: sha512-8B70+i+uB12Ae6Sn6B9Oc6W0W/XorGgc88Nx0pyUrcxFOdytHBaAVhTPqYsO3LLClfjYN8pQ9GMxd5cpGEnUcA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + + '@ai-sdk/provider-utils@2.2.8': + resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + + '@ai-sdk/provider-utils@3.0.0-beta.10': + resolution: {integrity: sha512-e6WSsgM01au04/1L/v5daXHn00eKjPBQXl3jq3BfvQbQ1jo8Rls2pvrdkyVc25jBW4TV4Zm+tw+v6NAh5NPXMA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4 + + '@ai-sdk/provider@1.1.3': + resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} + engines: {node: '>=18'} + + '@ai-sdk/provider@2.0.0-beta.2': + resolution: {integrity: sha512-vqhtZA7R24q1XnmfmIb1fZSmHMIaJH1BVQ+0kFnNJgqWsc+V8i+yfetZ37gUc4fXATFmBuS/6O7+RPoHsZ2Fqg==} + engines: {node: '>=18'} + + '@ai-sdk/react@2.0.0-beta.34': + resolution: {integrity: sha512-6v55iQbJRJ42nFM7GPzmzaP3NxEgFamKQu2fYc8jl5McQyYka3gZ7jHpy4jTMy+b16HIXKgPqVXd/RN/+uHOEw==} + engines: {node: '>=18'} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + zod: ^3.25.76 || ^4 + peerDependenciesMeta: + zod: + optional: true + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@astrojs/compiler@2.12.0': + resolution: {integrity: sha512-7bCjW6tVDpUurQLeKBUN9tZ5kSv5qYrGmcn0sG0IwacL7isR2ZbyyA3AdZ4uxsuUFOS2SlgReTH7wkxO6zpqWA==} + + '@astrojs/internal-helpers@0.6.1': + resolution: {integrity: sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A==} + + '@astrojs/markdown-remark@6.3.1': + resolution: {integrity: sha512-c5F5gGrkczUaTVgmMW9g1YMJGzOtRvjjhw6IfGuxarM6ct09MpwysP10US729dy07gg8y+ofVifezvP3BNsWZg==} + + '@astrojs/node@9.2.1': + resolution: {integrity: sha512-kEHLB37ooW91p7FLGalqa3jVQRIafntfKiZgCnjN1lEYw+j8NP6VJHQbLHmzzbtKUI0J+srGiTnGZmaHErHE5w==} + peerDependencies: + astro: ^5.3.0 + + '@astrojs/prism@3.2.0': + resolution: {integrity: sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw==} + engines: {node: ^18.17.1 || ^20.3.0 || >=22.0.0} + + '@astrojs/react@4.2.7': + resolution: {integrity: sha512-/wM90noT/6QyJEOGdDmDbq2D9qZooKTJNG1M8olmsW5ns6bJ7uxG5fzkYxcpA3WUTD6Dj6NtpEqchvb5h8Fa+g==} + engines: {node: ^18.17.1 || ^20.3.0 || >=22.0.0} + peerDependencies: + '@types/react': ^17.0.50 || ^18.0.21 || ^19.0.0 + '@types/react-dom': ^17.0.17 || ^18.0.6 || ^19.0.0 + react: ^17.0.2 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.2 || ^18.0.0 || ^19.0.0 + + '@astrojs/sitemap@3.4.0': + resolution: {integrity: sha512-C5m/xsKvRSILKM3hy47n5wKtTQtJXn8epoYuUmCCstaE9XBt20yInym3Bz2uNbEiNfv11bokoW0MqeXPIvjFIQ==} + + '@astrojs/telemetry@3.2.1': + resolution: {integrity: sha512-SSVM820Jqc6wjsn7qYfV9qfeQvePtVc1nSofhyap7l0/iakUKywj3hfy3UJAOV4sGV4Q/u450RD4AaCaFvNPlg==} + engines: {node: ^18.17.1 || ^20.3.0 || >=22.0.0} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.27.2': + resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.27.1': + resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.27.1': + resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.27.1': + resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.27.1': + resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.27.2': + resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.27.1': + resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.27.1': + resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.27.1': + resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} + engines: {node: '>=6.9.0'} + + '@capsizecss/unpack@2.4.0': + resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==} + + '@emnapi/core@1.4.3': + resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} + + '@emnapi/runtime@1.4.3': + resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + + '@emnapi/wasi-threads@1.0.2': + resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} + + '@esbuild/aix-ppc64@0.25.4': + resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.4': + resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.4': + resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.4': + resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.4': + resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.4': + resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.4': + resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.4': + resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.4': + resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.4': + resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.4': + resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.4': + resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.4': + resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.4': + resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.4': + resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.4': + resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.4': + resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.4': + resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.4': + resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.4': + resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.4': + resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.25.4': + resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.4': + resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.4': + resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.4': + resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@fingerprintjs/fingerprintjs@4.6.2': + resolution: {integrity: sha512-g8mXuqcFKbgH2CZKwPfVtsUJDHyvcgIABQI7Y0tzWEFXpGxJaXuAuzlifT2oTakjDBLTK4Gaa9/5PERDhqUjtw==} + + '@floating-ui/core@1.7.0': + resolution: {integrity: sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==} + + '@floating-ui/dom@1.7.0': + resolution: {integrity: sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==} + + '@floating-ui/react-dom@2.1.2': + resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-arm64@0.34.1': + resolution: {integrity: sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.1': + resolution: {integrity: sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.1.0': + resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.1.0': + resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm64@1.1.0': + resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.1.0': + resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.1.0': + resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.1.0': + resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.1.0': + resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.1.0': + resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.1.0': + resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.1': + resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-arm@0.34.1': + resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-s390x@0.34.1': + resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-x64@0.34.1': + resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.1': + resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.1': + resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-wasm32@0.34.1': + resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-ia32@0.34.1': + resolution: {integrity: sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@img/sharp-win32-x64@0.34.1': + resolution: {integrity: sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@microsoft/clarity@1.0.0': + resolution: {integrity: sha512-2QY6SmXnqRj6dWhNY8NYCN3e53j4zCFebH4wGnNhdGV1mqAsQwql2fT0w8TISxCvwwfVp8idsWLIdrRHOms1PQ==} + + '@mixmark-io/domino@2.2.0': + resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} + + '@nanostores/react@1.0.0': + resolution: {integrity: sha512-eDduyNy+lbQJMg6XxZ/YssQqF6b4OXMFEZMYKPJCCmBevp1lg0g+4ZRi94qGHirMtsNfAWKNwsjOhC+q1gvC+A==} + engines: {node: ^20.0.0 || >=22.0.0} + peerDependencies: + nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^1.0.0 + react: '>=18.0.0' + + '@napi-rs/image-android-arm64@1.9.2': + resolution: {integrity: sha512-DQNI06ukKqpF4eogz9zyxfU+GYp11TfDqSNWKmk/IRU2oiB0DEgskuj7ZzaKMPJWFRZjI86V233UrrNRh76h2Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/image-darwin-arm64@1.9.2': + resolution: {integrity: sha512-w+0X87sORbC2uDpH7NAdELOnvzhu3dB19h2oMaD+YIv/+CVXV5eK2PS3zkRgMLCinVtFOZFZK3dFbHU3kncCRw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/image-darwin-x64@1.9.2': + resolution: {integrity: sha512-8SnFDcgUSoL6Y38lstXi5FYECD1f4dJqQe2UCTwciED8gZnpC8Pju7JYJWcYgHHXn1JnKP9T1lPlSaX+L56EgA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/image-freebsd-x64@1.9.2': + resolution: {integrity: sha512-oS0+iSb8AekjaHgTZdARKceqTPxSokByLzNQ9vGf2lZlTwlRFmXGq4XYutyzqzRuLT3BATLwtGMXiguMEYMuUw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@napi-rs/image-linux-arm-gnueabihf@1.9.2': + resolution: {integrity: sha512-bsbZSvw3wa7yaLVvz4M5VhJaB9LmgjAL3W7rnmXaX5BgpaQImNDm9MrxPG8ennr9Pbn6qDtCSioOz53ZgWUtgg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@napi-rs/image-linux-arm64-gnu@1.9.2': + resolution: {integrity: sha512-tiN9RMwEIcA8TodvmxdeJqsRdUGKAmxQ2aa0FkYjshdkmChG/sqUtUoL9LdmDf1tw1IACrSuT2Wj4LevxBdIJA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/image-linux-arm64-musl@1.9.2': + resolution: {integrity: sha512-w6Sx1j9PtqO2bP3Jl6nuMryzxA3zsoc1U8u1H7AZketyhxXIxqVm0oGomZGs5Bgshzau45bcWinp6GWrlSwt6A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/image-linux-x64-gnu@1.9.2': + resolution: {integrity: sha512-yB/s9wNB/9YHpQ4TwN8NWMA1tEK1gPLQwtysa68yMdHczb+7BTCKCIYIHD9rUulyT1Q/VgLIJCUMoxve0pIoeg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/image-linux-x64-musl@1.9.2': + resolution: {integrity: sha512-x9dRlo27xYXonh+gZZTqQL4lAfi/lhi8K8LE2hczbZffqmXvWU7NuHSgPVVeU/nvcMMqw1Cjzn81h7ny44SLbQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/image-wasm32-wasi@1.9.2': + resolution: {integrity: sha512-BeA1wzzIG4+tdAwXWaAjObBOC6SzIbq0IhykSQ1xCGvYwd8stsn7ktPRz5b55PDo+Doj65PCT4H/xUgFcSiLCw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@napi-rs/image-win32-ia32-msvc@1.9.2': + resolution: {integrity: sha512-JDJP04Hg9Qru5Pth4gfBkXz9hZd/otx6ymi2VTuSKDFjpJIjk4tyUr9+BIE1ghFCHDzeJGVe7CDGdF/NTA1xrg==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@napi-rs/image-win32-x64-msvc@1.9.2': + resolution: {integrity: sha512-baRyTED6FkTsPliSOH7x8TV/cyAST9y6L1ClSgSCVEx7+W8MKKig90fF302kEa2PwMAyrXM3Ytq9KuIC7xJ+eA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/image@1.9.2': + resolution: {integrity: sha512-CvTC3XL5/BzHaVkJOZy31xOJLNSY3rBuUIQixaE/LwEQNSUdaxWa9gUyUkC9lUekkUp26CzaLLj2w7l7bxB1ag==} + engines: {node: '>= 10'} + + '@napi-rs/wasm-runtime@0.2.9': + resolution: {integrity: sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@playwright/test@1.52.0': + resolution: {integrity: sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==} + engines: {node: '>=18'} + hasBin: true + + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.2': + resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} + + '@radix-ui/react-accessible-icon@1.1.7': + resolution: {integrity: sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-accordion@1.2.11': + resolution: {integrity: sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-alert-dialog@1.1.14': + resolution: {integrity: sha512-IOZfZ3nPvN6lXpJTBCunFQPRSvK8MDgSc1FB85xnIpUKOw9en0dJj8JmCAxV7BiZdtYlUpmrQjoTFkVYtdoWzQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-aspect-ratio@1.1.7': + resolution: {integrity: sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.10': + resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.3.2': + resolution: {integrity: sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collapsible@1.1.11': + resolution: {integrity: sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context-menu@2.2.15': + resolution: {integrity: sha512-UsQUMjcYTsBjTSXw0P3GO0werEQvUY2plgRQuKoCTtkNr45q1DiL51j4m7gxhABzZ0BadoXNsIbg7F3KwiUBbw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.14': + resolution: {integrity: sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.10': + resolution: {integrity: sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.15': + resolution: {integrity: sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.2': + resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-form@0.1.7': + resolution: {integrity: sha512-IXLKFnaYvFg/KkeV5QfOX7tRnwHXp127koOFUjLWMTrRv5Rny3DQcAtIFFeA/Cli4HHM8DuJCXAUsgnFVJndlw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-hover-card@1.1.14': + resolution: {integrity: sha512-CPYZ24Mhirm+g6D8jArmLzjYu4Eyg3TTUHswR26QgzXBHBe64BO/RHOJKzmF/Dxb4y4f9PKyJdwm/O/AhNkb+Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.7': + resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.15': + resolution: {integrity: sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menubar@1.1.15': + resolution: {integrity: sha512-Z71C7LGD+YDYo3TV81paUs8f3Zbmkvg6VLRQpKYfzioOE6n7fOhA3ApK/V/2Odolxjoc4ENk8AYCjohCNayd5A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-navigation-menu@1.2.13': + resolution: {integrity: sha512-WG8wWfDiJlSF5hELjwfjSGOXcBR/ZMhBFCGYe8vERpC39CQYZeq1PQ2kaYHdye3V95d06H89KGMsVCIE4LWo3g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-one-time-password-field@0.1.7': + resolution: {integrity: sha512-w1vm7AGI8tNXVovOK7TYQHrAGpRF7qQL+ENpT1a743De5Zmay2RbWGKAiYDKIyIuqptns+znCKwNztE2xl1n0Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-password-toggle-field@0.1.2': + resolution: {integrity: sha512-F90uYnlBsLPU1UbSLciLsWQmk8+hdWa6SFw4GXaIdNWxFxI5ITKVdAG64f+Twaa9ic6xE7pqxPyUmodrGjT4pQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popover@1.1.14': + resolution: {integrity: sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.7': + resolution: {integrity: sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.4': + resolution: {integrity: sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-progress@1.1.7': + resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-radio-group@1.3.7': + resolution: {integrity: sha512-9w5XhD0KPOrm92OTTE0SysH3sYzHsSTHNvZgUBo/VZ80VdYyB5RneDbc0dKpURS24IxkoFRu/hI0i4XyfFwY6g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.10': + resolution: {integrity: sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.9': + resolution: {integrity: sha512-YSjEfBXnhUELsO2VzjdtYYD4CfQjvao+lhhrX5XsHD7/cyUNzljF1FHEbgTPN7LH2MClfwRMIsYlqTYpKTTe2A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.5': + resolution: {integrity: sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.7': + resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slider@1.3.5': + resolution: {integrity: sha512-rkfe2pU2NBAYfGaxa3Mqosi7VZEWX5CxKaanRv0vZd4Zhl9fvQrg0VM93dv3xGLGfrHuoTRF3JXH8nb9g+B3fw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.2.5': + resolution: {integrity: sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.12': + resolution: {integrity: sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toast@1.2.14': + resolution: {integrity: sha512-nAP5FBxBJGQ/YfUB+r+O6USFVkWq3gAInkxyEnmvEV5jtSbfDhfa4hwX8CraCnbjMLsE7XSf/K75l9xXY7joWg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle-group@1.1.10': + resolution: {integrity: sha512-kiU694Km3WFLTC75DdqgM/3Jauf3rD9wxeS9XtyWFKsBUeZA337lC+6uUazT7I1DhanZ5gyD5Stf8uf2dbQxOQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle@1.1.9': + resolution: {integrity: sha512-ZoFkBBz9zv9GWer7wIjvdRxmh2wyc2oKWw6C6CseWd6/yq1DK/l5lJ+wnsmFwJZbBYqr02mrf8A2q/CVCuM3ZA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toolbar@1.1.10': + resolution: {integrity: sha512-jiwQsduEL++M4YBIurjSa+voD86OIytCod0/dbIxFZDLD8NfO1//keXYMfsW8BPcfqwoNjt+y06XcJqAb4KR7A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.7': + resolution: {integrity: sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.0': + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@remirror/core-constants@3.0.0': + resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} + + '@resvg/resvg-js-android-arm-eabi@2.6.2': + resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + + '@resvg/resvg-js-android-arm64@2.6.2': + resolution: {integrity: sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@resvg/resvg-js-darwin-arm64@2.6.2': + resolution: {integrity: sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@resvg/resvg-js-darwin-x64@2.6.2': + resolution: {integrity: sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': + resolution: {integrity: sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@resvg/resvg-js-linux-arm64-gnu@2.6.2': + resolution: {integrity: sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@resvg/resvg-js-linux-arm64-musl@2.6.2': + resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@resvg/resvg-js-linux-x64-gnu@2.6.2': + resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@resvg/resvg-js-linux-x64-musl@2.6.2': + resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@resvg/resvg-js-win32-arm64-msvc@2.6.2': + resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@resvg/resvg-js-win32-ia32-msvc@2.6.2': + resolution: {integrity: sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@resvg/resvg-js-win32-x64-msvc@2.6.2': + resolution: {integrity: sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@resvg/resvg-js@2.6.2': + resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==} + engines: {node: '>= 10'} + + '@rollup/pluginutils@5.1.4': + resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.40.2': + resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.40.2': + resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.40.2': + resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.40.2': + resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.40.2': + resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.40.2': + resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.40.2': + resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.40.2': + resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.40.2': + resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.40.2': + resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.40.2': + resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': + resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.40.2': + resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.40.2': + resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.40.2': + resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.40.2': + resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.40.2': + resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.40.2': + resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.40.2': + resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.40.2': + resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==} + cpu: [x64] + os: [win32] + + '@shikijs/core@3.4.2': + resolution: {integrity: sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ==} + + '@shikijs/core@3.9.2': + resolution: {integrity: sha512-3q/mzmw09B2B6PgFNeiaN8pkNOixWS726IHmJEpjDAcneDPMQmUg2cweT9cWXY4XcyQS3i6mOOUgQz9RRUP6HA==} + + '@shikijs/engine-javascript@3.4.2': + resolution: {integrity: sha512-1/adJbSMBOkpScCE/SB6XkjJU17ANln3Wky7lOmrnpl+zBdQ1qXUJg2GXTYVHRq+2j3hd1DesmElTXYDgtfSOQ==} + + '@shikijs/engine-oniguruma@3.4.2': + resolution: {integrity: sha512-zcZKMnNndgRa3ORja6Iemsr3DrLtkX3cAF7lTJkdMB6v9alhlBsX9uNiCpqofNrXOvpA3h6lHcLJxgCIhVOU5Q==} + + '@shikijs/langs@3.4.2': + resolution: {integrity: sha512-H6azIAM+OXD98yztIfs/KH5H4PU39t+SREhmM8LaNXyUrqj2mx+zVkr8MWYqjceSjDw9I1jawm1WdFqU806rMA==} + + '@shikijs/themes@3.4.2': + resolution: {integrity: sha512-qAEuAQh+brd8Jyej2UDDf+b4V2g1Rm8aBIdvt32XhDPrHvDkEnpb7Kzc9hSuHUxz0Iuflmq7elaDuQAP9bHIhg==} + + '@shikijs/transformers@3.9.2': + resolution: {integrity: sha512-MW5hT4TyUp6bNAgTExRYLk1NNasVQMTCw1kgbxHcEC0O5cbepPWaB+1k+JzW9r3SP2/R8kiens8/3E6hGKfgsA==} + + '@shikijs/types@3.4.2': + resolution: {integrity: sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg==} + + '@shikijs/types@3.9.2': + resolution: {integrity: sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@shuding/opentype.js@1.4.0-beta.0': + resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==} + engines: {node: '>= 8.0.0'} + hasBin: true + + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@swc/helpers@0.5.17': + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + + '@tailwindcss/node@4.1.5': + resolution: {integrity: sha512-CBhSWo0vLnWhXIvpD0qsPephiaUYfHUX3U9anwDaHZAeuGpTiB3XmsxPAN6qX7bFhipyGBqOa1QYQVVhkOUGxg==} + + '@tailwindcss/node@4.1.7': + resolution: {integrity: sha512-9rsOpdY9idRI2NH6CL4wORFY0+Q6fnx9XP9Ju+iq/0wJwGD5IByIgFmwVbyy4ymuyprj8Qh4ErxMKTUL4uNh3g==} + + '@tailwindcss/oxide-android-arm64@4.1.5': + resolution: {integrity: sha512-LVvM0GirXHED02j7hSECm8l9GGJ1RfgpWCW+DRn5TvSaxVsv28gRtoL4aWKGnXqwvI3zu1GABeDNDVZeDPOQrw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-android-arm64@4.1.7': + resolution: {integrity: sha512-IWA410JZ8fF7kACus6BrUwY2Z1t1hm0+ZWNEzykKmMNM09wQooOcN/VXr0p/WJdtHZ90PvJf2AIBS/Ceqx1emg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.5': + resolution: {integrity: sha512-//TfCA3pNrgnw4rRJOqavW7XUk8gsg9ddi8cwcsWXp99tzdBAZW0WXrD8wDyNbqjW316Pk2hiN/NJx/KWHl8oA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-arm64@4.1.7': + resolution: {integrity: sha512-81jUw9To7fimGGkuJ2W5h3/oGonTOZKZ8C2ghm/TTxbwvfSiFSDPd6/A/KE2N7Jp4mv3Ps9OFqg2fEKgZFfsvg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.5': + resolution: {integrity: sha512-XQorp3Q6/WzRd9OalgHgaqgEbjP3qjHrlSUb5k1EuS1Z9NE9+BbzSORraO+ecW432cbCN7RVGGL/lSnHxcd+7Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.7': + resolution: {integrity: sha512-q77rWjEyGHV4PdDBtrzO0tgBBPlQWKY7wZK0cUok/HaGgbNKecegNxCGikuPJn5wFAlIywC3v+WMBt0PEBtwGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.5': + resolution: {integrity: sha512-bPrLWbxo8gAo97ZmrCbOdtlz/Dkuy8NK97aFbVpkJ2nJ2Jo/rsCbu0TlGx8joCuA3q6vMWTSn01JY46iwG+clg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-freebsd-x64@4.1.7': + resolution: {integrity: sha512-RfmdbbK6G6ptgF4qqbzoxmH+PKfP4KSVs7SRlTwcbRgBwezJkAO3Qta/7gDy10Q2DcUVkKxFLXUQO6J3CRvBGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.5': + resolution: {integrity: sha512-1gtQJY9JzMAhgAfvd/ZaVOjh/Ju/nCoAsvOVJenWZfs05wb8zq+GOTnZALWGqKIYEtyNpCzvMk+ocGpxwdvaVg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.7': + resolution: {integrity: sha512-OZqsGvpwOa13lVd1z6JVwQXadEobmesxQ4AxhrwRiPuE04quvZHWn/LnihMg7/XkN+dTioXp/VMu/p6A5eZP3g==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.5': + resolution: {integrity: sha512-dtlaHU2v7MtdxBXoqhxwsWjav7oim7Whc6S9wq/i/uUMTWAzq/gijq1InSgn2yTnh43kR+SFvcSyEF0GCNu1PQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.7': + resolution: {integrity: sha512-voMvBTnJSfKecJxGkoeAyW/2XRToLZ227LxswLAwKY7YslG/Xkw9/tJNH+3IVh5bdYzYE7DfiaPbRkSHFxY1xA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.5': + resolution: {integrity: sha512-fg0F6nAeYcJ3CriqDT1iVrqALMwD37+sLzXs8Rjy8Z1ZHshJoYceodfyUwGJEsQoTyWbliFNRs2wMQNXtT7MVA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.7': + resolution: {integrity: sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.5': + resolution: {integrity: sha512-SO+F2YEIAHa1AITwc8oPwMOWhgorPzzcbhWEb+4oLi953h45FklDmM8dPSZ7hNHpIk9p/SCZKUYn35t5fjGtHA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.7': + resolution: {integrity: sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.5': + resolution: {integrity: sha512-6UbBBplywkk/R+PqqioskUeXfKcBht3KU7juTi1UszJLx0KPXUo10v2Ok04iBJIaDPkIFkUOVboXms5Yxvaz+g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.7': + resolution: {integrity: sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.5': + resolution: {integrity: sha512-hwALf2K9FHuiXTPqmo1KeOb83fTRNbe9r/Ixv9ZNQ/R24yw8Ge1HOWDDgTdtzntIaIUJG5dfXCf4g9AD4RiyhQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-wasm32-wasi@4.1.7': + resolution: {integrity: sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.5': + resolution: {integrity: sha512-oDKncffWzaovJbkuR7/OTNFRJQVdiw/n8HnzaCItrNQUeQgjy7oUiYpsm9HUBgpmvmDpSSbGaCa2Evzvk3eFmA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.7': + resolution: {integrity: sha512-HUiSiXQ9gLJBAPCMVRk2RT1ZrBjto7WvqsPBwUrNK2BcdSxMnk19h4pjZjI7zgPhDxlAbJSumTC4ljeA9y0tEw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.5': + resolution: {integrity: sha512-WiR4dtyrFdbb+ov0LK+7XsFOsG+0xs0PKZKkt41KDn9jYpO7baE3bXiudPVkTqUEwNfiglCygQHl2jklvSBi7Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.7': + resolution: {integrity: sha512-rYHGmvoHiLJ8hWucSfSOEmdCBIGZIq7SpkPRSqLsH2Ab2YUNgKeAPT1Fi2cx3+hnYOrAb0jp9cRyode3bBW4mQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.5': + resolution: {integrity: sha512-1n4br1znquEvyW/QuqMKQZlBen+jxAbvyduU87RS8R3tUSvByAkcaMTkJepNIrTlYhD+U25K4iiCIxE6BGdRYA==} + engines: {node: '>= 10'} + + '@tailwindcss/oxide@4.1.7': + resolution: {integrity: sha512-5SF95Ctm9DFiUyjUPnDGkoKItPX/k+xifcQhcqX5RA85m50jw1pT/KzjdvlqxRja45Y52nR4MR9fD1JYd7f8NQ==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.5': + resolution: {integrity: sha512-5lAC2/pzuyfhsFgk6I58HcNy6vPK3dV/PoPxSDuOTVbDvCddYHzHiJZZInGIY0venvzzfrTEUAXJFULAfFmObg==} + + '@tailwindcss/typography@0.5.16': + resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + + '@tailwindcss/vite@4.1.7': + resolution: {integrity: sha512-tYa2fO3zDe41I7WqijyVbRd8oWT0aEID1Eokz5hMT6wShLIHj3yvwj9XbfuloHP9glZ6H+aG2AN/+ZrxJ1Y5RQ==} + peerDependencies: + vite: ^5.2.0 || ^6 + + '@tanstack/query-core@5.76.0': + resolution: {integrity: sha512-FN375hb8ctzfNAlex5gHI6+WDXTNpe0nbxp/d2YJtnP+IBM6OUm7zcaoCW6T63BawGOYZBbKC0iPvr41TteNVg==} + + '@tanstack/react-query@5.76.1': + resolution: {integrity: sha512-YxdLZVGN4QkT5YT1HKZQWiIlcgauIXEIsMOTSjvyD5wLYK8YVvKZUPAysMqossFJJfDpJW3pFn7WNZuPOqq+fw==} + peerDependencies: + react: ^18 || ^19 + + '@tiptap/core@2.12.0': + resolution: {integrity: sha512-3qX8oGVKFFZzQ0vit+ZolR6AJIATBzmEmjAA0llFhWk4vf3v64p1YcXcJsOBsr5scizJu5L6RYWEFatFwqckRg==} + peerDependencies: + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-bubble-menu@2.12.0': + resolution: {integrity: sha512-DYijoE0igV0Oi+ZppFsp2UrQsM/4HZtmmpD78BJM9zfCbd1YvAUIxmzmXr8uqU18OHd1uQy+/zvuNoUNYyw67g==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-document@2.12.0': + resolution: {integrity: sha512-sA1Q+mxDIv0Y3qQTBkYGwknNbDcGFiJ/fyAFholXpqbrcRx3GavwR/o0chBdsJZlFht0x7AWGwUYWvIo7wYilA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-floating-menu@2.12.0': + resolution: {integrity: sha512-BYpyZx/56KCDksWuJJbhki/uNgt9sACuSSZFH5AN1yS1ISD+EzIxqf6Pzzv8QCoNJ+KcRNVaZsOlOFaJGoyzag==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-paragraph@2.12.0': + resolution: {integrity: sha512-QNK5cgewCunWFxpLlbvvoO1rrLgEtNKxiY79fctP9toV+e59R+1i1Q9lXC1O5mOfDgVxCb6uFDMsqmKhFjpPog==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-placeholder@2.12.0': + resolution: {integrity: sha512-K7irDox4P+NLAMjVrJeG72f0sulsCRYpx1Cy4gxKCdi1LTivj5VkXa6MXmi42KTCwBu3pWajBctYIOAES1FTAA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-text@2.12.0': + resolution: {integrity: sha512-0ytN9V1tZYTXdiYDQg4FB2SQ56JAJC9r/65snefb9ztl+gZzDrIvih7CflHs1ic9PgyjexfMLeH+VzuMccNyZw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/pm@2.12.0': + resolution: {integrity: sha512-TNzVwpeNzFfHAcYTOKqX9iU4fRxliyoZrCnERR+RRzeg7gWrXrCLubQt1WEx0sojMAfznshSL3M5HGsYjEbYwA==} + + '@tiptap/react@2.12.0': + resolution: {integrity: sha512-D+PR+4kJO9h8AB/7XyQ/Anw8tqeS2ecv5QemBOCHi9JlMAjytauUrj6IfFBO9RbsCowlBjW5GnSpFhzpk2Gghg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tiptap/suggestion@2.12.0': + resolution: {integrity: sha512-bsXLoZbjUo1oOF1Z+XSfoGzbcnrTcYtJdfylM/FerMLU9T12dhsM/Ri2SKLX4IR5D0HJ07FcsEHCrGEy8Y5y0A==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tybys/wasm-util@0.9.0': + resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.7': + resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/dom-to-image@2.6.7': + resolution: {integrity: sha512-me5VbCv+fcXozblWwG13krNBvuEOm6kA5xoa4RrjDJCNFOZSWR3/QLtOXimBHk1Fisq69Gx3JtOoXtg1N1tijg==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + + '@types/fontkit@2.0.8': + resolution: {integrity: sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/js-cookie@3.0.6': + resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} + + '@types/katex@0.16.7': + resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} + + '@types/linkify-it@3.0.5': + resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/luxon@3.6.2': + resolution: {integrity: sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==} + + '@types/markdown-it@13.0.9': + resolution: {integrity: sha512-1XPwR0+MgXLWfTn9gCsZ55AHOKW1WN+P9vr0PaQh5aerR9LLQXUbjfEAFhjmEmyoYFWAyuN2Mqkn40MZ4ukjBw==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdurl@1.0.5': + resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + + '@types/node-fetch@2.6.12': + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} + + '@types/node@17.0.45': + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + + '@types/node@18.19.100': + resolution: {integrity: sha512-ojmMP8SZBKprc3qGrGk8Ujpo80AXkrP7G2tOT4VWr5jlr5DHjsJF+emXJz+Wm0glmy4Js62oKMdZZ6B9Y+tEcA==} + + '@types/node@22.15.17': + resolution: {integrity: sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==} + + '@types/prismjs@1.26.5': + resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} + + '@types/react-calendar-heatmap@1.9.0': + resolution: {integrity: sha512-BH8M/nsXoLGa3hxWbrq3guPwlK0cV+w1i4c/ktrTxTzN5fBths6WbeUZ4dK0+tE76qiGoVSo9Tse8WVVuMIV+w==} + + '@types/react-dom@19.1.5': + resolution: {integrity: sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg==} + peerDependencies: + '@types/react': ^19.0.0 + + '@types/react-slick@0.23.13': + resolution: {integrity: sha512-bNZfDhe/L8t5OQzIyhrRhBr/61pfBcWaYJoq6UDqFtv5LMwfg4NsVDD2J8N01JqdAdxLjOt66OZEp6PX+dGs/A==} + + '@types/react@19.1.4': + resolution: {integrity: sha512-EB1yiiYdvySuIITtD5lhW4yPyJ31RkJkkDw794LaQYrxCSaQV/47y5o1FMC4zF9ZyjUjzJMZwbovEnT5yHTW6g==} + + '@types/sanitize-html@2.16.0': + resolution: {integrity: sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==} + + '@types/sax@1.2.7': + resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + + '@types/turndown@5.0.5': + resolution: {integrity: sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@vitejs/plugin-react@4.4.1': + resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + + '@xyflow/react@12.6.0': + resolution: {integrity: sha512-YzsSK4SlpC6e9Ki1g6O9B1UH7xvz/bzWF+tJ+vWDD8Am5xJmFn0jYnCEuqvzvH8dRKb1NFBmyuqEGqWN39xXsA==} + peerDependencies: + react: '>=17' + react-dom: '>=17' + + '@xyflow/system@0.0.57': + resolution: {integrity: sha512-1YpBo0WgmZLR5wQw9Jvk3Tu0gISi/oYc4uSimrDuAsA/G2rGleulLrKkM59uuT/QU5m6DYC2VdBDAzjSNMGuBA==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ai@5.0.0-beta.34: + resolution: {integrity: sha512-AFJ4p35AxA+1KFtnoouePLaAUpoj0IxIAoq/xgIv88qzYajTg4Sac5KaV4CDHFRLoF0L2cwhlFXt/Ss/zyBKkA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4 + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + astro@5.7.13: + resolution: {integrity: sha512-cRGq2llKOhV3XMcYwQpfBIUcssN6HEK5CRbcMxAfd9OcFhvWE7KUy50zLioAZVVl3AqgUTJoNTlmZfD2eG0G1w==} + engines: {node: ^18.17.1 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + attr-accept@2.2.5: + resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-64@1.0.0: + resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} + + base64-js@0.0.8: + resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} + engines: {node: '>= 0.4'} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + blob-to-buffer@1.2.9: + resolution: {integrity: sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + boxen@8.0.1: + resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} + engines: {node: '>=18'} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brotli@1.3.3: + resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} + + browserslist@4.24.5: + resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + + camelize@1.0.1: + resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} + + caniuse-lite@1.0.30001717: + resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + ci-info@4.2.0: + resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} + engines: {node: '>=8'} + + classcat@5.0.5: + resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} + + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + + cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + common-ancestor-path@1.0.1: + resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + cross-fetch@3.2.0: + resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + css-background-parser@0.1.0: + resolution: {integrity: sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==} + + css-box-shadow@1.0.0-3: + resolution: {integrity: sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==} + + css-color-keywords@1.0.0: + resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} + engines: {node: '>=4'} + + css-gradient-parser@0.0.16: + resolution: {integrity: sha512-3O5QdqgFRUbXvK1x5INf1YkBz1UKSWqrd63vWsum8MNHDBYD5urm3QtxZbKU259OrEXNM26lP/MPY3d1IGkBgA==} + engines: {node: '>=16'} + + css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + + css-to-react-native@3.2.0: + resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} + + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + csv-parser@3.2.0: + resolution: {integrity: sha512-fgKbp+AJbn1h2dcAHKIdKNSSjfp43BZZykXsCjzALjKy80VXQNHPFJ6T9Afwdzoj24aMkq8GwDS7KGcDPpejrA==} + engines: {node: '>= 10'} + hasBin: true + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.1.0: + resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + deterministic-object-hash@2.0.2: + resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==} + engines: {node: '>=18'} + + devalue@5.1.1: + resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dfa@1.2.0: + resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + dom-to-image@2.6.0: + resolution: {integrity: sha512-Dt0QdaHmLpjURjU7Tnu3AgYSF2LuOmksSGsUcE6ItvJoCWTBEmiMXcqBdNSAm9+QbbwD7JMoVsuuKX6ZVQv1qA==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dracula-prism@2.1.16: + resolution: {integrity: sha512-fNZU8sMYOFYq/K8WFtsVUJEHemYlQJy7E3wm+Lndp3hTWG+Hp3+sCcbQdWVvQTfw+xIJeI+mIrjfUWHb9Q/s2Q==} + + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.151: + resolution: {integrity: sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA==} + + email-addresses@5.0.0: + resolution: {integrity: sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==} + + emoji-regex-xs@2.0.1: + resolution: {integrity: sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==} + engines: {node: '>=10.0.0'} + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + enhanced-resolve@5.18.1: + resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.0: + resolution: {integrity: sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==} + engines: {node: '>=0.12'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.25.4: + resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + eventsource-parser@3.0.3: + resolution: {integrity: sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==} + engines: {node: '>=20.0.0'} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fdir@6.4.4: + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fflate@0.7.4: + resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} + + file-selector@2.1.2: + resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==} + engines: {node: '>= 12'} + + filename-reserved-regex@2.0.0: + resolution: {integrity: sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==} + engines: {node: '>=4'} + + filenamify@4.3.0: + resolution: {integrity: sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==} + engines: {node: '>=8'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + + fontace@0.3.0: + resolution: {integrity: sha512-czoqATrcnxgWb/nAkfyIrRp6Q8biYj7nGnL6zfhTcX+JKKpWHFBnb8uNMw/kZr7u++3Y3wYSYoZgHkCcsuBpBg==} + + fontkit@2.0.4: + resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + engines: {node: '>=14.14'} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.10.0: + resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} + + gh-pages@6.3.0: + resolution: {integrity: sha512-Ot5lU6jK0Eb+sszG8pciXdjMXdBJ5wODvgjR+imihTqsUWF2K6dJ9HST55lgqcs8wWcw6o6wAsUzfcYRhJPXbA==} + engines: {node: '>=10'} + hasBin: true + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + + h3@1.15.3: + resolution: {integrity: sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-from-html-isomorphic@2.0.0: + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-parse5@8.0.0: + resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hex-rgb@4.3.0: + resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==} + engines: {node: '>=6'} + + htm@3.1.1: + resolution: {integrity: sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==} + + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + + http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + image-size@2.0.2: + resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==} + engines: {node: '>=16.x'} + hasBin: true + + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + inline-style-parser@0.2.4: + resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-absolute-url@4.0.1: + resolution: {integrity: sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + jose@6.0.11: + resolution: {integrity: sha512-QxG7EaliDARm1O1S8BGakqncGT9s25bKL1WSf6/oa17Tkqwi8D2ZNglqCF+DsYF88/rV66Q/Q2mFAy697E1DUg==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + katex@0.16.22: + resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==} + hasBin: true + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + lightningcss-darwin-arm64@1.29.2: + resolution: {integrity: sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.29.2: + resolution: {integrity: sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.29.2: + resolution: {integrity: sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.29.2: + resolution: {integrity: sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.29.2: + resolution: {integrity: sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.29.2: + resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.29.2: + resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.29.2: + resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.29.2: + resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.29.2: + resolution: {integrity: sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.29.2: + resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} + engines: {node: '>= 12.0.0'} + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + linebreak@1.1.0: + resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.503.0: + resolution: {integrity: sha512-HGGkdlPWQ0vTF8jJ5TdIqhQXZi6uh3LnNgfZ8MHiuxFfX3RZeA79r2MW2tHAZKlAVfoNE8esm3p+O6VkIvpj6w==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + lucide-react@0.511.0: + resolution: {integrity: sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + luxon@3.6.1: + resolution: {integrity: sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==} + engines: {node: '>=12'} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + + markdown-it-async@2.2.0: + resolution: {integrity: sha512-sITME+kf799vMeO/ww/CjH6q+c05f6TLpn6VOmmWCGNqPJzSh+uFgZoMB9s0plNtW6afy63qglNAC3MhrhP/gg==} + + markdown-it-task-lists@2.1.1: + resolution: {integrity: sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-math@3.0.0: + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.0.2: + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} + engines: {node: '>= 18'} + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanoid@5.1.5: + resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} + engines: {node: ^18 || >=20} + hasBin: true + + nanostores@1.0.1: + resolution: {integrity: sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw==} + engines: {node: ^20.0.0 || >=22.0.0} + + neotraverse@0.6.18: + resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} + engines: {node: '>= 10'} + + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch-native@1.6.6: + resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-html-parser@7.0.1: + resolution: {integrity: sha512-KGtmPY2kS0thCWGK0VuPyOS+pBKhhe8gXztzA2ilAOhbUbxa9homF1bOyKvhGzMLXUoRds9IOmr/v5lr/lqNmA==} + + node-mock-http@1.0.0: + resolution: {integrity: sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-check-updates@18.0.1: + resolution: {integrity: sha512-MO7mLp/8nm6kZNLLyPgz4gHmr9tLoU+pWPLdXuGAx+oZydBHkHWN0ibTonsrfwC2WEQNIQxuZagYwB67JQpAuw==} + engines: {node: ^18.18.0 || >=20.0.0, npm: '>=8.12.1'} + hasBin: true + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-path@0.11.8: + resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} + engines: {node: '>= 10.12.0'} + + ofetch@1.4.1: + resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + + oniguruma-to-es@4.3.3: + resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==} + + openai@4.100.0: + resolution: {integrity: sha512-9soq/wukv3utxcuD7TWFqKdKp0INWdeyhUCvxwrne5KwnxaCp4eHL4GdT/tMFhYolxgNhxFzg5GFwM331Z5CZg==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@6.2.0: + resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==} + engines: {node: '>=18'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-queue@8.1.0: + resolution: {integrity: sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw==} + engines: {node: '>=18'} + + p-timeout@6.1.4: + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + + pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + + parse-css-color@0.2.1: + resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + + parse-srcset@1.0.2: + resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + playwright-core@1.52.0: + resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.52.0: + resolution: {integrity: sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==} + engines: {node: '>=18'} + hasBin: true + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-replace@2.0.1: + resolution: {integrity: sha512-T83GVovCkBQkFCTmuid0B2bWNu/O0Bh/HDMeEGFC62EwMvVBLZQFYM7iBbcGT48QDXSNSX6e/X1Q7/Syh5NFng==} + engines: {node: ^12 || ^14 || >=16} + peerDependencies: + postcss: ^8.4 + + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} + + prettier-plugin-astro@0.14.1: + resolution: {integrity: sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==} + engines: {node: ^14.15.0 || >=16.0.0} + + prettier-plugin-tailwindcss@0.6.11: + resolution: {integrity: sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==} + engines: {node: '>=14.21.3'} + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-import-sort: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-style-order: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-import-sort: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-style-order: + optional: true + prettier-plugin-svelte: + optional: true + + prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + engines: {node: '>=14'} + hasBin: true + + prism-react-renderer@2.4.1: + resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} + peerDependencies: + react: '>=16.0.0' + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + property-information@6.5.0: + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + prosemirror-changeset@2.3.0: + resolution: {integrity: sha512-8wRKhlEwEJ4I13Ju54q2NZR1pVKGTgJ/8XsQ8L5A5uUsQ/YQScQJuEAuh8Bn8i6IwAMjjLRABd9lVli+DlIiVw==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.7.1: + resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} + + prosemirror-dropcursor@1.8.2: + resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} + + prosemirror-gapcursor@1.3.2: + resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==} + + prosemirror-history@1.4.1: + resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==} + + prosemirror-inputrules@1.5.0: + resolution: {integrity: sha512-K0xJRCmt+uSw7xesnHmcn72yBGTbY45vm8gXI4LZXbx2Z0jwh5aF9xrGQgrVPu0WbyFVFF3E/o9VhJYz6SQWnA==} + + prosemirror-keymap@1.2.3: + resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} + + prosemirror-markdown@1.13.2: + resolution: {integrity: sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==} + + prosemirror-menu@1.2.5: + resolution: {integrity: sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==} + + prosemirror-model@1.25.1: + resolution: {integrity: sha512-AUvbm7qqmpZa5d9fPKMvH1Q5bqYQvAZWOGRvxsB6iFLyycvC9MwNemNVjHVrWgjaoxAfY8XVg7DbvQ/qxvI9Eg==} + + prosemirror-schema-basic@1.2.4: + resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==} + + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} + + prosemirror-state@1.4.3: + resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} + + prosemirror-tables@1.7.1: + resolution: {integrity: sha512-eRQ97Bf+i9Eby99QbyAiyov43iOKgWa7QCGly+lrDt7efZ1v8NWolhXiB43hSDGIXT1UXgbs4KJN3a06FGpr1Q==} + + prosemirror-trailing-node@3.0.0: + resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.10.4: + resolution: {integrity: sha512-pwDy22nAnGqNR1feOQKHxoFkkUtepoFAd3r2hbEDsnf4wp57kKA36hXsB3njA9FtONBEwSDnDeCiJe+ItD+ykw==} + + prosemirror-view@1.39.2: + resolution: {integrity: sha512-BmOkml0QWNob165gyUxXi5K5CVUgVPpqMEAAml/qzgKn9boLUWVPzQ6LtzXw8Cn1GtRQX4ELumPxqtLTDaAKtg==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + radix-ui@1.4.2: + resolution: {integrity: sha512-fT/3YFPJzf2WUpqDoQi005GS8EpCi+53VhcLaHUj5fwkPYiZAjk1mSxFvbMA8Uq71L03n+WysuYC+mlKkXxt/Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + react-calendar-heatmap@1.10.0: + resolution: {integrity: sha512-e5vcrzMWzKIF710egr1FpjWyuDEFeZm39nvV25muc8Wtqqi8iDOfqREELeQ9Wouqf9hhj939gq0i+iAxo7KdSw==} + peerDependencies: + react: '>=0.14.0' + + react-confetti@6.4.0: + resolution: {integrity: sha512-5MdGUcqxrTU26I2EU7ltkWPwxvucQTuqMm8dUz72z2YMqTD6s9vMcDUysk7n9jnC+lXuCPeJJ7Knf98VEYE9Rg==} + engines: {node: '>=16'} + peerDependencies: + react: ^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 + + react-dom@19.1.0: + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + peerDependencies: + react: ^19.1.0 + + react-dropzone@14.3.8: + resolution: {integrity: sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==} + engines: {node: '>= 10.13'} + peerDependencies: + react: '>= 16.8 || 18.0.0' + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-resizable-panels@3.0.2: + resolution: {integrity: sha512-j4RNII75fnHkLnbsTb5G5YsDvJsSEZrJK2XSF2z0Tc2jIonYlIVir/Yh/5LvcUFCfs1HqrMAoiBFmIrRjC4XnA==} + peerDependencies: + react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-textarea-autosize@8.5.9: + resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} + engines: {node: '>=10'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-tooltip@5.28.1: + resolution: {integrity: sha512-ZA4oHwoIIK09TS7PvSLFcRlje1wGZaxw6xHvfrzn6T82UcMEfEmHVCad16Gnr4NDNDh93HyN037VK4HDi5odfQ==} + peerDependencies: + react: '>=16.14.0' + react-dom: '>=16.14.0' + + react@19.1.0: + resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + engines: {node: '>=0.10.0'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.0.1: + resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} + + rehype-external-links@3.0.0: + resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==} + + rehype-katex@7.0.1: + resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + rehype@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-math@6.0.0: + resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-smartypants@3.0.2: + resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==} + engines: {node: '>=16.0.0'} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + restructure@3.0.2: + resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} + + retext-latin@4.0.0: + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} + + retext-smartypants@6.2.0: + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + + retext-stringify@4.0.0: + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} + + retext@9.0.0: + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + roadmap-renderer@1.0.7: + resolution: {integrity: sha512-qn06f17ChBD6JiCTivZPMdHro5U9w7dJymApid9e0yUBjPisVRPPNxs2N6sPcom74qic4+YDIJ/vUnkspJ2MdA==} + + rollup@4.40.2: + resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + s.color@0.0.15: + resolution: {integrity: sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==} + + sanitize-html@2.17.0: + resolution: {integrity: sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==} + + sass-formatter@0.7.9: + resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==} + + satori-html@0.3.2: + resolution: {integrity: sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==} + + satori@0.13.1: + resolution: {integrity: sha512-FlXblaCRDOONmz4JSIG9lUxSIklBZsMVwfLkvXv0MaHa3H6GWZDZccpcCeLqdQ6RjBkYMSh6zZDxkkBFJ4M61A==} + engines: {node: '>=16'} + + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + + server-destroy@1.0.1: + resolution: {integrity: sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + sharp@0.34.1: + resolution: {integrity: sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shiki@3.4.2: + resolution: {integrity: sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sitemap@8.0.0: + resolution: {integrity: sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A==} + engines: {node: '>=14.0.0', npm: '>=6.0.0'} + hasBin: true + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slugify@1.6.6: + resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==} + engines: {node: '>=8.0.0'} + + smol-toml@1.3.4: + resolution: {integrity: sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==} + engines: {node: '>= 18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + stream-replace-string@2.0.0: + resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string.prototype.codepointat@0.2.1: + resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + + strip-outer@1.0.1: + resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} + engines: {node: '>=0.10.0'} + + style-to-js@1.1.17: + resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==} + + style-to-object@1.0.9: + resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==} + + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + suf-log@2.5.3: + resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==} + + swr@2.3.5: + resolution: {integrity: sha512-4e7pjTVulZTIL+b/S0RYFsgDcTcXPLUOvBPqyh9YdD+PkHeEMoaPwDmF9Kv6I1nnPg1OFKhiiEYpsYaaE2W2jA==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + tailwind-merge@3.3.0: + resolution: {integrity: sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==} + + tailwind-scrollbar@4.0.2: + resolution: {integrity: sha512-wAQiIxAPqk0MNTPptVe/xoyWi27y+NRGnTwvn4PQnbvB9kp8QUBiGl/wsfoVBHnQxTmhXJSNt9NHTmcz9EivFA==} + engines: {node: '>=12.13.0'} + peerDependencies: + tailwindcss: 4.x + + tailwindcss@4.1.5: + resolution: {integrity: sha512-nYtSPfWGDiWgCkwQG/m+aX83XCwf62sBgg3bIlNiiOcggnS1x3uVRDAuyelBFL+vJdOPPCGElxv9DjHJjRHiVA==} + + tailwindcss@4.1.7: + resolution: {integrity: sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg==} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + throttleit@2.1.0: + resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} + engines: {node: '>=18'} + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + + tippy.js@6.3.7: + resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + + tiptap-markdown@0.8.10: + resolution: {integrity: sha512-iDVkR2BjAqkTDtFX0h94yVvE2AihCXlF0Q7RIXSJPRSR5I0PA1TMuAg6FHFpmqTn4tPxJ0by0CK7PUMlnFLGEQ==} + peerDependencies: + '@tiptap/core': ^2.0.3 + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trim-repeated@1.0.0: + resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} + engines: {node: '>=0.10.0'} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tsconfck@3.1.5: + resolution: {integrity: sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsup@8.4.0: + resolution: {integrity: sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + tsx@4.19.4: + resolution: {integrity: sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==} + engines: {node: '>=18.0.0'} + hasBin: true + + turndown@7.2.0: + resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==} + + tween-functions@1.2.0: + resolution: {integrity: sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unicode-properties@1.4.1: + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} + + unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.5.0: + resolution: {integrity: sha512-4DueXMP5Hy4n607sh+vJ+rajoLu778aU3GzqeTCqsD/EaUcvqZT9wPC8kgK6Vjh22ZskrxyRCR71FwNOaYn6jA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + + unist-util-modify-children@4.0.0: + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-children@3.0.0: + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + + unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unstorage@1.16.0: + resolution: {integrity: sha512-WQ37/H5A7LcRPWfYOrDa1Ys02xAbpPJq6q5GkO88FBXVSQzHd7+BjEwfRqyaSWCv9MbsJy058GWjjPjcJ16GGA==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6.0.3 || ^7.0.0 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/kv': ^1.0.1 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-composed-ref@1.4.0: + resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-isomorphic-layout-effect@1.2.0: + resolution: {integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-latest@1.3.0: + resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.2: + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@6.3.5: + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.0.6: + resolution: {integrity: sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + vite: + optional: true + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + + which-pm-runs@1.1.0: + resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} + engines: {node: '>=4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + widest-line@5.0.0: + resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} + engines: {node: '>=18'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yocto-queue@1.2.1: + resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} + engines: {node: '>=12.20'} + + yocto-spinner@0.2.2: + resolution: {integrity: sha512-21rPcM3e4vCpOXThiFRByX8amU5By1R0wNS8Oex+DP3YgC8xdU0vEJ/K8cbPLiIJVosSSysgcFof6s6MSD5/Vw==} + engines: {node: '>=18.19'} + + yoctocolors@2.1.1: + resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} + engines: {node: '>=18'} + + yoga-wasm-web@0.3.3: + resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} + + zod-to-json-schema@3.24.5: + resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} + peerDependencies: + zod: ^3.24.1 + + zod-to-ts@1.2.0: + resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==} + peerDependencies: + typescript: ^4.9.4 || ^5.0.2 + zod: ^3 + + zod@3.24.4: + resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} + + zod@4.0.17: + resolution: {integrity: sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ==} + + zustand@4.5.6: + resolution: {integrity: sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + + zustand@5.0.4: + resolution: {integrity: sha512-39VFTN5InDtMd28ZhjLyuTnlytDr9HfwO512Ai4I8ZABCoyAj4F1+sr7sD1jP/+p7k77Iko0Pb5NhgBFDCX0kQ==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@ai-sdk/gateway@1.0.0-beta.19(zod@4.0.17)': + dependencies: + '@ai-sdk/provider': 2.0.0-beta.2 + '@ai-sdk/provider-utils': 3.0.0-beta.10(zod@4.0.17) + zod: 4.0.17 + + '@ai-sdk/google@1.2.18(zod@4.0.17)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@4.0.17) + zod: 4.0.17 + + '@ai-sdk/provider-utils@2.2.8(zod@4.0.17)': + dependencies: + '@ai-sdk/provider': 1.1.3 + nanoid: 3.3.11 + secure-json-parse: 2.7.0 + zod: 4.0.17 + + '@ai-sdk/provider-utils@3.0.0-beta.10(zod@4.0.17)': + dependencies: + '@ai-sdk/provider': 2.0.0-beta.2 + '@standard-schema/spec': 1.0.0 + eventsource-parser: 3.0.3 + zod: 4.0.17 + zod-to-json-schema: 3.24.5(zod@4.0.17) + + '@ai-sdk/provider@1.1.3': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@2.0.0-beta.2': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/react@2.0.0-beta.34(react@19.1.0)(zod@4.0.17)': + dependencies: + '@ai-sdk/provider-utils': 3.0.0-beta.10(zod@4.0.17) + ai: 5.0.0-beta.34(zod@4.0.17) + react: 19.1.0 + swr: 2.3.5(react@19.1.0) + throttleit: 2.1.0 + optionalDependencies: + zod: 4.0.17 + + '@alloc/quick-lru@5.2.0': {} + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@astrojs/compiler@2.12.0': {} + + '@astrojs/internal-helpers@0.6.1': {} + + '@astrojs/markdown-remark@6.3.1': + dependencies: + '@astrojs/internal-helpers': 0.6.1 + '@astrojs/prism': 3.2.0 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + import-meta-resolve: 4.1.0 + js-yaml: 4.1.0 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.2 + shiki: 3.4.2 + smol-toml: 1.3.4 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.0.0 + unist-util-visit-parents: 6.0.1 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/node@9.2.1(astro@5.7.13(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.40.2)(tsx@4.19.4)(typescript@5.8.3))': + dependencies: + '@astrojs/internal-helpers': 0.6.1 + astro: 5.7.13(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.40.2)(tsx@4.19.4)(typescript@5.8.3) + send: 1.2.0 + server-destroy: 1.0.1 + transitivePeerDependencies: + - supports-color + + '@astrojs/prism@3.2.0': + dependencies: + prismjs: 1.30.0 + + '@astrojs/react@4.2.7(@types/node@22.15.17)(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(jiti@2.4.2)(lightningcss@1.30.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tsx@4.19.4)': + dependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + '@vitejs/plugin-react': 4.4.1(vite@6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + ultrahtml: 1.6.0 + vite: 6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + '@astrojs/sitemap@3.4.0': + dependencies: + sitemap: 8.0.0 + stream-replace-string: 2.0.0 + zod: 3.24.4 + + '@astrojs/telemetry@3.2.1': + dependencies: + ci-info: 4.2.0 + debug: 4.4.0 + dlv: 1.1.3 + dset: 3.1.4 + is-docker: 3.0.0 + is-wsl: 3.1.0 + which-pm-runs: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.27.2': {} + + '@babel/core@7.27.1': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) + '@babel/helpers': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.1 + '@babel/types': 7.27.1 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.27.1': + dependencies: + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.27.2 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.24.5 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.27.1 + '@babel/types': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)': + dependencies: + '@babel/core': 7.27.1 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.27.1': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.27.1 + + '@babel/parser@7.27.2': + dependencies: + '@babel/types': 7.27.1 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.1)': + dependencies: + '@babel/core': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.27.1)': + dependencies: + '@babel/core': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/runtime@7.27.1': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 + + '@babel/traverse@7.27.1': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/template': 7.27.2 + '@babel/types': 7.27.1 + debug: 4.4.0 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.27.1': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@capsizecss/unpack@2.4.0': + dependencies: + blob-to-buffer: 1.2.9 + cross-fetch: 3.2.0 + fontkit: 2.0.4 + transitivePeerDependencies: + - encoding + + '@emnapi/core@1.4.3': + dependencies: + '@emnapi/wasi-threads': 1.0.2 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.4.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.0.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.25.4': + optional: true + + '@esbuild/android-arm64@0.25.4': + optional: true + + '@esbuild/android-arm@0.25.4': + optional: true + + '@esbuild/android-x64@0.25.4': + optional: true + + '@esbuild/darwin-arm64@0.25.4': + optional: true + + '@esbuild/darwin-x64@0.25.4': + optional: true + + '@esbuild/freebsd-arm64@0.25.4': + optional: true + + '@esbuild/freebsd-x64@0.25.4': + optional: true + + '@esbuild/linux-arm64@0.25.4': + optional: true + + '@esbuild/linux-arm@0.25.4': + optional: true + + '@esbuild/linux-ia32@0.25.4': + optional: true + + '@esbuild/linux-loong64@0.25.4': + optional: true + + '@esbuild/linux-mips64el@0.25.4': + optional: true + + '@esbuild/linux-ppc64@0.25.4': + optional: true + + '@esbuild/linux-riscv64@0.25.4': + optional: true + + '@esbuild/linux-s390x@0.25.4': + optional: true + + '@esbuild/linux-x64@0.25.4': + optional: true + + '@esbuild/netbsd-arm64@0.25.4': + optional: true + + '@esbuild/netbsd-x64@0.25.4': + optional: true + + '@esbuild/openbsd-arm64@0.25.4': + optional: true + + '@esbuild/openbsd-x64@0.25.4': + optional: true + + '@esbuild/sunos-x64@0.25.4': + optional: true + + '@esbuild/win32-arm64@0.25.4': + optional: true + + '@esbuild/win32-ia32@0.25.4': + optional: true + + '@esbuild/win32-x64@0.25.4': + optional: true + + '@fingerprintjs/fingerprintjs@4.6.2': + dependencies: + tslib: 2.8.1 + + '@floating-ui/core@1.7.0': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.7.0': + dependencies: + '@floating-ui/core': 1.7.0 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/react-dom@2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/dom': 1.7.0 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@floating-ui/utils@0.2.9': {} + + '@img/sharp-darwin-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true + + '@img/sharp-darwin-arm64@0.34.1': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.1.0 + optional: true + + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 + optional: true + + '@img/sharp-darwin-x64@0.34.1': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.1.0 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-darwin-arm64@1.1.0': + optional: true + + '@img/sharp-libvips-darwin-x64@1.0.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.1.0': + optional: true + + '@img/sharp-libvips-linux-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.1.0': + optional: true + + '@img/sharp-libvips-linux-arm@1.0.5': + optional: true + + '@img/sharp-libvips-linux-arm@1.1.0': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.1.0': + optional: true + + '@img/sharp-libvips-linux-s390x@1.0.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.1.0': + optional: true + + '@img/sharp-libvips-linux-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.1.0': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.1.0': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.1.0': + optional: true + + '@img/sharp-linux-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.4 + optional: true + + '@img/sharp-linux-arm64@0.34.1': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.1.0 + optional: true + + '@img/sharp-linux-arm@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.5 + optional: true + + '@img/sharp-linux-arm@0.34.1': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.1.0 + optional: true + + '@img/sharp-linux-s390x@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.4 + optional: true + + '@img/sharp-linux-s390x@0.34.1': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.1.0 + optional: true + + '@img/sharp-linux-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.4 + optional: true + + '@img/sharp-linux-x64@0.34.1': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.1.0 + optional: true + + '@img/sharp-linuxmusl-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.1': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 + optional: true + + '@img/sharp-linuxmusl-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.1': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.1.0 + optional: true + + '@img/sharp-wasm32@0.33.5': + dependencies: + '@emnapi/runtime': 1.4.3 + optional: true + + '@img/sharp-wasm32@0.34.1': + dependencies: + '@emnapi/runtime': 1.4.3 + optional: true + + '@img/sharp-win32-ia32@0.33.5': + optional: true + + '@img/sharp-win32-ia32@0.34.1': + optional: true + + '@img/sharp-win32-x64@0.33.5': + optional: true + + '@img/sharp-win32-x64@0.34.1': + optional: true + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@microsoft/clarity@1.0.0': {} + + '@mixmark-io/domino@2.2.0': {} + + '@nanostores/react@1.0.0(nanostores@1.0.1)(react@19.1.0)': + dependencies: + nanostores: 1.0.1 + react: 19.1.0 + + '@napi-rs/image-android-arm64@1.9.2': + optional: true + + '@napi-rs/image-darwin-arm64@1.9.2': + optional: true + + '@napi-rs/image-darwin-x64@1.9.2': + optional: true + + '@napi-rs/image-freebsd-x64@1.9.2': + optional: true + + '@napi-rs/image-linux-arm-gnueabihf@1.9.2': + optional: true + + '@napi-rs/image-linux-arm64-gnu@1.9.2': + optional: true + + '@napi-rs/image-linux-arm64-musl@1.9.2': + optional: true + + '@napi-rs/image-linux-x64-gnu@1.9.2': + optional: true + + '@napi-rs/image-linux-x64-musl@1.9.2': + optional: true + + '@napi-rs/image-wasm32-wasi@1.9.2': + dependencies: + '@napi-rs/wasm-runtime': 0.2.9 + optional: true + + '@napi-rs/image-win32-ia32-msvc@1.9.2': + optional: true + + '@napi-rs/image-win32-x64-msvc@1.9.2': + optional: true + + '@napi-rs/image@1.9.2': + optionalDependencies: + '@napi-rs/image-android-arm64': 1.9.2 + '@napi-rs/image-darwin-arm64': 1.9.2 + '@napi-rs/image-darwin-x64': 1.9.2 + '@napi-rs/image-freebsd-x64': 1.9.2 + '@napi-rs/image-linux-arm-gnueabihf': 1.9.2 + '@napi-rs/image-linux-arm64-gnu': 1.9.2 + '@napi-rs/image-linux-arm64-musl': 1.9.2 + '@napi-rs/image-linux-x64-gnu': 1.9.2 + '@napi-rs/image-linux-x64-musl': 1.9.2 + '@napi-rs/image-wasm32-wasi': 1.9.2 + '@napi-rs/image-win32-ia32-msvc': 1.9.2 + '@napi-rs/image-win32-x64-msvc': 1.9.2 + + '@napi-rs/wasm-runtime@0.2.9': + dependencies: + '@emnapi/core': 1.4.3 + '@emnapi/runtime': 1.4.3 + '@tybys/wasm-util': 0.9.0 + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@opentelemetry/api@1.9.0': {} + + '@oslojs/encoding@1.1.0': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@playwright/test@1.52.0': + dependencies: + playwright: 1.52.0 + + '@popperjs/core@2.11.8': {} + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.2': {} + + '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-accordion@1.2.11(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collapsible': 1.1.11(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-alert-dialog@1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dialog': 1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-collapsible@1.1.11(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-context-menu@2.2.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-context@1.1.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-dialog@1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.1(@types/react@19.1.4)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-direction@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-dropdown-menu@2.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-form@0.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-hover-card@1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-id@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-menu@2.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.1(@types/react@19.1.4)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-menubar@1.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-navigation-menu@1.2.13(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-one-time-password-field@0.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-password-toggle-field@0.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-popover@1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.1(@types/react@19.1.4)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-popper@1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/react-dom': 2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/rect': 1.1.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-progress@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-radio-group@1.3.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-scroll-area@1.2.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-select@2.2.5(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.1(@types/react@19.1.4)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-slider@1.3.5(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-slot@1.2.3(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-switch@1.2.5(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-tabs@1.1.12(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-toast@1.2.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-toggle-group@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-toggle@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-toolbar@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle-group': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-tooltip@1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + use-sync-external-store: 1.5.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/rect@1.1.1': {} + + '@remirror/core-constants@3.0.0': {} + + '@resvg/resvg-js-android-arm-eabi@2.6.2': + optional: true + + '@resvg/resvg-js-android-arm64@2.6.2': + optional: true + + '@resvg/resvg-js-darwin-arm64@2.6.2': + optional: true + + '@resvg/resvg-js-darwin-x64@2.6.2': + optional: true + + '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': + optional: true + + '@resvg/resvg-js-linux-arm64-gnu@2.6.2': + optional: true + + '@resvg/resvg-js-linux-arm64-musl@2.6.2': + optional: true + + '@resvg/resvg-js-linux-x64-gnu@2.6.2': + optional: true + + '@resvg/resvg-js-linux-x64-musl@2.6.2': + optional: true + + '@resvg/resvg-js-win32-arm64-msvc@2.6.2': + optional: true + + '@resvg/resvg-js-win32-ia32-msvc@2.6.2': + optional: true + + '@resvg/resvg-js-win32-x64-msvc@2.6.2': + optional: true + + '@resvg/resvg-js@2.6.2': + optionalDependencies: + '@resvg/resvg-js-android-arm-eabi': 2.6.2 + '@resvg/resvg-js-android-arm64': 2.6.2 + '@resvg/resvg-js-darwin-arm64': 2.6.2 + '@resvg/resvg-js-darwin-x64': 2.6.2 + '@resvg/resvg-js-linux-arm-gnueabihf': 2.6.2 + '@resvg/resvg-js-linux-arm64-gnu': 2.6.2 + '@resvg/resvg-js-linux-arm64-musl': 2.6.2 + '@resvg/resvg-js-linux-x64-gnu': 2.6.2 + '@resvg/resvg-js-linux-x64-musl': 2.6.2 + '@resvg/resvg-js-win32-arm64-msvc': 2.6.2 + '@resvg/resvg-js-win32-ia32-msvc': 2.6.2 + '@resvg/resvg-js-win32-x64-msvc': 2.6.2 + + '@rollup/pluginutils@5.1.4(rollup@4.40.2)': + dependencies: + '@types/estree': 1.0.7 + estree-walker: 2.0.2 + picomatch: 4.0.2 + optionalDependencies: + rollup: 4.40.2 + + '@rollup/rollup-android-arm-eabi@4.40.2': + optional: true + + '@rollup/rollup-android-arm64@4.40.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.40.2': + optional: true + + '@rollup/rollup-darwin-x64@4.40.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.40.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.40.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.40.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.40.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.40.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.40.2': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.40.2': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.40.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.40.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.40.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.40.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.40.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.40.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.40.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.40.2': + optional: true + + '@shikijs/core@3.4.2': + dependencies: + '@shikijs/types': 3.4.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/core@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.4.2': + dependencies: + '@shikijs/types': 3.4.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.3 + + '@shikijs/engine-oniguruma@3.4.2': + dependencies: + '@shikijs/types': 3.4.2 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.4.2': + dependencies: + '@shikijs/types': 3.4.2 + + '@shikijs/themes@3.4.2': + dependencies: + '@shikijs/types': 3.4.2 + + '@shikijs/transformers@3.9.2': + dependencies: + '@shikijs/core': 3.9.2 + '@shikijs/types': 3.9.2 + + '@shikijs/types@3.4.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/types@3.9.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@shuding/opentype.js@1.4.0-beta.0': + dependencies: + fflate: 0.7.4 + string.prototype.codepointat: 0.2.1 + + '@standard-schema/spec@1.0.0': {} + + '@swc/helpers@0.5.17': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.1.5': + dependencies: + enhanced-resolve: 5.18.1 + jiti: 2.4.2 + lightningcss: 1.29.2 + tailwindcss: 4.1.5 + + '@tailwindcss/node@4.1.7': + dependencies: + '@ampproject/remapping': 2.3.0 + enhanced-resolve: 5.18.1 + jiti: 2.4.2 + lightningcss: 1.30.1 + magic-string: 0.30.17 + source-map-js: 1.2.1 + tailwindcss: 4.1.7 + + '@tailwindcss/oxide-android-arm64@4.1.5': + optional: true + + '@tailwindcss/oxide-android-arm64@4.1.7': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.5': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.7': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.5': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.7': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.5': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.7': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.5': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.7': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.5': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.7': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.5': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.7': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.5': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.7': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.5': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.7': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.5': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.7': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.5': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.7': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.5': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.7': + optional: true + + '@tailwindcss/oxide@4.1.5': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.5 + '@tailwindcss/oxide-darwin-arm64': 4.1.5 + '@tailwindcss/oxide-darwin-x64': 4.1.5 + '@tailwindcss/oxide-freebsd-x64': 4.1.5 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.5 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.5 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.5 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.5 + '@tailwindcss/oxide-linux-x64-musl': 4.1.5 + '@tailwindcss/oxide-wasm32-wasi': 4.1.5 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.5 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.5 + + '@tailwindcss/oxide@4.1.7': + dependencies: + detect-libc: 2.0.4 + tar: 7.4.3 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.7 + '@tailwindcss/oxide-darwin-arm64': 4.1.7 + '@tailwindcss/oxide-darwin-x64': 4.1.7 + '@tailwindcss/oxide-freebsd-x64': 4.1.7 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.7 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.7 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.7 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.7 + '@tailwindcss/oxide-linux-x64-musl': 4.1.7 + '@tailwindcss/oxide-wasm32-wasi': 4.1.7 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.7 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.7 + + '@tailwindcss/postcss@4.1.5': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.5 + '@tailwindcss/oxide': 4.1.5 + postcss: 8.5.3 + tailwindcss: 4.1.5 + + '@tailwindcss/typography@0.5.16(tailwindcss@4.1.7)': + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 4.1.7 + + '@tailwindcss/vite@4.1.7(vite@6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4))': + dependencies: + '@tailwindcss/node': 4.1.7 + '@tailwindcss/oxide': 4.1.7 + tailwindcss: 4.1.7 + vite: 6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4) + + '@tanstack/query-core@5.76.0': {} + + '@tanstack/react-query@5.76.1(react@19.1.0)': + dependencies: + '@tanstack/query-core': 5.76.0 + react: 19.1.0 + + '@tiptap/core@2.12.0(@tiptap/pm@2.12.0)': + dependencies: + '@tiptap/pm': 2.12.0 + + '@tiptap/extension-bubble-menu@2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)': + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + '@tiptap/pm': 2.12.0 + tippy.js: 6.3.7 + + '@tiptap/extension-document@2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))': + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + + '@tiptap/extension-floating-menu@2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)': + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + '@tiptap/pm': 2.12.0 + tippy.js: 6.3.7 + + '@tiptap/extension-paragraph@2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))': + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + + '@tiptap/extension-placeholder@2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)': + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + '@tiptap/pm': 2.12.0 + + '@tiptap/extension-text@2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))': + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + + '@tiptap/pm@2.12.0': + dependencies: + prosemirror-changeset: 2.3.0 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.7.1 + prosemirror-dropcursor: 1.8.2 + prosemirror-gapcursor: 1.3.2 + prosemirror-history: 1.4.1 + prosemirror-inputrules: 1.5.0 + prosemirror-keymap: 1.2.3 + prosemirror-markdown: 1.13.2 + prosemirror-menu: 1.2.5 + prosemirror-model: 1.25.1 + prosemirror-schema-basic: 1.2.4 + prosemirror-schema-list: 1.5.1 + prosemirror-state: 1.4.3 + prosemirror-tables: 1.7.1 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.2) + prosemirror-transform: 1.10.4 + prosemirror-view: 1.39.2 + + '@tiptap/react@2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + '@tiptap/extension-bubble-menu': 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0) + '@tiptap/extension-floating-menu': 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0) + '@tiptap/pm': 2.12.0 + '@types/use-sync-external-store': 0.0.6 + fast-deep-equal: 3.1.3 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + use-sync-external-store: 1.5.0(react@19.1.0) + + '@tiptap/suggestion@2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)': + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + '@tiptap/pm': 2.12.0 + + '@tybys/wasm-util@0.9.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.7 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.27.1 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 + + '@types/babel__traverse@7.20.7': + dependencies: + '@babel/types': 7.27.1 + + '@types/d3-color@3.1.3': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/dom-to-image@2.6.7': {} + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.7 + + '@types/estree@1.0.7': {} + + '@types/fontkit@2.0.8': + dependencies: + '@types/node': 22.15.17 + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/js-cookie@3.0.6': {} + + '@types/katex@0.16.7': {} + + '@types/linkify-it@3.0.5': {} + + '@types/linkify-it@5.0.0': {} + + '@types/luxon@3.6.2': {} + + '@types/markdown-it@13.0.9': + dependencies: + '@types/linkify-it': 3.0.5 + '@types/mdurl': 1.0.5 + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdurl@1.0.5': {} + + '@types/mdurl@2.0.0': {} + + '@types/ms@2.1.0': {} + + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + + '@types/node-fetch@2.6.12': + dependencies: + '@types/node': 22.15.17 + form-data: 4.0.2 + + '@types/node@17.0.45': {} + + '@types/node@18.19.100': + dependencies: + undici-types: 5.26.5 + + '@types/node@22.15.17': + dependencies: + undici-types: 6.21.0 + + '@types/prismjs@1.26.5': {} + + '@types/react-calendar-heatmap@1.9.0': + dependencies: + '@types/react': 19.1.4 + + '@types/react-dom@19.1.5(@types/react@19.1.4)': + dependencies: + '@types/react': 19.1.4 + + '@types/react-slick@0.23.13': + dependencies: + '@types/react': 19.1.4 + + '@types/react@19.1.4': + dependencies: + csstype: 3.1.3 + + '@types/sanitize-html@2.16.0': + dependencies: + htmlparser2: 8.0.2 + + '@types/sax@1.2.7': + dependencies: + '@types/node': 22.15.17 + + '@types/turndown@5.0.5': {} + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@types/use-sync-external-store@0.0.6': {} + + '@ungap/structured-clone@1.3.0': {} + + '@vitejs/plugin-react@4.4.1(vite@6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4))': + dependencies: + '@babel/core': 7.27.1 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.1) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.27.1) + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4) + transitivePeerDependencies: + - supports-color + + '@xyflow/react@12.6.0(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@xyflow/system': 0.0.57 + classcat: 5.0.5 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + zustand: 4.5.6(@types/react@19.1.4)(react@19.1.0) + transitivePeerDependencies: + - '@types/react' + - immer + + '@xyflow/system@0.0.57': + dependencies: + '@types/d3-drag': 3.0.7 + '@types/d3-selection': 3.0.11 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + d3-drag: 3.0.0 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn@8.14.1: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + ai@5.0.0-beta.34(zod@4.0.17): + dependencies: + '@ai-sdk/gateway': 1.0.0-beta.19(zod@4.0.17) + '@ai-sdk/provider': 2.0.0-beta.2 + '@ai-sdk/provider-utils': 3.0.0-beta.10(zod@4.0.17) + '@opentelemetry/api': 1.9.0 + zod: 4.0.17 + + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + aria-query@5.3.2: {} + + array-iterate@2.0.1: {} + + array-union@2.1.0: {} + + astro@5.7.13(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.40.2)(tsx@4.19.4)(typescript@5.8.3): + dependencies: + '@astrojs/compiler': 2.12.0 + '@astrojs/internal-helpers': 0.6.1 + '@astrojs/markdown-remark': 6.3.1 + '@astrojs/telemetry': 3.2.1 + '@capsizecss/unpack': 2.4.0 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.1.4(rollup@4.40.2) + acorn: 8.14.1 + aria-query: 5.3.2 + axobject-query: 4.1.0 + boxen: 8.0.1 + ci-info: 4.2.0 + clsx: 2.1.1 + common-ancestor-path: 1.0.1 + cookie: 1.0.2 + cssesc: 3.0.0 + debug: 4.4.0 + deterministic-object-hash: 2.0.2 + devalue: 5.1.1 + diff: 5.2.0 + dlv: 1.1.3 + dset: 3.1.4 + es-module-lexer: 1.7.0 + esbuild: 0.25.4 + estree-walker: 3.0.3 + flattie: 1.1.1 + fontace: 0.3.0 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.1.1 + js-yaml: 4.1.0 + kleur: 4.1.5 + magic-string: 0.30.17 + magicast: 0.3.5 + mrmime: 2.0.1 + neotraverse: 0.6.18 + p-limit: 6.2.0 + p-queue: 8.1.0 + package-manager-detector: 1.3.0 + picomatch: 4.0.2 + prompts: 2.4.2 + rehype: 13.0.2 + semver: 7.7.1 + shiki: 3.4.2 + tinyexec: 0.3.2 + tinyglobby: 0.2.13 + tsconfck: 3.1.5(typescript@5.8.3) + ultrahtml: 1.6.0 + unifont: 0.5.0 + unist-util-visit: 5.0.0 + unstorage: 1.16.0 + vfile: 6.0.3 + vite: 6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4) + vitefu: 1.0.6(vite@6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)) + xxhash-wasm: 1.1.0 + yargs-parser: 21.1.1 + yocto-spinner: 0.2.2 + zod: 3.24.4 + zod-to-json-schema: 3.24.5(zod@3.24.4) + zod-to-ts: 1.2.0(typescript@5.8.3)(zod@3.24.4) + optionalDependencies: + sharp: 0.33.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/kv' + - aws4fetch + - db0 + - encoding + - idb-keyval + - ioredis + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - yaml + + async@3.2.6: {} + + asynckit@0.4.0: {} + + attr-accept@2.2.5: {} + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + base-64@1.0.0: {} + + base64-js@0.0.8: {} + + base64-js@1.5.1: {} + + blob-to-buffer@1.2.9: {} + + boolbase@1.0.0: {} + + boxen@8.0.1: + dependencies: + ansi-align: 3.0.1 + camelcase: 8.0.0 + chalk: 5.4.1 + cli-boxes: 3.0.0 + string-width: 7.2.0 + type-fest: 4.41.0 + widest-line: 5.0.0 + wrap-ansi: 9.0.0 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brotli@1.3.3: + dependencies: + base64-js: 1.5.1 + + browserslist@4.24.5: + dependencies: + caniuse-lite: 1.0.30001717 + electron-to-chromium: 1.5.151 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.24.5) + + bundle-require@5.1.0(esbuild@0.25.4): + dependencies: + esbuild: 0.25.4 + load-tsconfig: 0.2.5 + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + camelcase@8.0.0: {} + + camelize@1.0.1: {} + + caniuse-lite@1.0.30001717: {} + + ccount@2.0.1: {} + + chalk@5.4.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chownr@3.0.0: {} + + ci-info@4.2.0: {} + + classcat@5.0.5: {} + + classnames@2.5.1: {} + + cli-boxes@3.0.0: {} + + clone@2.1.2: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + comma-separated-tokens@2.0.3: {} + + commander@13.1.0: {} + + commander@4.1.1: {} + + commander@8.3.0: {} + + common-ancestor-path@1.0.1: {} + + commondir@1.0.1: {} + + consola@3.4.2: {} + + convert-source-map@2.0.0: {} + + cookie-es@1.2.2: {} + + cookie@1.0.2: {} + + crelt@1.0.6: {} + + cross-fetch@3.2.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-background-parser@0.1.0: {} + + css-box-shadow@1.0.0-3: {} + + css-color-keywords@1.0.0: {} + + css-gradient-parser@0.0.16: {} + + css-select@5.1.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-to-react-native@3.2.0: + dependencies: + camelize: 1.0.1 + css-color-keywords: 1.0.0 + postcss-value-parser: 4.2.0 + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + + css-what@6.1.0: {} + + cssesc@3.0.0: {} + + csstype@3.1.3: {} + + csv-parser@3.2.0: {} + + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-ease@3.0.1: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-selection@3.0.0: {} + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + dayjs@1.11.13: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.1.0: + dependencies: + character-entities: 2.0.2 + + deepmerge@4.3.1: {} + + defu@6.1.4: {} + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-libc@2.0.4: {} + + detect-node-es@1.1.0: {} + + deterministic-object-hash@2.0.2: + dependencies: + base-64: 1.0.0 + + devalue@5.1.1: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dfa@1.2.0: {} + + diff@5.2.0: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dlv@1.1.3: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + dom-to-image@2.6.0: {} + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dracula-prism@2.1.16: {} + + dset@3.1.4: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.151: {} + + email-addresses@5.0.0: {} + + emoji-regex-xs@2.0.1: {} + + emoji-regex@10.4.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + enhanced-resolve@5.18.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + entities@4.5.0: {} + + entities@6.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.25.4: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.4 + '@esbuild/android-arm': 0.25.4 + '@esbuild/android-arm64': 0.25.4 + '@esbuild/android-x64': 0.25.4 + '@esbuild/darwin-arm64': 0.25.4 + '@esbuild/darwin-x64': 0.25.4 + '@esbuild/freebsd-arm64': 0.25.4 + '@esbuild/freebsd-x64': 0.25.4 + '@esbuild/linux-arm': 0.25.4 + '@esbuild/linux-arm64': 0.25.4 + '@esbuild/linux-ia32': 0.25.4 + '@esbuild/linux-loong64': 0.25.4 + '@esbuild/linux-mips64el': 0.25.4 + '@esbuild/linux-ppc64': 0.25.4 + '@esbuild/linux-riscv64': 0.25.4 + '@esbuild/linux-s390x': 0.25.4 + '@esbuild/linux-x64': 0.25.4 + '@esbuild/netbsd-arm64': 0.25.4 + '@esbuild/netbsd-x64': 0.25.4 + '@esbuild/openbsd-arm64': 0.25.4 + '@esbuild/openbsd-x64': 0.25.4 + '@esbuild/sunos-x64': 0.25.4 + '@esbuild/win32-arm64': 0.25.4 + '@esbuild/win32-ia32': 0.25.4 + '@esbuild/win32-x64': 0.25.4 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + esprima@4.0.1: {} + + estree-util-is-identifier-name@3.0.0: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.7 + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + eventemitter3@5.0.1: {} + + eventsource-parser@3.0.3: {} + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fdir@6.4.4(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + fflate@0.7.4: {} + + file-selector@2.1.2: + dependencies: + tslib: 2.8.1 + + filename-reserved-regex@2.0.0: {} + + filenamify@4.3.0: + dependencies: + filename-reserved-regex: 2.0.0 + strip-outer: 1.0.1 + trim-repeated: 1.0.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-cache-dir@3.3.2: + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + flattie@1.1.1: {} + + fontace@0.3.0: + dependencies: + '@types/fontkit': 2.0.8 + fontkit: 2.0.4 + + fontkit@2.0.4: + dependencies: + '@swc/helpers': 0.5.17 + brotli: 1.3.3 + clone: 2.1.2 + dfa: 1.2.0 + fast-deep-equal: 3.1.3 + restructure: 3.0.2 + tiny-inflate: 1.0.3 + unicode-properties: 1.4.1 + unicode-trie: 2.0.0 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data-encoder@1.7.2: {} + + form-data@4.0.2: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + + fresh@2.0.0: {} + + fs-extra@11.3.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fsevents@2.3.2: + optional: true + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-east-asian-width@1.3.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-tsconfig@4.10.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + gh-pages@6.3.0: + dependencies: + async: 3.2.6 + commander: 13.1.0 + email-addresses: 5.0.0 + filenamify: 4.3.0 + find-cache-dir: 3.3.2 + fs-extra: 11.3.0 + globby: 11.1.0 + + github-slugger@2.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + globals@11.12.0: {} + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + gray-matter@4.0.3: + dependencies: + js-yaml: 3.14.1 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + + h3@1.15.3: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.0 + radix3: 1.1.2 + ufo: 1.6.1 + uncrypto: 0.1.3 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-from-html-isomorphic@2.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-dom: 5.0.1 + hast-util-from-html: 2.0.3 + unist-util-remove-position: 5.0.0 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.2 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.7 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.17 + unist-util-position: 5.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.0: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + he@1.2.0: {} + + hex-rgb@4.3.0: {} + + htm@3.1.1: {} + + html-escaper@3.0.3: {} + + html-url-attributes@3.0.1: {} + + html-void-elements@3.0.0: {} + + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + + http-cache-semantics@4.1.1: {} + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + ignore@5.3.2: {} + + image-size@2.0.2: {} + + import-meta-resolve@4.1.0: {} + + inherits@2.0.4: {} + + inline-style-parser@0.2.4: {} + + iron-webcrypto@1.2.1: {} + + is-absolute-url@4.0.1: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-arrayish@0.3.2: {} + + is-decimal@2.0.1: {} + + is-docker@3.0.0: {} + + is-extendable@0.1.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-number@7.0.0: {} + + is-plain-obj@4.1.0: {} + + is-plain-object@5.0.0: {} + + is-wsl@3.1.0: + dependencies: + is-inside-container: 1.0.0 + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@2.4.2: {} + + jose@6.0.11: {} + + joycon@3.1.1: {} + + js-cookie@3.0.5: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-schema@0.4.0: {} + + json5@2.2.3: {} + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + katex@0.16.22: + dependencies: + commander: 8.3.0 + + kind-of@6.0.3: {} + + kleur@3.0.3: {} + + kleur@4.1.5: {} + + lightningcss-darwin-arm64@1.29.2: + optional: true + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.29.2: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.29.2: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.29.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.29.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.29.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.29.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.29.2: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.29.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.29.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.29.2: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.29.2 + lightningcss-darwin-x64: 1.29.2 + lightningcss-freebsd-x64: 1.29.2 + lightningcss-linux-arm-gnueabihf: 1.29.2 + lightningcss-linux-arm64-gnu: 1.29.2 + lightningcss-linux-arm64-musl: 1.29.2 + lightningcss-linux-x64-gnu: 1.29.2 + lightningcss-linux-x64-musl: 1.29.2 + lightningcss-win32-arm64-msvc: 1.29.2 + lightningcss-win32-x64-msvc: 1.29.2 + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + lilconfig@3.1.3: {} + + linebreak@1.1.0: + dependencies: + base64-js: 0.0.8 + unicode-trie: 2.0.0 + + lines-and-columns@1.2.4: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + load-tsconfig@0.2.5: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.castarray@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + + lodash.sortby@4.7.0: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.503.0(react@19.1.0): + dependencies: + react: 19.1.0 + + lucide-react@0.511.0(react@19.1.0): + dependencies: + react: 19.1.0 + + luxon@3.6.1: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + magicast@0.3.5: + dependencies: + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 + source-map-js: 1.2.1 + + make-dir@3.1.0: + dependencies: + semver: 6.3.1 + + markdown-it-async@2.2.0: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + + markdown-it-task-lists@2.1.1: {} + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + markdown-table@3.0.4: {} + + math-intrinsics@1.1.0: {} + + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.0.0 + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.1.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-math@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + longest-streak: 3.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + unist-util-remove-position: 5.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.0 + + mdast-util-to-hast@13.2.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdn-data@2.12.2: {} + + mdurl@2.0.0: {} + + memoize-one@5.2.1: {} + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.1.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.7 + devlop: 1.1.0 + katex: 0.16.22 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.0 + decode-named-character-reference: 1.1.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minipass@7.1.2: {} + + minizlib@3.0.2: + dependencies: + minipass: 7.1.2 + + mkdirp@3.0.1: {} + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.11: {} + + nanoid@5.1.5: {} + + nanostores@1.0.1: {} + + neotraverse@0.6.18: {} + + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + + node-domexception@1.0.0: {} + + node-fetch-native@1.6.6: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-html-parser@7.0.1: + dependencies: + css-select: 5.1.0 + he: 1.2.0 + + node-mock-http@1.0.0: {} + + node-releases@2.0.19: {} + + normalize-path@3.0.0: {} + + npm-check-updates@18.0.1: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + object-assign@4.1.1: {} + + object-path@0.11.8: {} + + ofetch@1.4.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.6 + ufo: 1.6.1 + + ohash@2.0.11: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.3: + dependencies: + oniguruma-parser: 0.12.1 + regex: 6.0.1 + regex-recursion: 6.0.2 + + openai@4.100.0(zod@4.0.17): + dependencies: + '@types/node': 18.19.100 + '@types/node-fetch': 2.6.12 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + optionalDependencies: + zod: 4.0.17 + transitivePeerDependencies: + - encoding + + orderedmap@2.1.1: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@6.2.0: + dependencies: + yocto-queue: 1.2.1 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-queue@8.1.0: + dependencies: + eventemitter3: 5.0.1 + p-timeout: 6.1.4 + + p-timeout@6.1.4: {} + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + package-manager-detector@1.3.0: {} + + pako@0.2.9: {} + + parse-css-color@0.2.1: + dependencies: + color-name: 1.1.4 + hex-rgb: 4.3.0 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.1.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-latin@7.0.0: + dependencies: + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + + parse-srcset@1.0.2: {} + + parse5@7.3.0: + dependencies: + entities: 6.0.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-type@4.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + playwright-core@1.52.0: {} + + playwright@1.52.0: + dependencies: + playwright-core: 1.52.0 + optionalDependencies: + fsevents: 2.3.2 + + postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.4.2 + postcss: 8.5.3 + tsx: 4.19.4 + + postcss-replace@2.0.1(postcss@8.5.3): + dependencies: + kind-of: 6.0.3 + object-path: 0.11.8 + postcss: 8.5.3 + + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.3: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier-plugin-astro@0.14.1: + dependencies: + '@astrojs/compiler': 2.12.0 + prettier: 3.5.3 + sass-formatter: 0.7.9 + + prettier-plugin-tailwindcss@0.6.11(prettier-plugin-astro@0.14.1)(prettier@3.5.3): + dependencies: + prettier: 3.5.3 + optionalDependencies: + prettier-plugin-astro: 0.14.1 + + prettier@3.5.3: {} + + prism-react-renderer@2.4.1(react@19.1.0): + dependencies: + '@types/prismjs': 1.26.5 + clsx: 2.1.1 + react: 19.1.0 + + prismjs@1.30.0: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + property-information@6.5.0: {} + + property-information@7.1.0: {} + + prosemirror-changeset@2.3.0: + dependencies: + prosemirror-transform: 1.10.4 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.3 + + prosemirror-commands@1.7.1: + dependencies: + prosemirror-model: 1.25.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.4 + + prosemirror-dropcursor@1.8.2: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.4 + prosemirror-view: 1.39.2 + + prosemirror-gapcursor@1.3.2: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.1 + prosemirror-state: 1.4.3 + prosemirror-view: 1.39.2 + + prosemirror-history@1.4.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.4 + prosemirror-view: 1.39.2 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.5.0: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.4 + + prosemirror-keymap@1.2.3: + dependencies: + prosemirror-state: 1.4.3 + w3c-keyname: 2.2.8 + + prosemirror-markdown@1.13.2: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + prosemirror-model: 1.25.1 + + prosemirror-menu@1.2.5: + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.7.1 + prosemirror-history: 1.4.1 + prosemirror-state: 1.4.3 + + prosemirror-model@1.25.1: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-basic@1.2.4: + dependencies: + prosemirror-model: 1.25.1 + + prosemirror-schema-list@1.5.1: + dependencies: + prosemirror-model: 1.25.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.4 + + prosemirror-state@1.4.3: + dependencies: + prosemirror-model: 1.25.1 + prosemirror-transform: 1.10.4 + prosemirror-view: 1.39.2 + + prosemirror-tables@1.7.1: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.4 + prosemirror-view: 1.39.2 + + prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.39.2): + dependencies: + '@remirror/core-constants': 3.0.0 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.25.1 + prosemirror-state: 1.4.3 + prosemirror-view: 1.39.2 + + prosemirror-transform@1.10.4: + dependencies: + prosemirror-model: 1.25.1 + + prosemirror-view@1.39.2: + dependencies: + prosemirror-model: 1.25.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.4 + + punycode.js@2.3.1: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + radix-ui@1.4.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-accordion': 1.2.11(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-alert-dialog': 1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-checkbox': 1.3.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collapsible': 1.1.11(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context-menu': 2.2.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dialog': 1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dropdown-menu': 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-form': 0.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-hover-card': 1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menubar': 1.1.15(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-navigation-menu': 1.2.13(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-one-time-password-field': 0.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-password-toggle-field': 0.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popover': 1.1.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-radio-group': 1.3.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-scroll-area': 1.2.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-select': 2.2.5(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slider': 1.3.5(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-switch': 1.2.5(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-tabs': 1.1.12(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toast': 1.2.14(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle-group': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toolbar': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-tooltip': 1.2.7(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + radix3@1.1.2: {} + + range-parser@1.2.1: {} + + react-calendar-heatmap@1.10.0(react@19.1.0): + dependencies: + memoize-one: 5.2.1 + prop-types: 15.8.1 + react: 19.1.0 + + react-confetti@6.4.0(react@19.1.0): + dependencies: + react: 19.1.0 + tween-functions: 1.2.0 + + react-dom@19.1.0(react@19.1.0): + dependencies: + react: 19.1.0 + scheduler: 0.26.0 + + react-dropzone@14.3.8(react@19.1.0): + dependencies: + attr-accept: 2.2.5 + file-selector: 2.1.2 + prop-types: 15.8.1 + react: 19.1.0 + + react-is@16.13.1: {} + + react-markdown@10.1.0(@types/react@19.1.4)(react@19.1.0): + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/react': 19.1.4 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.0 + react: 19.1.0 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + react-refresh@0.17.0: {} + + react-remove-scroll-bar@2.3.8(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + react-style-singleton: 2.2.3(@types/react@19.1.4)(react@19.1.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.4 + + react-remove-scroll@2.7.1(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.1.4)(react@19.1.0) + react-style-singleton: 2.2.3(@types/react@19.1.4)(react@19.1.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.1.4)(react@19.1.0) + use-sidecar: 1.1.3(@types/react@19.1.4)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + + react-resizable-panels@3.0.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + react-style-singleton@2.2.3(@types/react@19.1.4)(react@19.1.0): + dependencies: + get-nonce: 1.0.1 + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.4 + + react-textarea-autosize@8.5.9(@types/react@19.1.4)(react@19.1.0): + dependencies: + '@babel/runtime': 7.27.1 + react: 19.1.0 + use-composed-ref: 1.4.0(@types/react@19.1.4)(react@19.1.0) + use-latest: 1.3.0(@types/react@19.1.4)(react@19.1.0) + transitivePeerDependencies: + - '@types/react' + + react-tooltip@5.28.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@floating-ui/dom': 1.7.0 + classnames: 2.5.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + react@19.1.0: {} + + readdirp@4.1.2: {} + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.0.1: + dependencies: + regex-utilities: 2.3.0 + + rehype-external-links@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.0 + hast-util-is-element: 3.0.0 + is-absolute-url: 4.0.1 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.0.0 + + rehype-katex@7.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/katex': 0.16.7 + hast-util-from-html-isomorphic: 2.0.0 + hast-util-to-text: 4.0.2 + katex: 0.16.22 + unist-util-visit-parents: 6.0.1 + vfile: 6.0.3 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.4 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-math@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-math: 3.0.0 + micromark-extension-math: 3.1.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.0 + unified: 11.0.5 + vfile: 6.0.3 + + remark-smartypants@3.0.2: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.0.0 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + resolve-from@5.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + restructure@3.0.2: {} + + retext-latin@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + + retext-smartypants@6.2.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.0.0 + + retext-stringify@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + '@types/nlcst': 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + + reusify@1.1.0: {} + + roadmap-renderer@1.0.7: {} + + rollup@4.40.2: + dependencies: + '@types/estree': 1.0.7 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.40.2 + '@rollup/rollup-android-arm64': 4.40.2 + '@rollup/rollup-darwin-arm64': 4.40.2 + '@rollup/rollup-darwin-x64': 4.40.2 + '@rollup/rollup-freebsd-arm64': 4.40.2 + '@rollup/rollup-freebsd-x64': 4.40.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.40.2 + '@rollup/rollup-linux-arm-musleabihf': 4.40.2 + '@rollup/rollup-linux-arm64-gnu': 4.40.2 + '@rollup/rollup-linux-arm64-musl': 4.40.2 + '@rollup/rollup-linux-loongarch64-gnu': 4.40.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.40.2 + '@rollup/rollup-linux-riscv64-gnu': 4.40.2 + '@rollup/rollup-linux-riscv64-musl': 4.40.2 + '@rollup/rollup-linux-s390x-gnu': 4.40.2 + '@rollup/rollup-linux-x64-gnu': 4.40.2 + '@rollup/rollup-linux-x64-musl': 4.40.2 + '@rollup/rollup-win32-arm64-msvc': 4.40.2 + '@rollup/rollup-win32-ia32-msvc': 4.40.2 + '@rollup/rollup-win32-x64-msvc': 4.40.2 + fsevents: 2.3.3 + + rope-sequence@1.3.4: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + s.color@0.0.15: {} + + sanitize-html@2.17.0: + dependencies: + deepmerge: 4.3.1 + escape-string-regexp: 4.0.0 + htmlparser2: 8.0.2 + is-plain-object: 5.0.0 + parse-srcset: 1.0.2 + postcss: 8.5.3 + + sass-formatter@0.7.9: + dependencies: + suf-log: 2.5.3 + + satori-html@0.3.2: + dependencies: + ultrahtml: 1.6.0 + + satori@0.13.1: + dependencies: + '@shuding/opentype.js': 1.4.0-beta.0 + css-background-parser: 0.1.0 + css-box-shadow: 1.0.0-3 + css-gradient-parser: 0.0.16 + css-to-react-native: 3.2.0 + emoji-regex-xs: 2.0.1 + escape-html: 1.0.3 + linebreak: 1.1.0 + parse-css-color: 0.2.1 + postcss-value-parser: 4.2.0 + yoga-wasm-web: 0.3.3 + + sax@1.4.1: {} + + scheduler@0.26.0: {} + + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + + secure-json-parse@2.7.0: {} + + semver@6.3.1: {} + + semver@7.7.1: {} + + send@1.2.0: + dependencies: + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + server-destroy@1.0.1: {} + + setprototypeof@1.2.0: {} + + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.0.4 + semver: 7.7.1 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 + optional: true + + sharp@0.34.1: + dependencies: + color: 4.2.3 + detect-libc: 2.0.4 + semver: 7.7.1 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.1 + '@img/sharp-darwin-x64': 0.34.1 + '@img/sharp-libvips-darwin-arm64': 1.1.0 + '@img/sharp-libvips-darwin-x64': 1.1.0 + '@img/sharp-libvips-linux-arm': 1.1.0 + '@img/sharp-libvips-linux-arm64': 1.1.0 + '@img/sharp-libvips-linux-ppc64': 1.1.0 + '@img/sharp-libvips-linux-s390x': 1.1.0 + '@img/sharp-libvips-linux-x64': 1.1.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 + '@img/sharp-libvips-linuxmusl-x64': 1.1.0 + '@img/sharp-linux-arm': 0.34.1 + '@img/sharp-linux-arm64': 0.34.1 + '@img/sharp-linux-s390x': 0.34.1 + '@img/sharp-linux-x64': 0.34.1 + '@img/sharp-linuxmusl-arm64': 0.34.1 + '@img/sharp-linuxmusl-x64': 0.34.1 + '@img/sharp-wasm32': 0.34.1 + '@img/sharp-win32-ia32': 0.34.1 + '@img/sharp-win32-x64': 0.34.1 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shiki@3.4.2: + dependencies: + '@shikijs/core': 3.4.2 + '@shikijs/engine-javascript': 3.4.2 + '@shikijs/engine-oniguruma': 3.4.2 + '@shikijs/langs': 3.4.2 + '@shikijs/themes': 3.4.2 + '@shikijs/types': 3.4.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + signal-exit@4.1.0: {} + + simple-swizzle@0.2.2: + dependencies: + is-arrayish: 0.3.2 + + sisteransi@1.0.5: {} + + sitemap@8.0.0: + dependencies: + '@types/node': 17.0.45 + '@types/sax': 1.2.7 + arg: 5.0.2 + sax: 1.4.1 + + slash@3.0.0: {} + + slugify@1.6.6: {} + + smol-toml@1.3.4: {} + + source-map-js@1.2.1: {} + + source-map@0.8.0-beta.0: + dependencies: + whatwg-url: 7.1.0 + + space-separated-tokens@2.0.2: {} + + sprintf-js@1.0.3: {} + + statuses@2.0.1: {} + + stream-replace-string@2.0.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 + strip-ansi: 7.1.0 + + string.prototype.codepointat@0.2.1: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-bom-string@1.0.0: {} + + strip-outer@1.0.1: + dependencies: + escape-string-regexp: 1.0.5 + + style-to-js@1.1.17: + dependencies: + style-to-object: 1.0.9 + + style-to-object@1.0.9: + dependencies: + inline-style-parser: 0.2.4 + + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + ts-interface-checker: 0.1.13 + + suf-log@2.5.3: + dependencies: + s.color: 0.0.15 + + swr@2.3.5(react@19.1.0): + dependencies: + dequal: 2.0.3 + react: 19.1.0 + use-sync-external-store: 1.5.0(react@19.1.0) + + tailwind-merge@3.3.0: {} + + tailwind-scrollbar@4.0.2(react@19.1.0)(tailwindcss@4.1.7): + dependencies: + prism-react-renderer: 2.4.1(react@19.1.0) + tailwindcss: 4.1.7 + transitivePeerDependencies: + - react + + tailwindcss@4.1.5: {} + + tailwindcss@4.1.7: {} + + tapable@2.2.1: {} + + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.2 + mkdirp: 3.0.1 + yallist: 5.0.0 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + throttleit@2.1.0: {} + + tiny-inflate@1.0.3: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.13: + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + + tippy.js@6.3.7: + dependencies: + '@popperjs/core': 2.11.8 + + tiptap-markdown@0.8.10(@tiptap/core@2.12.0(@tiptap/pm@2.12.0)): + dependencies: + '@tiptap/core': 2.12.0(@tiptap/pm@2.12.0) + '@types/markdown-it': 13.0.9 + markdown-it: 14.1.0 + markdown-it-task-lists: 2.1.1 + prosemirror-markdown: 1.13.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tr46@0.0.3: {} + + tr46@1.0.1: + dependencies: + punycode: 2.3.1 + + tree-kill@1.2.2: {} + + trim-lines@3.0.1: {} + + trim-repeated@1.0.0: + dependencies: + escape-string-regexp: 1.0.5 + + trough@2.2.0: {} + + ts-interface-checker@0.1.13: {} + + tsconfck@3.1.5(typescript@5.8.3): + optionalDependencies: + typescript: 5.8.3 + + tslib@2.8.1: {} + + tsup@8.4.0(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(typescript@5.8.3): + dependencies: + bundle-require: 5.1.0(esbuild@0.25.4) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.0 + esbuild: 0.25.4 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4) + resolve-from: 5.0.0 + rollup: 4.40.2 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.13 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.3 + typescript: 5.8.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + + tsx@4.19.4: + dependencies: + esbuild: 0.25.4 + get-tsconfig: 4.10.0 + optionalDependencies: + fsevents: 2.3.3 + + turndown@7.2.0: + dependencies: + '@mixmark-io/domino': 2.2.0 + + tween-functions@1.2.0: {} + + type-fest@4.41.0: {} + + typescript@5.8.3: {} + + uc.micro@2.1.0: {} + + ufo@1.6.1: {} + + ultrahtml@1.6.0: {} + + uncrypto@0.1.3: {} + + undici-types@5.26.5: {} + + undici-types@6.21.0: {} + + unicode-properties@1.4.1: + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + + unicode-trie@2.0.0: + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unifont@0.5.0: + dependencies: + css-tree: 3.1.0 + ohash: 2.0.11 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-is@6.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-modify-children@4.0.0: + dependencies: + '@types/unist': 3.0.3 + array-iterate: 2.0.1 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.0.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-children@3.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.1: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + universalify@2.0.1: {} + + unstorage@1.16.0: + dependencies: + anymatch: 3.1.3 + chokidar: 4.0.3 + destr: 2.0.5 + h3: 1.15.3 + lru-cache: 10.4.3 + node-fetch-native: 1.6.6 + ofetch: 1.4.1 + ufo: 1.6.1 + + update-browserslist-db@1.1.3(browserslist@4.24.5): + dependencies: + browserslist: 4.24.5 + escalade: 3.2.0 + picocolors: 1.1.1 + + use-callback-ref@1.3.3(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.4 + + use-composed-ref@1.4.0(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + use-isomorphic-layout-effect@1.2.0(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + use-latest@1.3.0(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + use-isomorphic-layout-effect: 1.2.0(@types/react@19.1.4)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + + use-sidecar@1.1.3(@types/react@19.1.4)(react@19.1.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.4 + + use-sync-external-store@1.5.0(react@19.1.0): + dependencies: + react: 19.1.0 + + util-deprecate@1.0.2: {} + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.2 + + vite@6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4): + dependencies: + esbuild: 0.25.4 + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.3 + rollup: 4.40.2 + tinyglobby: 0.2.13 + optionalDependencies: + '@types/node': 22.15.17 + fsevents: 2.3.3 + jiti: 2.4.2 + lightningcss: 1.30.1 + tsx: 4.19.4 + + vitefu@1.0.6(vite@6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)): + optionalDependencies: + vite: 6.3.5(@types/node@22.15.17)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4) + + w3c-keyname@2.2.8: {} + + web-namespaces@2.0.1: {} + + web-streams-polyfill@4.0.0-beta.3: {} + + webidl-conversions@3.0.1: {} + + webidl-conversions@4.0.2: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + whatwg-url@7.1.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + + which-pm-runs@1.1.0: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + widest-line@5.0.0: + dependencies: + string-width: 7.2.0 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + xxhash-wasm@1.1.0: {} + + yallist@3.1.1: {} + + yallist@5.0.0: {} + + yargs-parser@21.1.1: {} + + yocto-queue@1.2.1: {} + + yocto-spinner@0.2.2: + dependencies: + yoctocolors: 2.1.1 + + yoctocolors@2.1.1: {} + + yoga-wasm-web@0.3.3: {} + + zod-to-json-schema@3.24.5(zod@3.24.4): + dependencies: + zod: 3.24.4 + + zod-to-json-schema@3.24.5(zod@4.0.17): + dependencies: + zod: 4.0.17 + + zod-to-ts@1.2.0(typescript@5.8.3)(zod@3.24.4): + dependencies: + typescript: 5.8.3 + zod: 3.24.4 + + zod@3.24.4: {} + + zod@4.0.17: {} + + zustand@4.5.6(@types/react@19.1.4)(react@19.1.0): + dependencies: + use-sync-external-store: 1.5.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + react: 19.1.0 + + zustand@5.0.4(@types/react@19.1.4)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)): + optionalDependencies: + '@types/react': 19.1.4 + react: 19.1.0 + use-sync-external-store: 1.5.0(react@19.1.0) + + zwitch@2.0.4: {} \ No newline at end of file diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 000000000000..924b55f42e98 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* diff --git a/project-files/backend-map.json b/project-files/backend-map.json deleted file mode 100644 index f7219573ae6d..000000000000 --- a/project-files/backend-map.json +++ /dev/null @@ -1 +0,0 @@ -{"mockup":{"controls":{"control":[{"ID":"0","measuredH":"40","measuredW":"146","properties":{"bold":"true","size":"32","text":"Back-end"},"typeID":"Label","x":"566","y":"149","zOrder":"0"},{"ID":"1","h":"105","measuredH":"104","measuredW":"12","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":2,"y":0},"p1":{"x":0.46601941747572817,"y":0.10679611650485436},"p2":{"x":0,"y":104},"rightArrow":"false","shape":"bezier","stroke":"dotted"},"typeID":"Arrow","w":"13","x":"645","y":"41","zOrder":"1"},{"ID":"2","h":"128","measuredH":"127","measuredW":"24","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":3,"y":0},"p1":{"x":0.430241233523999,"y":-0.06441183785128078},"p2":{"x":24,"y":127},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"25","x":"626","y":"205","zOrder":"2"},{"ID":"3","h":"119","measuredH":"118","measuredW":"21","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":15,"y":0},"p1":{"x":0.4700685560817019,"y":0.10212735882394516},"p2":{"x":0,"y":118},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"22","x":"636","y":"333","zOrder":"3"},{"ID":"4","measuredH":"32","measuredW":"74","properties":{"align":"center","color":"16770457","size":"18","text":"Node.js"},"typeID":"TextInput","w":"139","x":"396","y":"509","zOrder":"4"},{"ID":"5","h":"31","measuredH":"30","measuredW":"87","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":87,"y":2},"p1":{"x":0.5740384615384616,"y":-0.1451923076923077},"p2":{"x":0,"y":30},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"88","x":"306","y":"526","zOrder":"5"},{"ID":"6","measuredH":"26","measuredW":"92","properties":{"bold":"true","size":"18","text":"Framework"},"typeID":"Label","x":"254","y":"557","zOrder":"6"},{"ID":"7","h":"36","measuredH":"35","measuredW":"2","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"length":2,"x":2,"y":0},"p1":{"length":0.34758643030275543,"x":0.34285714285714286,"y":-0.05714285714285715},"p2":{"length":35.05709628591621,"x":2,"y":35},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"3","x":"292","y":"583","zOrder":"7"},{"ID":"8","measuredH":"32","measuredW":"81","properties":{"align":"center","color":"16776960","size":"18","text":"Express"},"typeID":"TextInput","w":"139","x":"232","y":"620","zOrder":"8"},{"ID":"9","measuredH":"32","measuredW":"47","properties":{"align":"center","color":"15658734","size":"18","text":"hapi"},"typeID":"TextInput","w":"139","x":"233","y":"655","zOrder":"9"},{"ID":"10","measuredH":"32","measuredW":"46","properties":{"align":"center","color":"15658734","size":"18","text":"Koa"},"typeID":"TextInput","w":"139","x":"234","y":"690","zOrder":"10"},{"ID":"11","measuredH":"32","measuredW":"71","properties":{"align":"center","color":"15658734","size":"18","text":"Sails.js"},"typeID":"TextInput","w":"139","x":"235","y":"726","zOrder":"11"},{"ID":"12","h":"38","measuredH":"37","measuredW":"228","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":228,"y":14},"p1":{"x":0.5200997848151886,"y":-0.10509778531030411},"p2":{"x":0,"y":37},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"229","x":"167","y":"506","zOrder":"12"},{"ID":"13","measuredH":"26","measuredW":"151","properties":{"bold":"true","size":"18","text":"Package Manager"},"typeID":"Label","x":"81","y":"548","zOrder":"13"},{"ID":"14","h":"36","measuredH":"35","measuredW":"12","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":12,"y":0},"p1":{"x":0.4678777137793531,"y":-0.06956136464333186},"p2":{"x":0,"y":35},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"13","x":"133","y":"579","zOrder":"14"},{"ID":"15","measuredH":"32","measuredW":"49","properties":{"align":"center","color":"16776960","size":"18","text":"npm"},"typeID":"TextInput","w":"139","x":"72","y":"621","zOrder":"15"},{"ID":"16","measuredH":"32","measuredW":"51","properties":{"align":"center","color":"16776960","size":"18","text":"Yarn"},"typeID":"TextInput","w":"139","x":"73","y":"656","zOrder":"16"},{"ID":"17","h":"42","measuredH":"41","measuredW":"87","properties":{"color":"2848996","curvature":"0","direction":"bottom","leftArrow":"false","p0":{"x":87,"y":0},"p1":{"x":0.42179546506247106,"y":-0.003933364183248496},"p2":{"x":0,"y":41},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"88","x":"537","y":"466","zOrder":"17"},{"ID":"18","measuredH":"26","measuredW":"63","properties":{"bold":"true","size":"18","text":"Testing"},"typeID":"Label","x":"458","y":"565","zOrder":"18"},{"ID":"19","h":"27","measuredH":"26","measuredW":"4","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"length":4,"x":4,"y":0},"p1":{"length":0.4999999999999996,"x":0.4977375565610856,"y":0.04751131221719452},"p2":{"length":26,"x":0,"y":26},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"5","x":"486","y":"592","zOrder":"19"},{"ID":"20","measuredH":"32","measuredW":"50","properties":{"align":"center","color":"16770457","size":"18","text":"Jest"},"typeID":"TextInput","w":"162","x":"407","y":"621","zOrder":"20"},{"ID":"21","measuredH":"32","measuredW":"67","properties":{"align":"center","color":"16776960","size":"18","text":"Mocha"},"typeID":"TextInput","w":"162","x":"408","y":"656","zOrder":"21"},{"ID":"22","measuredH":"32","measuredW":"82","properties":{"align":"center","color":"15658734","size":"18","text":"Jasmine"},"typeID":"TextInput","w":"162","x":"408","y":"691","zOrder":"22"},{"ID":"23","h":"20","measuredH":"19","measuredW":"3","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"length":19.1049731745428,"x":2,"y":19},"p1":{"length":0.5592341933075103,"x":0.5513330320831451,"y":0.09367374604609124},"p2":{"length":3,"x":3,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"4","x":"484","y":"545","zOrder":"23"},{"ID":"24","measuredH":"32","measuredW":"51","properties":{"align":"center","color":"16770457","size":"18","text":"Chai"},"typeID":"TextInput","w":"162","x":"408","y":"726","zOrder":"24"},{"ID":"25","h":"72","measuredH":"71","measuredW":"100","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.4557377049180328,"y":0.11311475409836064},"p2":{"x":100,"y":71},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"101","x":"641","y":"456","zOrder":"25"},{"ID":"26","measuredH":"32","measuredW":"64","properties":{"align":"center","color":"16770457","size":"18","text":"PHP 7"},"typeID":"TextInput","w":"139","x":"739","y":"530","zOrder":"26"},{"ID":"27","h":"29","measuredH":"28","measuredW":"62","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"length":28,"x":0,"y":28},"p1":{"length":0.582362350666069,"x":0.5718861209964412,"y":0.10996441281138793},"p2":{"length":62.00806399170998,"x":62,"y":1},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"63","x":"849","y":"500","zOrder":"27"},{"ID":"28","measuredH":"26","measuredW":"151","properties":{"bold":"true","size":"18","text":"Package Manager"},"typeID":"Label","x":"918","y":"487","zOrder":"28"},{"ID":"29","h":"2","measuredH":"1","measuredW":"39","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"length":1,"x":0,"y":1},"p1":{"length":0.4622501635210244,"x":0.4615384615384616,"y":0.025641025641025644},"p2":{"length":39.01281840626232,"x":39,"y":1},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"40","x":"1078","y":"499","zOrder":"29"},{"ID":"30","measuredH":"32","measuredW":"99","properties":{"align":"center","color":"16776960","size":"18","text":"Composer"},"typeID":"TextInput","w":"139","x":"1123","y":"484","zOrder":"30"},{"ID":"31","h":"27","measuredH":"26","measuredW":"49","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.5574496644295301,"y":0.0877852348993286},"p2":{"x":49,"y":26},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"50","x":"878","y":"559","zOrder":"31"},{"ID":"32","measuredH":"26","measuredW":"92","properties":{"bold":"true","size":"18","text":"Framework"},"typeID":"Label","x":"904","y":"586","zOrder":"32"},{"ID":"33","h":"34","measuredH":"33","measuredW":"19","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.6391778508289956,"x":0.6388140161725069,"y":0.021563342318059286},"p2":{"length":38.07886552931954,"x":19,"y":33},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"20","x":"940","y":"612","zOrder":"33"},{"ID":"34","measuredH":"32","measuredW":"73","properties":{"align":"center","color":"16776960","size":"18","text":"Laravel"},"typeID":"TextInput","w":"139","x":"927","y":"648","zOrder":"34"},{"ID":"35","measuredH":"32","measuredW":"85","properties":{"align":"center","color":"16770457","size":"18","text":"Symfony"},"typeID":"TextInput","w":"139","x":"928","y":"683","zOrder":"35"},{"ID":"36","measuredH":"26","measuredW":"63","properties":{"bold":"true","size":"18","text":"Testing"},"typeID":"Label","x":"743","y":"590","zOrder":"36"},{"ID":"37","h":"27","measuredH":"26","measuredW":"13","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.6878740667500972,"x":0.6878048780487805,"y":0.009756097560975547},"p2":{"length":29.068883707497267,"x":13,"y":26},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"14","x":"787","y":"616","zOrder":"37"},{"ID":"38","measuredH":"32","measuredW":"82","properties":{"align":"center","color":"16776960","size":"18","text":"PHPUnit"},"typeID":"TextInput","w":"162","x":"752","y":"649","zOrder":"38"},{"ID":"39","measuredH":"32","measuredW":"84","properties":{"align":"center","color":"16770457","size":"18","text":"phpspec"},"typeID":"TextInput","w":"162","x":"753","y":"684","zOrder":"39"},{"ID":"40","measuredH":"32","measuredW":"118","properties":{"align":"center","color":"15658734","size":"18","text":"Codeception"},"typeID":"TextInput","w":"162","x":"753","y":"719","zOrder":"40"},{"ID":"41","h":"25","measuredH":"24","measuredW":"17","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"length":29.410882339705484,"x":17,"y":24},"p1":{"length":0.5252257314388903,"x":0.5059505645407385,"y":-0.14098260604211188},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"18","x":"756","y":"563","zOrder":"41"},{"ID":"42","h":"33","measuredH":"32","measuredW":"0","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.5178212058827155,"x":0.5173501577287066,"y":0.02208201892744478},"p2":{"length":32,"x":0,"y":32},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"1","x":"822","y":"754","zOrder":"42"},{"ID":"43","measuredH":"32","measuredW":"82","properties":{"align":"center","color":"16776960","size":"18","text":"Mockery"},"typeID":"TextInput","w":"162","x":"752","y":"788","zOrder":"43"},{"ID":"44","measuredH":"32","measuredW":"85","properties":{"align":"center","color":"15658734","size":"18","text":"should.js"},"typeID":"TextInput","w":"162","x":"408","y":"760","zOrder":"44"},{"ID":"45","h":"433","measuredH":"432","measuredW":"155","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.5136269339042673,"y":-0.052342997118429234},"p2":{"x":155,"y":432},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"156","x":"635","y":"473","zOrder":"45"},{"ID":"46","measuredH":"32","measuredW":"70","properties":{"align":"center","color":"16770457","size":"18","text":"Python"},"typeID":"TextInput","w":"130","x":"747","y":"397","zOrder":"46"},{"ID":"47","measuredH":"32","measuredW":"97","properties":{"align":"center","color":"16770457","size":"18","text":"C# (.NET)"},"typeID":"TextInput","w":"246","x":"789","y":"906","zOrder":"47"},{"ID":"48","measuredH":"32","measuredW":"221","properties":{"align":"center","color":"16770457","size":"18","text":"Java (Grails, Spring, Play)"},"typeID":"TextInput","w":"246","x":"789","y":"944","zOrder":"48"},{"ID":"49","measuredH":"32","measuredW":"37","properties":{"align":"center","color":"16770457","size":"18","text":"Go"},"typeID":"TextInput","w":"246","x":"789","y":"981","zOrder":"49"},{"ID":"50","measuredH":"32","measuredW":"56","properties":{"align":"center","color":"16770457","size":"18","text":"Ruby"},"typeID":"TextInput","w":"139","x":"396","y":"397","zOrder":"50"},{"ID":"51","h":"396","measuredH":"395","measuredW":"59","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":14,"y":0},"p1":{"x":0.5603409503308074,"y":-0.08790823622100975},"p2":{"x":59,"y":395},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"60","x":"616","y":"461","zOrder":"51"},{"ID":"52","h":"79","measuredH":"78","measuredW":"140","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":140,"y":0},"p1":{"x":0.4648072163064605,"y":-0.04307523630745718},"p2":{"x":0,"y":78},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"141","x":"539","y":"857","zOrder":"52"},{"ID":"53","measuredH":"32","measuredW":"127","properties":{"align":"center","color":"16776960","size":"18","text":"RESTful APIs"},"typeID":"TextInput","w":"231","x":"306","y":"923","zOrder":"53"},{"ID":"54","h":"112","measuredH":"111","measuredW":"124","properties":{"color":"2848996","curvature":"0","direction":"bottom","leftArrow":"false","p0":{"x":124,"y":0},"p1":{"x":0.45325750773221585,"y":-0.004290132694801955},"p2":{"x":0,"y":111},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"125","x":"542","y":"864","zOrder":"54"},{"ID":"55","measuredH":"32","measuredW":"154","properties":{"align":"center","color":"16776960","size":"18","text":"Read about MVC"},"typeID":"TextInput","w":"231","x":"306","y":"961","zOrder":"55"},{"ID":"56","h":"155","measuredH":"154","measuredW":"135","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":135,"y":0},"p1":{"x":0.4400283386468296,"y":0.01608218207580588},"p2":{"x":0,"y":154},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"136","x":"540","y":"861","zOrder":"56"},{"ID":"57","measuredH":"32","measuredW":"130","properties":{"align":"center","color":"16776960","size":"18","text":"Authentication"},"typeID":"TextInput","w":"231","x":"306","y":"997","zOrder":"57"},{"ID":"58","h":"18","measuredH":"17","measuredW":"50","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":50,"y":15},"p1":{"x":0.4532110091743119,"y":0.1559633027522936},"p2":{"x":0,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"51","x":"256","y":"992","zOrder":"58"},{"ID":"59","measuredH":"32","measuredW":"94","properties":{"align":"center","color":"16776960","size":"18","text":"OAuth 2.0"},"typeID":"TextInput","w":"117","x":"117","y":"1011","zOrder":"59"},{"ID":"60","h":"15","measuredH":"14","measuredW":"70","properties":{"color":"2848996","curvature":"0","direction":"bottom","leftArrow":"false","p0":{"x":70,"y":0},"p1":{"x":0.5879828326180258,"y":0.002861230329041488},"p2":{"x":0,"y":14},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"71","x":"236","y":"1014","zOrder":"60"},{"ID":"61","measuredH":"32","measuredW":"218","properties":{"align":"center","color":"16776960","size":"18","text":"JSON Web Token (JWT)"},"typeID":"TextInput","w":"249","x":"39","y":"957","zOrder":"61"},{"ID":"62","measuredH":"32","measuredW":"212","properties":{"align":"center","color":"16776960","size":"18","text":"SOLID, YAGNI, KISS etc"},"typeID":"TextInput","w":"231","x":"306","y":"1033","zOrder":"62"},{"ID":"63","h":"189","measuredH":"188","measuredW":"143","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":143,"y":0},"p1":{"x":0.484958364461289,"y":0.03977697199395055},"p2":{"x":0,"y":188},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"144","x":"542","y":"862","zOrder":"63"},{"ID":"64","h":"359","measuredH":"358","measuredW":"74","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":21,"y":0},"p1":{"x":0.4478752770110027,"y":0.17431670619338285},"p2":{"x":0,"y":358},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"75","x":"659","y":"860","zOrder":"64"},{"ID":"65","measuredH":"32","measuredW":"78","properties":{"align":"center","color":"16776960","size":"18","text":"Storage"},"typeID":"TextInput","w":"153","x":"799","y":"1142","zOrder":"65"},{"ID":"66","h":"34","measuredH":"33","measuredW":"33","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":33,"y":33},"p1":{"x":0.4795564795564795,"y":-0.08246708246708248},"p2":{"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"34","x":"887","y":"1176","zOrder":"66"},{"ID":"67","measuredH":"26","measuredW":"182","properties":{"bold":"true","size":"18","text":"Relational Databases"},"typeID":"Label","x":"854","y":"1210","zOrder":"67"},{"ID":"68","h":"38","measuredH":"37","measuredW":"7","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.4243243243243244,"y":0.05405405405405411},"p2":{"x":7,"y":37},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"8","x":"934","y":"1240","zOrder":"68"},{"ID":"69","measuredH":"32","measuredW":"76","properties":{"align":"center","color":"16776960","size":"18","text":"MySQL"},"typeID":"TextInput","w":"246","x":"864","y":"1391","zOrder":"69"},{"ID":"70","measuredH":"32","measuredW":"83","properties":{"align":"center","color":"16776960","size":"18","text":"MariaDB"},"typeID":"TextInput","w":"246","x":"864","y":"1353","zOrder":"70"},{"ID":"71","measuredH":"32","measuredW":"114","properties":{"align":"center","color":"16776960","size":"18","text":"PostgreSQL"},"typeID":"TextInput","w":"246","x":"864","y":"1316","zOrder":"71"},{"ID":"72","measuredH":"32","measuredW":"67","properties":{"align":"center","color":"16770457","size":"18","text":"Oracle"},"typeID":"TextInput","w":"246","x":"863","y":"1279","zOrder":"72"},{"ID":"73","h":"301","measuredH":"300","measuredW":"64","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":64,"y":300},"p1":{"x":0.46014238003164,"y":0.15758481279662506},"p2":{"x":32,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"65","x":"796","y":"1173","zOrder":"73"},{"ID":"74","measuredH":"26","measuredW":"158","properties":{"bold":"true","size":"18","text":"NoSQL Databases"},"typeID":"Label","x":"825","y":"1477","zOrder":"74"},{"ID":"75","measuredH":"32","measuredW":"185","properties":{"align":"center","color":"16776960","size":"18","text":"Regular Expressions"},"typeID":"TextInput","w":"231","x":"306","y":"1069","zOrder":"75"},{"ID":"76","h":"216","measuredH":"215","measuredW":"143","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":143,"y":0},"p1":{"x":0.4401741954956379,"y":0.060565991635166794},"p2":{"x":0,"y":215},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"144","x":"542","y":"869","zOrder":"76"},{"ID":"77","h":"36","measuredH":"35","measuredW":"10","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.42432432432432426,"y":0.05405405405405404},"p2":{"x":10,"y":35},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"11","x":"877","y":"1505","zOrder":"77"},{"ID":"78","measuredH":"32","measuredW":"104","properties":{"align":"center","color":"15658734","size":"18","text":"Cassandra"},"typeID":"TextInput","w":"246","x":"831","y":"1616","zOrder":"78"},{"ID":"79","measuredH":"32","measuredW":"92","properties":{"align":"center","color":"16776960","size":"18","text":"MongoDB"},"typeID":"TextInput","w":"246","x":"831","y":"1578","zOrder":"79"},{"ID":"80","measuredH":"32","measuredW":"61","properties":{"align":"center","color":"16776960","size":"18","text":"Redis"},"typeID":"TextInput","w":"246","x":"830","y":"1541","zOrder":"80"},{"ID":"81","measuredH":"26","measuredW":"195","properties":{"bold":"true","size":"18","text":"Up your Game further!"},"typeID":"Label","x":"593","y":"1434","zOrder":"81"},{"ID":"82","h":"141","measuredH":"140","measuredW":"18","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":6,"y":0},"p1":{"x":0.591307066916823,"y":0.116635397123202},"p2":{"x":0,"y":140},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"19","x":"677","y":"1468","zOrder":"82"},{"ID":"83","h":"33","measuredH":"32","measuredW":"116","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"length":120.3328716519306,"x":116,"y":32},"p1":{"length":0.4993624094871551,"x":0.4988634015292415,"y":-0.022318660880347164},"p2":{"length":0,"x":0,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"117","x":"557","y":"1577","zOrder":"83"},{"ID":"84","measuredH":"32","measuredW":"188","properties":{"align":"center","color":"16776960","size":"18","text":"GOF Design Patterns"},"typeID":"TextInput","w":"316","x":"234","y":"1559","zOrder":"84"},{"ID":"85","measuredH":"32","measuredW":"190","properties":{"align":"center","color":"16776960","size":"18","text":"Architectural Patterns"},"typeID":"TextInput","w":"316","x":"234","y":"1596","zOrder":"85"},{"ID":"86","h":"7","measuredH":"6","measuredW":"115","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"length":115.15641536623131,"x":115,"y":6},"p1":{"length":0.4993624094871552,"x":0.4988634015292416,"y":-0.02231866088034718},"p2":{"length":1,"x":0,"y":1},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"116","x":"559","y":"1610","zOrder":"86"},{"ID":"87","measuredH":"32","measuredW":"149","properties":{"align":"center","color":"16776960","size":"18","text":"Give DDD a shot"},"typeID":"TextInput","w":"316","x":"234","y":"1632","zOrder":"87"},{"ID":"88","h":"24","measuredH":"23","measuredW":"119","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"length":119,"x":119,"y":0},"p1":{"length":0.4993624094871551,"x":0.4988634015292415,"y":-0.022318660880347178},"p2":{"length":23,"x":0,"y":23},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"120","x":"559","y":"1625","zOrder":"88"},{"ID":"89","measuredH":"32","measuredW":"294","properties":{"align":"center","color":"16776960","size":"18","text":"Learn different testing techniques"},"typeID":"TextInput","w":"316","x":"234","y":"1669","zOrder":"89"},{"ID":"90","h":"62","measuredH":"61","measuredW":"121","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"length":121,"x":121,"y":0},"p1":{"length":0.5087625513847925,"x":0.5029016657710907,"y":0.07700161203653946},"p2":{"length":61,"x":0,"y":61},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"122","x":"558","y":"1625","zOrder":"90"},{"ID":"91","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"flag-checkered","size":"large"}},"typeID":"Icon","x":"766","y":"1817","zOrder":"91"},{"ID":"93","h":"208","measuredH":"207","measuredW":"84","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":1,"y":0},"p1":{"x":0.5282078957200382,"y":-0.11864336419112459},"p2":{"x":74,"y":207},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"75","x":"679","y":"1609","zOrder":"92"},{"ID":"94","measuredH":"32","measuredW":"141","properties":{"align":"center","color":"16776960","size":"18","text":"Search Engines"},"typeID":"TextInput","w":"316","x":"234","y":"1522","zOrder":"93"},{"ID":"95","h":"65","measuredH":"64","measuredW":"117","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":117,"y":64},"p1":{"x":0.5428732077593478,"y":-0.07056508293505763},"p2":{"x":0,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"118","x":"561","y":"1539","zOrder":"94"},{"ID":"96","h":"141","measuredH":"140","measuredW":"61","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":140},"p1":{"x":0.5428732077593478,"y":-0.0705650829350576},"p2":{"x":61,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"62","x":"375","y":"1383","zOrder":"95"},{"ID":"97","measuredH":"32","measuredW":"127","properties":{"align":"center","color":"16776960","size":"18","text":"ElasticSearch"},"typeID":"TextInput","w":"182","x":"361","y":"1343","zOrder":"96"},{"ID":"98","h":"146","measuredH":"145","measuredW":"79","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":79,"y":145},"p1":{"x":0.5378461538461539,"y":0.11876923076923078},"p2":{"x":1,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"80","x":"261","y":"1376","zOrder":"97"},{"ID":"99","measuredH":"32","measuredW":"47","properties":{"align":"center","color":"15658734","size":"18","text":"Solr"},"typeID":"TextInput","w":"80","x":"224","y":"1342","zOrder":"98"},{"ID":"100","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"655","y":"1591","zOrder":"99"},{"ID":"101","h":"53","measuredH":"52","measuredW":"131","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":44},"p1":{"x":0.4846834581347856,"y":-0.1933287950987066},"p2":{"x":131,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"132","x":"667","y":"1174","zOrder":"100"},{"ID":"102","h":"218","measuredH":"217","measuredW":"46","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":37,"y":0},"p1":{"x":0.4439686241255035,"y":-0.18431206275174897},"p2":{"x":46,"y":217},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"47","x":"621","y":"1216","zOrder":"101"},{"ID":"103","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"637","y":"1190","zOrder":"102"},{"ID":"104","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"655","y":"838","zOrder":"103"},{"ID":"105","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"605","y":"437","zOrder":"104"},{"ID":"106","measuredH":"26","measuredW":"63","properties":{"bold":"true","size":"18","text":"Testing"},"typeID":"Label","x":"253","y":"326","zOrder":"105"},{"ID":"107","h":"34","measuredH":"33","measuredW":"3","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"false","p0":{"x":3,"y":33},"p1":{"x":0.6878048780487805,"y":0.0097560975609756},"p2":{"x":1,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"4","x":"451","y":"365","zOrder":"106"},{"ID":"108","measuredH":"32","measuredW":"69","properties":{"align":"center","color":"16776960","size":"18","text":"RSpec"},"typeID":"TextInput","w":"130","x":"238","y":"261","zOrder":"107"},{"ID":"109","measuredH":"26","measuredW":"151","properties":{"bold":"true","size":"18","text":"Package Manager"},"typeID":"Label","x":"386","y":"333","zOrder":"108"},{"ID":"110","h":"38","measuredH":"37","measuredW":"2","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"false","p0":{"x":2,"y":37},"p1":{"x":0.6878048780487805,"y":0.009756097560975618},"p2":{"x":1,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"3","x":"448","y":"300","zOrder":"109"},{"ID":"111","measuredH":"32","measuredW":"103","properties":{"align":"center","color":"16776960","size":"18","text":"RubyGems"},"typeID":"TextInput","w":"130","x":"396","y":"261","zOrder":"110"},{"ID":"112","measuredH":"32","measuredW":"72","properties":{"align":"center","color":"15658734","size":"18","text":"Sinatra"},"typeID":"TextInput","w":"142","x":"81","y":"225","zOrder":"111"},{"ID":"113","measuredH":"32","measuredW":"126","properties":{"align":"center","color":"16776960","size":"18","text":"Ruby on Rails"},"typeID":"TextInput","w":"142","x":"81","y":"261","zOrder":"112"},{"ID":"114","h":"92","measuredH":"91","measuredW":"240","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.5738202807452291,"y":0.08565902600444236},"p2":{"x":240,"y":91},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"241","x":"882","y":"552","zOrder":"113"},{"ID":"115","measuredH":"32","measuredW":"60","properties":{"align":"center","color":"16776960","size":"18","text":"PSRs"},"typeID":"TextInput","w":"139","x":"1074","y":"648","zOrder":"114"},{"ID":"116","measuredH":"32","measuredW":"78","properties":{"align":"center","color":"16770457","size":"18","text":"MSSQL"},"typeID":"TextInput","w":"246","x":"864","y":"1427","zOrder":"115"},{"ID":"117","measuredH":"32","measuredW":"113","properties":{"align":"center","color":"16776960","size":"18","text":"Memcached"},"typeID":"TextInput","w":"246","x":"980","y":"1112","zOrder":"116"},{"ID":"118","h":"30","measuredH":"29","measuredW":"7","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"length":7,"x":7,"y":0},"p1":{"length":0.4865955577019141,"x":0.4795564795564795,"y":-0.08246708246708247},"p2":{"length":29.017236257093817,"x":1,"y":29},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"8","x":"864","y":"1113","zOrder":"117"},{"ID":"119","h":"46","measuredH":"45","measuredW":"137","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":137,"y":1},"p1":{"x":0.4663459178162894,"y":-0.0777652314792086},"p2":{"x":0,"y":45},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"138","x":"539","y":"855","zOrder":"118"},{"ID":"120","measuredH":"32","measuredW":"112","properties":{"align":"center","color":"16776960","size":"18","text":"Web Server"},"typeID":"TextInput","w":"231","x":"307","y":"885","zOrder":"119"},{"ID":"121","h":"33","measuredH":"32","measuredW":"69","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":69,"y":32},"p1":{"x":0.5192660550458715,"y":-0.06422018348623854},"p2":{"x":0,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"70","x":"238","y":"867","zOrder":"120"},{"ID":"122","measuredH":"32","measuredW":"60","properties":{"align":"center","color":"16776960","size":"18","text":"Nginx"},"typeID":"TextInput","w":"117","x":"118","y":"888","zOrder":"121"},{"ID":"123","h":"4","measuredH":"3","measuredW":"70","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":70,"y":3},"p1":{"x":0.6145684554172618,"y":-0.01979187920832483},"p2":{"x":0,"y":2},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"71","x":"237","y":"903","zOrder":"122"},{"ID":"124","measuredH":"32","measuredW":"76","properties":{"align":"center","color":"15658734","size":"18","text":"Apache"},"typeID":"TextInput","w":"117","x":"117","y":"849","zOrder":"123"},{"ID":"125","h":"40","measuredH":"39","measuredW":"83","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":83,"y":39},"p1":{"x":0.500780031201248,"y":-0.12012480499219969},"p2":{"x":0,"y":1},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"84","x":"539","y":"413","zOrder":"124"},{"ID":"126","measuredH":"26","measuredW":"92","properties":{"bold":"true","size":"18","text":"Framework"},"typeID":"Label","x":"147","y":"333","zOrder":"125"},{"ID":"127","h":"56","measuredH":"55","measuredW":"206","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":206,"y":55},"p1":{"x":0.6664393656100833,"y":0.08569983062405138},"p2":{"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"207","x":"189","y":"360","zOrder":"126"},{"ID":"128","h":"39","measuredH":"38","measuredW":"23","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":23,"y":38},"p1":{"x":0.3862138874809934,"y":0.02939685757729346},"p2":{"x":0,"y":0},"rightArrow":"true","shape":"bezier","text":""},"typeID":"Arrow","w":"24","x":"155","y":"299","zOrder":"127"},{"ID":"129","h":"51","measuredH":"50","measuredW":"113","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":113,"y":50},"p1":{"x":0.6909198212629626,"y":0.12950004215496166},"p2":{"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"114","x":"282","y":"354","zOrder":"128"},{"ID":"130","h":"33","measuredH":"32","measuredW":"3","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"length":32.0624390837628,"x":2,"y":32},"p1":{"length":0.34758643030275543,"x":0.34285714285714286,"y":-0.057142857142857155},"p2":{"length":0,"x":0,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"4","x":"279","y":"299","zOrder":"129"},{"ID":"131","measuredH":"26","measuredW":"69","properties":{"bold":"true","size":"18","text":"Caching"},"typeID":"Label","x":"854","y":"1085","zOrder":"130"},{"ID":"132","h":"62","measuredH":"61","measuredW":"168","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"x":168,"y":61},"p1":{"x":0.5550848978712711,"y":-0.2914168790609183},"p2":{"x":0,"y":41},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"169","x":"889","y":"1040","zOrder":"131"},{"ID":"133","measuredH":"32","measuredW":"61","properties":{"align":"center","color":"16776960","size":"18","text":"Redis"},"typeID":"TextInput","w":"246","x":"980","y":"1147","zOrder":"132"},{"ID":"138","measuredH":"32","measuredW":"99","properties":{"align":"center","color":"15658734","size":"18","text":"RethinkDB"},"typeID":"TextInput","w":"246","x":"832","y":"1652","zOrder":"133"},{"ID":"139","measuredH":"32","measuredW":"83","properties":{"align":"center","color":"16776960","size":"18","text":"Security"},"typeID":"TextInput","w":"231","x":"306","y":"1105","zOrder":"134"},{"ID":"140","h":"245","measuredH":"244","measuredW":"144","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":144,"y":0},"p1":{"x":0.4401741954956379,"y":0.060565991635166794},"p2":{"x":0,"y":244},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"145","x":"544","y":"876","zOrder":"135"},{"ID":"141","h":"32","measuredH":"31","measuredW":"2","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"length":2,"x":2,"y":0},"p1":{"length":0.4622501635210244,"x":0.4615384615384616,"y":0.025641025641025644},"p2":{"length":31,"x":0,"y":31},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"3","x":"997","y":"725","zOrder":"136"},{"ID":"142","measuredH":"32","measuredW":"49","properties":{"align":"center","color":"15658734","size":"18","text":"Slim"},"typeID":"TextInput","w":"139","x":"932","y":"764","zOrder":"137"},{"ID":"143","measuredH":"32","measuredW":"70","properties":{"align":"center","color":"16770457","size":"18","text":"Lumen"},"typeID":"TextInput","w":"139","x":"933","y":"799","zOrder":"138"},{"ID":"144","h":"73","measuredH":"72","measuredW":"22","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":22,"y":72},"p1":{"x":0.5378461538461539,"y":0.11876923076923072},"p2":{"x":2,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"23","x":"339","y":"1447","zOrder":"139"},{"ID":"145","measuredH":"32","measuredW":"69","properties":{"align":"center","color":"15658734","size":"18","text":"Sphinx"},"typeID":"TextInput","w":"80","x":"305","y":"1410","zOrder":"140"},{"ID":"146","measuredH":"32","measuredW":"106","properties":{"align":"center","color":"15658734","size":"18","text":"Couchbase"},"typeID":"TextInput","w":"246","x":"832","y":"1688","zOrder":"141"},{"ID":"147","h":"43","measuredH":"42","measuredW":"110","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":42},"p1":{"x":0.4557377049180327,"y":0.11311475409836064},"p2":{"x":110,"y":1},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"111","x":"636","y":"414","zOrder":"142"},{"ID":"148","h":"17","measuredH":"16","measuredW":"193","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":193,"y":0},"p1":{"x":0.30006759497093416,"y":0.05572529403812356},"p2":{"x":0,"y":14},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"194","x":"879","y":"405","zOrder":"143"},{"ID":"149","measuredH":"32","measuredW":"58","properties":{"align":"center","color":"15658734","size":"18","text":"Flask"},"typeID":"TextInput","w":"142","x":"1226","y":"246","zOrder":"144"},{"ID":"150","measuredH":"32","measuredW":"72","properties":{"align":"center","color":"16776960","size":"18","text":"Django"},"typeID":"TextInput","w":"142","x":"1226","y":"282","zOrder":"145"},{"ID":"151","h":"46","measuredH":"45","measuredW":"20","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":45},"p1":{"x":0.4047619047619048,"y":0.047619047619047616},"p2":{"x":20,"y":0},"rightArrow":"false","shape":"bezier","text":""},"typeID":"Arrow","w":"21","x":"1084","y":"332","zOrder":"146"},{"ID":"152","measuredH":"32","measuredW":"80","properties":{"align":"center","color":"15658734","size":"18","text":"Pyramid"},"typeID":"TextInput","w":"142","x":"1226","y":"211","zOrder":"147"},{"ID":"153","h":"45","measuredH":"43","measuredW":"87","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":87,"y":0},"p1":{"x":0.41884488965409294,"y":0.22350915636249805},"p2":{"x":0,"y":41},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"89","x":"878","y":"367","zOrder":"148"},{"ID":"154","measuredH":"26","measuredW":"63","properties":{"bold":"true","size":"18","text":"Testing"},"typeID":"Label","x":"934","y":"343","zOrder":"149"},{"ID":"155","measuredH":"32","measuredW":"67","properties":{"align":"center","color":"15658734","size":"18","text":"py.test"},"typeID":"TextInput","w":"142","x":"902","y":"246","zOrder":"150"},{"ID":"156","measuredH":"32","measuredW":"137","properties":{"align":"center","color":"16776960","size":"18","text":"unittest/pyUnit"},"typeID":"TextInput","w":"142","x":"902","y":"282","zOrder":"151"},{"ID":"157","h":"26","measuredH":"25","measuredW":"2","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":2,"y":25},"p1":{"x":0.32114467408585057,"y":0.014308426073131956},"p2":{"x":0,"y":0},"rightArrow":"true","shape":"bezier","text":""},"typeID":"Arrow","w":"3","x":"963","y":"318","zOrder":"152"},{"ID":"158","measuredH":"32","measuredW":"77","properties":{"align":"center","color":"15658734","size":"18","text":"doctest"},"typeID":"TextInput","w":"142","x":"902","y":"211","zOrder":"153"},{"ID":"159","h":"70","measuredH":"69","measuredW":"4","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.5532446697169622,"x":0.5522012578616352,"y":0.033962264150943396},"p2":{"length":69.06518659932803,"x":3,"y":69},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"5","x":"793","y":"329","zOrder":"154"},{"ID":"160","measuredH":"26","measuredW":"151","properties":{"bold":"true","size":"18","text":"Package Manager"},"typeID":"Label","x":"728","y":"300","zOrder":"155"},{"ID":"161","h":"38","measuredH":"37","measuredW":"2","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"false","p0":{"length":37.05401462729781,"x":2,"y":37},"p1":{"length":0.6878740667500971,"x":0.6878048780487804,"y":0.009756097560975624},"p2":{"length":1,"x":1,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"3","x":"790","y":"267","zOrder":"156"},{"ID":"162","measuredH":"32","measuredW":"40","properties":{"align":"center","color":"16776960","size":"18","text":"Pip"},"typeID":"TextInput","w":"130","x":"728","y":"228","zOrder":"157"},{"ID":"163","measuredH":"32","measuredW":"67","properties":{"align":"center","color":"15658734","size":"18","text":"Caddy"},"typeID":"TextInput","w":"117","x":"117","y":"812","zOrder":"158"},{"ID":"164","h":"54","measuredH":"53","measuredW":"76","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":76,"y":53},"p1":{"x":0.511578947368421,"y":-0.1031578947368421},"p2":{"x":0,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"77","x":"239","y":"832","zOrder":"159"},{"ID":"165","measuredH":"32","measuredW":"87","properties":{"align":"center","color":"15658734","size":"18","text":"GraphQL"},"typeID":"TextInput","w":"231","x":"306","y":"1142","zOrder":"160"},{"ID":"166","h":"287","measuredH":"286","measuredW":"144","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":144,"y":0},"p1":{"x":0.515039207271876,"y":0.1159637966683572},"p2":{"x":0,"y":286},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"145","x":"543","y":"870","zOrder":"161"},{"ID":"167","measuredH":"32","measuredW":"72","properties":{"align":"center","color":"16776960","size":"18","text":"Docker"},"typeID":"TextInput","w":"231","x":"306","y":"1177","zOrder":"162"},{"ID":"168","h":"321","measuredH":"320","measuredW":"149","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":149,"y":0},"p1":{"x":0.5121913158818711,"y":0.1355089142901728},"p2":{"x":0,"y":320},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"150","x":"544","y":"876","zOrder":"163"},{"ID":"169","measuredH":"26","measuredW":"43","properties":{"bold":"true","size":"18","text":"Sync"},"typeID":"Label","x":"1094","y":"300","zOrder":"164"},{"ID":"170","h":"70","measuredH":"69","measuredW":"99","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":69},"p1":{"x":0.45920889987639063,"y":0.1950968273588793},"p2":{"x":99,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"100","x":"1124","y":"226","zOrder":"165"},{"ID":"171","h":"38","measuredH":"37","measuredW":"89","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":37},"p1":{"x":0.4303716360529688,"y":0.15313968389577104},"p2":{"x":89,"y":1},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"90","x":"1136","y":"263","zOrder":"166"},{"ID":"172","h":"10","measuredH":"9","measuredW":"77","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":9},"p1":{"x":0.4227014755959138,"y":-0.01452894438138478},"p2":{"x":77,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"78","x":"1144","y":"299","zOrder":"167"},{"ID":"173","measuredH":"26","measuredW":"52","properties":{"bold":"true","size":"18","text":"Async"},"typeID":"Label","x":"1128","y":"422","zOrder":"168"},{"ID":"174","h":"24","measuredH":"23","measuredW":"234","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.6014234875444839,"y":-0.07473309608540925},"p2":{"x":234,"y":10},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"235","x":"878","y":"427","zOrder":"169"},{"ID":"175","measuredH":"32","measuredW":"70","properties":{"align":"center","color":"15658734","size":"18","text":"gevent"},"typeID":"TextInput","w":"142","x":"1265","y":"399","zOrder":"170"},{"ID":"176","measuredH":"32","measuredW":"70","properties":{"align":"center","color":"16776960","size":"18","text":"aiohttp"},"typeID":"TextInput","w":"142","x":"1265","y":"435","zOrder":"171"},{"ID":"177","measuredH":"32","measuredW":"81","properties":{"align":"center","color":"15658734","size":"18","text":"Tornado"},"typeID":"TextInput","w":"142","x":"1265","y":"364","zOrder":"172"},{"ID":"178","h":"32","measuredH":"31","measuredW":"64","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"length":31,"x":0,"y":31},"p1":{"length":0.4695655473719175,"x":0.4557377049180327,"y":0.11311475409836094},"p2":{"length":64,"x":64,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"65","x":"1198","y":"379","zOrder":"173"},{"ID":"179","h":"8","measuredH":"7","measuredW":"66","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"length":7,"x":0,"y":7},"p1":{"length":0.4229510937399269,"x":0.4227014755959139,"y":-0.01452894438138492},"p2":{"length":66,"x":66,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"67","x":"1198","y":"417","zOrder":"174"},{"ID":"180","h":"13","measuredH":"12","measuredW":"60","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.42295109373992673,"x":0.4227014755959138,"y":-0.014528944381384704},"p2":{"length":61.18823416311342,"x":60,"y":12},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"61","x":"1200","y":"440","zOrder":"175"},{"ID":"181","measuredH":"26","measuredW":"101","properties":{"bold":"true","size":"18","text":"Frameworks"},"typeID":"Label","x":"1030","y":"379","zOrder":"176"},{"ID":"182","measuredH":"32","measuredW":"54","properties":{"align":"center","color":"16770457","size":"18","text":"Silex"},"typeID":"TextInput","w":"139","x":"933","y":"835","zOrder":"177"},{"ID":"183","h":"4","measuredH":"3","measuredW":"98","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":1},"p1":{"x":0.5688243831640057,"y":0.012423802612481858},"p2":{"x":98,"y":3},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"99","x":"881","y":"540","zOrder":"178"},{"ID":"184","measuredH":"32","measuredW":"78","properties":{"align":"center","color":"15658734","size":"18","text":"xDebug"},"typeID":"TextInput","w":"139","x":"1234","y":"573","zOrder":"179"},{"ID":"185","measuredH":"32","measuredW":"72","properties":{"align":"center","color":"15658734","size":"18","text":"XHProf"},"typeID":"TextInput","w":"139","x":"1234","y":"608","zOrder":"180"},{"ID":"186","measuredH":"26","measuredW":"154","properties":{"bold":"true","size":"18","text":"Debugger/Profiler"},"typeID":"Label","x":"983","y":"531","zOrder":"181"},{"ID":"187","h":"25","measuredH":"24","measuredW":"83","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.6077640824789771,"y":0.0346734247206543},"p2":{"x":83,"y":24},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"84","x":"1146","y":"546","zOrder":"182"},{"ID":"188","measuredH":"32","measuredW":"95","properties":{"align":"center","color":"15658734","size":"18","text":"New Relic"},"typeID":"TextInput","w":"139","x":"1234","y":"644","zOrder":"183"},{"ID":"189","measuredH":"32","measuredW":"84","properties":{"align":"center","color":"15658734","size":"18","text":"Blackfire"},"typeID":"TextInput","w":"139","x":"1234","y":"679","zOrder":"184"},{"ID":"190","h":"13","measuredH":"12","measuredW":"168","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":168,"y":0},"p1":{"x":0.6863437367603445,"y":0.030574777573789017},"p2":{"x":0,"y":10},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"169","x":"227","y":"422","zOrder":"185"},{"ID":"191","measuredH":"32","measuredW":"77","properties":{"align":"center","color":"15658734","size":"18","text":"ByeBug"},"typeID":"TextInput","w":"139","x":"84","y":"415","zOrder":"186"},{"ID":"192","measuredH":"32","measuredW":"60","properties":{"align":"center","color":"15658734","size":"18","text":"Sanic"},"typeID":"TextInput","w":"142","x":"1264","y":"328","zOrder":"187"},{"ID":"193","measuredH":"32","measuredW":"54","properties":{"align":"center","color":"15658734","size":"18","text":"nose"},"typeID":"TextInput","w":"142","x":"903","y":"176","zOrder":"188"}]},"measuredH":"1865","measuredW":"1407","mockupH":"1824","mockupW":"1368","version":"1.0"}} \ No newline at end of file diff --git a/project-files/devops-map.json b/project-files/devops-map.json deleted file mode 100644 index cf7da14cdd22..000000000000 --- a/project-files/devops-map.json +++ /dev/null @@ -1 +0,0 @@ -{"mockup":{"controls":{"control":[{"ID":"194","measuredH":"40","measuredW":"119","properties":{"bold":"true","size":"32","text":"DevOps"},"typeID":"Label","x":"652","y":"124","zOrder":"0"},{"ID":"195","h":"105","measuredH":"104","measuredW":"12","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"length":2,"x":2,"y":0},"p1":{"length":0.47809989329107294,"x":0.46601941747572806,"y":0.10679611650485436},"p2":{"length":104,"x":0,"y":104},"rightArrow":"false","shape":"bezier","stroke":"dotted"},"typeID":"Arrow","w":"13","x":"731","y":"16","zOrder":"1"},{"ID":"196","h":"147","measuredH":"146","measuredW":"10","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.4301356220719697,"x":0.4251067223342871,"y":0.06558146080592954},"p2":{"length":146.00342461736986,"x":1,"y":146},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"11","x":"715","y":"180","zOrder":"2"},{"ID":"197","h":"475","measuredH":"474","measuredW":"57","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"length":1,"x":1,"y":0},"p1":{"length":0.5515933856670949,"x":0.5501641704563411,"y":-0.03968184292311207},"p2":{"length":477.4149138851865,"x":57,"y":474},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"58","x":"715","y":"336","zOrder":"3"},{"ID":"198","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"691","y":"312","zOrder":"4"},{"ID":"203","h":"44","measuredH":"43","measuredW":"157","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.4934050443495624,"x":0.4809722749715154,"y":-0.1100645651348272},"p2":{"length":162.265215003093,"x":157,"y":41},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"158","x":"558","y":"299","zOrder":"5"},{"ID":"204","measuredH":"32","measuredW":"50","properties":{"align":"center","color":"16770457","size":"18","text":"Unix"},"typeID":"TextInput","w":"123","x":"391","y":"163","zOrder":"6"},{"ID":"205","measuredH":"32","measuredW":"57","properties":{"align":"center","color":"16770457","size":"18","text":"Linux"},"typeID":"TextInput","w":"106","x":"269","y":"164","zOrder":"7"},{"ID":"206","h":"68","measuredH":"67","measuredW":"41","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":1,"x":1,"y":0},"p1":{"length":0.4869902582973339,"x":0.4570883894856472,"y":-0.16801701066832864},"p2":{"length":78.54934754662193,"x":41,"y":67},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"42","x":"426","y":"205","zOrder":"8"},{"ID":"207","measuredH":"32","measuredW":"164","properties":{"align":"center","color":"16776960","size":"18","text":"Operating System"},"typeID":"TextInput","w":"168","x":"468","y":"264","zOrder":"9"},{"ID":"208","h":"79","measuredH":"78","measuredW":"137","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.4869902582973339,"x":0.4570883894856472,"y":-0.1680170106683286},"p2":{"length":157.64834283937145,"x":137,"y":78},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"138","x":"331","y":"203","zOrder":"10"},{"ID":"209","h":"68","measuredH":"67","measuredW":"177","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":180.6239186818844,"x":177,"y":36},"p1":{"length":0.4940024311499264,"x":0.4168473211520594,"y":-0.2650975534221121},"p2":{"length":67,"x":0,"y":67},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"178","x":"719","y":"269","zOrder":"11"},{"ID":"210","measuredH":"32","measuredW":"61","properties":{"align":"center","color":"16776960","size":"18","text":"Cloud"},"typeID":"TextInput","w":"168","x":"862","y":"309","zOrder":"12"},{"ID":"211","h":"50","measuredH":"49","measuredW":"82","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":93.05912099305472,"x":82,"y":44},"p1":{"length":0.6782899599731566,"x":0.5978750804893754,"y":0.32034771410173857},"p2":{"length":1,"x":1,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"83","x":"971","y":"340","zOrder":"13"},{"ID":"212","measuredH":"32","measuredW":"107","properties":{"align":"center","color":"15658734","size":"18","text":"Rackspace"},"typeID":"TextInput","w":"182","x":"1055","y":"368","zOrder":"14"},{"ID":"213","h":"88","measuredH":"87","measuredW":"98","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":126.50691680694776,"x":98,"y":80},"p1":{"length":0.5769423312009603,"x":0.4653531598513011,"y":0.3410408921933086},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"99","x":"954","y":"343","zOrder":"15"},{"ID":"214","measuredH":"32","measuredW":"54","properties":{"align":"center","color":"16776960","size":"18","text":"AWS"},"typeID":"TextInput","w":"182","x":"1055","y":"407","zOrder":"16"},{"ID":"215","h":"120","measuredH":"119","measuredW":"123","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":169.7586522095413,"x":123,"y":117},"p1":{"length":0.5859147708613179,"x":0.4960627165505897,"y":0.3117978511181885},"p2":{"length":1,"x":1,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"124","x":"928","y":"342","zOrder":"17"},{"ID":"216","measuredH":"32","measuredW":"72","properties":{"align":"center","color":"15658734","size":"18","text":"Heroku"},"typeID":"TextInput","w":"182","x":"1055","y":"444","zOrder":"18"},{"ID":"217","measuredH":"32","measuredW":"63","properties":{"align":"center","color":"15658734","size":"18","text":"Azure"},"typeID":"TextInput","w":"184","x":"1053","y":"482","zOrder":"19"},{"ID":"218","h":"156","measuredH":"155","measuredW":"146","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":212.93426215618751,"x":146,"y":155},"p1":{"length":0.5859147708613179,"x":0.4960627165505897,"y":0.3117978511181885},"p2":{"length":4,"x":4,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"147","x":"903","y":"342","zOrder":"20"},{"ID":"219","measuredH":"29","measuredW":"166","properties":{"align":"center","color":"15658734","size":"15","text":"Google Cloud Platform"},"typeID":"TextInput","w":"182","x":"1054","y":"519","zOrder":"21"},{"ID":"220","h":"193","measuredH":"192","measuredW":"165","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":253.15805339747735,"x":165,"y":192},"p1":{"length":0.5859147708613179,"x":0.4960627165505896,"y":0.3117978511181884},"p2":{"length":7,"x":7,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"166","x":"884","y":"343","zOrder":"22"},{"ID":"221","measuredH":"32","measuredW":"105","properties":{"align":"center","color":"16776960","size":"18","text":"Automation"},"typeID":"TextInput","w":"168","x":"421","y":"423","zOrder":"23"},{"ID":"222","h":"103","measuredH":"102","measuredW":"122","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":102,"x":0,"y":102},"p1":{"length":0.3843433494783224,"x":0.36800437796424645,"y":-0.11087194454578624},"p2":{"length":122,"x":122,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"123","x":"592","y":"336","zOrder":"24"},{"ID":"223","measuredH":"32","measuredW":"54","properties":{"align":"center","color":"15658734","size":"18","text":"Chef"},"typeID":"TextInput","w":"116","x":"239","y":"514","zOrder":"25"},{"ID":"224","measuredH":"32","measuredW":"74","properties":{"align":"center","color":"16770457","size":"18","text":"Ansible"},"typeID":"TextInput","w":"116","x":"361","y":"514","zOrder":"26"},{"ID":"225","measuredH":"32","measuredW":"73","properties":{"align":"center","color":"16770457","size":"18","text":"Puppet"},"typeID":"TextInput","w":"101","x":"483","y":"514","zOrder":"27"},{"ID":"226","h":"66","measuredH":"65","measuredW":"127","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"true","p0":{"length":65,"x":0,"y":65},"p1":{"length":0.47567843814048066,"x":0.4645604016027265,"y":0.1022428959609447},"p2":{"length":127,"x":127,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"128","x":"292","y":"444","zOrder":"28"},{"ID":"227","h":"58","measuredH":"57","measuredW":"13","properties":{"color":"2848996","curvature":"0","direction":"bottom","leftArrow":"true","p0":{"length":57,"x":0,"y":57},"p1":{"length":0.5269229044372591,"x":0.526916325336454,"y":-0.0026331187829139848},"p2":{"length":13,"x":13,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"14","x":"439","y":"458","zOrder":"29"},{"ID":"228","h":"60","measuredH":"59","measuredW":"1","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"true","p0":{"length":59.00847396772772,"x":1,"y":59},"p1":{"length":0.5084015562986306,"x":0.5083285468121769,"y":-0.00861573808156232},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"2","x":"518","y":"455","zOrder":"30"},{"ID":"229","measuredH":"32","measuredW":"78","properties":{"align":"center","color":"16776960","size":"18","text":"CI / CD"},"typeID":"TextInput","w":"168","x":"803","y":"586","zOrder":"31"},{"ID":"230","h":"237","measuredH":"236","measuredW":"120","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":264.7564918939666,"x":120,"y":236},"p1":{"length":0.4041626025095476,"x":0.3964277562200411,"y":-0.0786920794339192},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier","text":""},"typeID":"Arrow","w":"121","x":"724","y":"346","zOrder":"32"},{"ID":"231","h":"20","measuredH":"19","measuredW":"89","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":90.4267659490264,"x":89,"y":16},"p1":{"length":0.6859943405700353,"x":0.670906200317965,"y":0.14308426073131955},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"90","x":"939","y":"620","zOrder":"33"},{"ID":"232","measuredH":"32","measuredW":"77","properties":{"align":"center","color":"16770457","size":"18","text":"Jenkins"},"typeID":"TextInput","w":"182","x":"1032","y":"618","zOrder":"34"},{"ID":"233","measuredH":"32","measuredW":"63","properties":{"align":"center","color":"16770457","size":"18","text":"Travis"},"typeID":"TextInput","w":"184","x":"1030","y":"656","zOrder":"35"},{"ID":"234","measuredH":"32","measuredW":"93","properties":{"align":"center","color":"16770457","size":"18","text":"TeamCity"},"typeID":"TextInput","w":"182","x":"1031","y":"693","zOrder":"36"},{"ID":"235","h":"54","measuredH":"53","measuredW":"124","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":133.70115930686617,"x":124,"y":50},"p1":{"length":0.6812795800472109,"x":0.6424255985679123,"y":0.22678451555157753},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"125","x":"903","y":"618","zOrder":"37"},{"ID":"236","h":"92","measuredH":"91","measuredW":"145","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":170.66048165876012,"x":145,"y":90},"p1":{"length":0.6458020485348883,"x":0.590366687383468,"y":0.2617775015537601},"p2":{"length":1,"x":1,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"146","x":"884","y":"619","zOrder":"38"},{"ID":"237","measuredH":"32","measuredW":"63","properties":{"align":"center","color":"15658734","size":"18","text":"Drone"},"typeID":"TextInput","w":"182","x":"1032","y":"732","zOrder":"39"},{"ID":"238","measuredH":"32","measuredW":"80","properties":{"align":"center","color":"15658734","size":"18","text":"Bamboo"},"typeID":"TextInput","w":"182","x":"1033","y":"769","zOrder":"40"},{"ID":"239","h":"129","measuredH":"128","measuredW":"167","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":210.41150158677164,"x":167,"y":128},"p1":{"length":0.6458020485348883,"x":0.590366687383468,"y":0.2617775015537601},"p2":{"length":2,"x":2,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"168","x":"861","y":"619","zOrder":"41"},{"ID":"240","h":"165","measuredH":"164","measuredW":"200","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":258.6426105652354,"x":200,"y":164},"p1":{"length":0.6458020485348882,"x":0.5903666873834679,"y":0.2617775015537602},"p2":{"length":3,"x":3,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"201","x":"831","y":"619","zOrder":"42"},{"ID":"241","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"749","y":"795","zOrder":"43"},{"ID":"242","h":"29","measuredH":"28","measuredW":"178","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"true","p0":{"x":0,"y":0},"p1":{"x":0.3805593199457928,"y":0.009301466058888753},"p2":{"x":178,"y":28},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"179","x":"590","y":"794","zOrder":"44"},{"ID":"243","measuredH":"32","measuredW":"206","properties":{"align":"center","color":"16776960","size":"18","text":"Monitoring and Alerting"},"typeID":"TextInput","w":"230","x":"355","y":"775","zOrder":"45"},{"ID":"244","measuredH":"32","measuredW":"69","properties":{"align":"center","color":"16770457","size":"18","text":"Nagios"},"typeID":"TextInput","w":"101","x":"154","y":"709","zOrder":"46"},{"ID":"245","measuredH":"32","measuredW":"100","properties":{"align":"center","color":"16770457","size":"18","text":"PagerDuty"},"typeID":"TextInput","w":"101","x":"231","y":"576","zOrder":"47"},{"ID":"246","measuredH":"32","measuredW":"82","properties":{"align":"center","color":"15658734","size":"18","text":"Graphite"},"typeID":"TextInput","w":"101","x":"460","y":"576","zOrder":"48"},{"ID":"247","measuredH":"32","measuredW":"112","properties":{"align":"center","color":"15658734","size":"18","text":"Prometheus"},"typeID":"TextInput","w":"115","x":"531","y":"638","zOrder":"49"},{"ID":"248","measuredH":"32","measuredW":"127","properties":{"align":"center","color":"16770457","size":"18","text":"AppDynamics"},"typeID":"TextInput","w":"141","x":"114","y":"759","zOrder":"50"},{"ID":"249","h":"22","measuredH":"21","measuredW":"90","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"x":0,"y":0},"p1":{"x":0.47438524590163944,"y":0.03176229508196722},"p2":{"x":90,"y":21},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"91","x":"262","y":"776","zOrder":"51"},{"ID":"250","h":"43","measuredH":"42","measuredW":"91","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.4967064277201685,"x":0.49507591300779646,"y":0.04021337710299548},"p2":{"length":100.22474744293449,"x":91,"y":42},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"92","x":"263","y":"740","zOrder":"52"},{"ID":"251","h":"163","measuredH":"162","measuredW":"38","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.5520035911131103,"x":0.5482477876106194,"y":-0.06428318584070783},"p2":{"length":166.39711535961192,"x":38,"y":162},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"39","x":"400","y":"610","zOrder":"53"},{"ID":"252","h":"159","measuredH":"158","measuredW":"29","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":1,"x":1,"y":0},"p1":{"length":0.5520035911131101,"x":0.5482477876106193,"y":-0.06428318584070793},"p2":{"length":160.63934760823702,"x":29,"y":158},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"30","x":"502","y":"615","zOrder":"54"},{"ID":"253","h":"103","measuredH":"102","measuredW":"7","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":1,"x":1,"y":0},"p1":{"length":0.5944851299924161,"x":0.5934629929767694,"y":-0.03484602917341978},"p2":{"length":102.23991392797627,"x":7,"y":102},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"8","x":"563","y":"674","zOrder":"55"},{"ID":"254","h":"79","measuredH":"78","measuredW":"165","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":182.50753409106156,"x":165,"y":78},"p1":{"length":0.5387969581467017,"x":0.49148815671119694,"y":-0.22077489422660493},"p2":{"length":10,"x":0,"y":10},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"166","x":"778","y":"811","zOrder":"56"},{"ID":"255","measuredH":"32","measuredW":"100","properties":{"align":"center","color":"15658734","size":"18","text":"Salt Stack"},"typeID":"TextInput","w":"116","x":"176","y":"444","zOrder":"57"},{"ID":"256","h":"37","measuredH":"36","measuredW":"153","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"true","p0":{"length":36,"x":0,"y":36},"p1":{"length":0.41049609004336346,"x":0.3467837937687287,"y":0.2196543655843357},"p2":{"length":155.9134375222354,"x":153,"y":30},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"154","x":"269","y":"402","zOrder":"58"},{"ID":"257","measuredH":"32","measuredW":"98","properties":{"align":"center","color":"15658734","size":"18","text":"CF Engine"},"typeID":"TextInput","w":"116","x":"176","y":"349","zOrder":"59"},{"ID":"258","h":"74","measuredH":"73","measuredW":"149","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":19,"x":0,"y":19},"p1":{"length":0.41049609004336374,"x":0.346783793768729,"y":0.2196543655843358},"p2":{"length":165.92166826548,"x":149,"y":73},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"150","x":"297","y":"349","zOrder":"60"},{"ID":"259","measuredH":"32","measuredW":"104","properties":{"align":"center","color":"16776960","size":"18","text":"Containers"},"typeID":"TextInput","w":"168","x":"919","y":"892","zOrder":"61"},{"ID":"260","measuredH":"32","measuredW":"72","properties":{"align":"center","color":"16776960","size":"18","text":"Docker"},"typeID":"TextInput","w":"182","x":"1124","y":"822","zOrder":"62"},{"ID":"261","h":"55","measuredH":"54","measuredW":"103","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":103.0194156457898,"x":103,"y":2},"p1":{"length":0.5074373619782105,"x":0.4799819725080749,"y":-0.16465109291669797},"p2":{"length":54,"x":0,"y":54},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"104","x":"1014","y":"836","zOrder":"63"},{"ID":"262","measuredH":"32","measuredW":"115","properties":{"align":"center","color":"15658734","size":"18","text":"Digitalocean"},"typeID":"TextInput","w":"182","x":"1054","y":"555","zOrder":"64"},{"ID":"263","h":"229","measuredH":"228","measuredW":"189","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":296.150299679065,"x":189,"y":228},"p1":{"length":0.5604738542395299,"x":0.4815004659832246,"y":0.28685927306616965},"p2":{"length":5,"x":5,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"190","x":"865","y":"343","zOrder":"65"},{"ID":"264","h":"842","measuredH":"841","measuredW":"89","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":841.770158653774,"x":36,"y":841},"p1":{"length":0.40416260250954766,"x":0.3964277562200411,"y":-0.07869207943391922},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier","text":""},"typeID":"Arrow","w":"90","x":"774","y":"821","zOrder":"66"},{"ID":"265","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"flag-checkered","size":"large"}},"typeID":"Icon","x":"782","y":"1683","zOrder":"67"},{"ID":"267","measuredH":"32","measuredW":"37","properties":{"align":"center","color":"16770457","size":"18","text":"rkt"},"typeID":"TextInput","w":"182","x":"1124","y":"859","zOrder":"68"},{"ID":"268","h":"17","measuredH":"16","measuredW":"81","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":81.00617260431454,"x":81,"y":1},"p1":{"length":0.6565321642986127,"x":0.6511936339522546,"y":-0.08355437665782496},"p2":{"length":16,"x":0,"y":16},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"82","x":"1041","y":"875","zOrder":"69"},{"ID":"269","measuredH":"32","measuredW":"161","properties":{"align":"center","color":"16776960","size":"18","text":"Cluster Managers"},"typeID":"TextInput","w":"168","x":"442","y":"961","zOrder":"70"},{"ID":"270","h":"153","measuredH":"152","measuredW":"155","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":152,"x":0,"y":152},"p1":{"length":0.3730354812206476,"x":0.34836852207293667,"y":-0.13339731285988485},"p2":{"length":155,"x":155,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"156","x":"613","y":"821","zOrder":"71"},{"ID":"271","h":"12","measuredH":"11","measuredW":"105","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"true","p0":{"x":0,"y":11},"p1":{"x":0.5613096317794304,"y":0.0624886631598041},"p2":{"x":105,"y":5},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"106","x":"338","y":"967","zOrder":"72"},{"ID":"272","measuredH":"32","measuredW":"109","properties":{"align":"center","color":"16770457","size":"18","text":"Kubernetes"},"typeID":"TextInput","w":"182","x":"152","y":"964","zOrder":"73"},{"ID":"273","h":"29","measuredH":"28","measuredW":"104","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"x":0,"y":28},"p1":{"x":0.5482477876106191,"y":-0.0642831858407078},"p2":{"x":104,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"105","x":"341","y":"991","zOrder":"74"},{"ID":"274","measuredH":"32","measuredW":"114","properties":{"align":"center","color":"16770457","size":"18","text":"Mesosphere"},"typeID":"TextInput","w":"182","x":"152","y":"1004","zOrder":"75"},{"ID":"275","measuredH":"32","measuredW":"68","properties":{"align":"center","color":"16770457","size":"18","text":"Mesos"},"typeID":"TextInput","w":"182","x":"152","y":"1043","zOrder":"76"},{"ID":"276","h":"59","measuredH":"58","measuredW":"127","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":58,"x":0,"y":58},"p1":{"length":0.55200359111311,"x":0.5482477876106192,"y":-0.06428318584070777},"p2":{"length":127,"x":127,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"128","x":"337","y":"994","zOrder":"77"},{"ID":"277","measuredH":"32","measuredW":"133","properties":{"align":"center","color":"16770457","size":"18","text":"Docker Swarm"},"typeID":"TextInput","w":"182","x":"244","y":"1083","zOrder":"78"},{"ID":"278","h":"89","measuredH":"88","measuredW":"65","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":88,"x":0,"y":88},"p1":{"length":0.6545112618155575,"x":0.6482871125611747,"y":-0.09004893964110934},"p2":{"length":65,"x":65,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"66","x":"421","y":"996","zOrder":"79"},{"ID":"279","measuredH":"32","measuredW":"72","properties":{"align":"center","color":"16770457","size":"18","text":"Nomad"},"typeID":"TextInput","w":"182","x":"453","y":"1083","zOrder":"80"},{"ID":"280","h":"86","measuredH":"85","measuredW":"10","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":85.00588214941364,"x":1,"y":85},"p1":{"length":0.6526170293253694,"x":0.6420077749828493,"y":-0.11719643265492792},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"11","x":"522","y":"996","zOrder":"81"},{"ID":"281","h":"119","measuredH":"118","measuredW":"165","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":1,"x":0,"y":1},"p1":{"length":0.5147451733782548,"x":0.4837905236907732,"y":0.17581047381546133},"p2":{"length":202.85216291674092,"x":165,"y":118},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"166","x":"303","y":"302","zOrder":"82"},{"ID":"282","measuredH":"32","measuredW":"93","properties":{"align":"center","color":"16770457","size":"18","text":"Terraform"},"typeID":"TextInput","w":"116","x":"185","y":"287","zOrder":"83"},{"ID":"283","measuredH":"29","measuredW":"161","properties":{"align":"center","color":"16770457","size":"15","text":"AWS Cloud Formation"},"typeID":"TextInput","w":"163","x":"475","y":"359","zOrder":"84"},{"ID":"284","h":"33","measuredH":"32","measuredW":"4","properties":{"color":"2848996","curvature":"0","direction":"bottom","leftArrow":"false","p0":{"length":32,"x":0,"y":32},"p1":{"length":0.5084015562986307,"x":0.508328546812177,"y":-0.008615738081562331},"p2":{"length":4,"x":4,"y":0},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"5","x":"526","y":"390","zOrder":"85"},{"ID":"285","h":"399","measuredH":"398","measuredW":"73","properties":{"color":"2848996","curvature":"0","direction":"bottom","leftArrow":"true","p0":{"length":398,"x":0,"y":398},"p1":{"length":0.3436579847258308,"x":0.34351657882039666,"y":-0.009857511924902128},"p2":{"length":73,"x":73,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"74","x":"699","y":"821","zOrder":"86"},{"ID":"286","measuredH":"32","measuredW":"156","properties":{"align":"center","color":"16776960","size":"18","text":"Love for Terminal"},"typeID":"TextInput","w":"159","x":"567","y":"1223","zOrder":"87"},{"ID":"287","h":"40","measuredH":"39","measuredW":"90","properties":{"color":"2848996","curvature":"0","direction":"bottom","leftArrow":"true","p0":{"length":39,"x":0,"y":39},"p1":{"length":0.5248229639985018,"x":0.5247895229186157,"y":0.005924540068599915},"p2":{"length":90,"x":90,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"91","x":"476","y":"1240","zOrder":"88"},{"ID":"288","measuredH":"32","measuredW":"118","properties":{"align":"center","color":"16776960","size":"18","text":"Bash Scripts"},"typeID":"TextInput","w":"136","x":"338","y":"1261","zOrder":"89"},{"ID":"289","h":"66","measuredH":"65","measuredW":"105","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":65,"x":0,"y":65},"p1":{"length":0.5346528392673001,"x":0.5287804878048781,"y":-0.07902439024390241},"p2":{"length":105,"x":105,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"106","x":"476","y":"1255","zOrder":"90"},{"ID":"290","measuredH":"32","measuredW":"105","properties":{"align":"center","color":"16776960","size":"18","text":"Vim / Nano"},"typeID":"TextInput","w":"136","x":"337","y":"1304","zOrder":"91"},{"ID":"291","h":"110","measuredH":"109","measuredW":"131","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":109,"x":0,"y":109},"p1":{"length":0.5346528392673001,"x":0.5287804878048781,"y":-0.0790243902439025},"p2":{"length":131,"x":131,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"132","x":"483","y":"1256","zOrder":"92"},{"ID":"292","measuredH":"32","measuredW":"120","properties":{"align":"center","color":"16776960","size":"18","text":"Web Servers"},"typeID":"TextInput","w":"138","x":"909","y":"961","zOrder":"93"},{"ID":"293","h":"138","measuredH":"137","measuredW":"127","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":186.81006396872735,"x":127,"y":137},"p1":{"length":0.4961462141111039,"x":0.48035560653857184,"y":-0.1241755090335533},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"128","x":"787","y":"823","zOrder":"94"},{"ID":"294","measuredH":"32","measuredW":"76","properties":{"align":"center","color":"16776960","size":"18","text":"Apache"},"typeID":"TextInput","w":"182","x":"1105","y":"946","zOrder":"95"},{"ID":"295","h":"11","measuredH":"10","measuredW":"57","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":57.0350769263968,"x":57,"y":2},"p1":{"length":0.5041332333156514,"x":0.4965288258376094,"y":-0.08723211590703289},"p2":{"length":10,"x":0,"y":10},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"58","x":"1047","y":"962","zOrder":"96"},{"ID":"296","measuredH":"32","measuredW":"60","properties":{"align":"center","color":"16776960","size":"18","text":"Nginx"},"typeID":"TextInput","w":"182","x":"1106","y":"982","zOrder":"97"},{"ID":"297","h":"21","measuredH":"20","measuredW":"58","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":61.35144660071187,"x":58,"y":20},"p1":{"length":0.4074883541492552,"x":0.4070138150903294,"y":0.019659936238044632},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"59","x":"1047","y":"981","zOrder":"98"},{"ID":"298","h":"185","measuredH":"140","measuredW":"180","properties":{"text":"Differences and when to use what"},"typeID":"VCurly","w":"180","x":"1294","y":"940","zOrder":"99"},{"ID":"299","measuredH":"32","measuredW":"317","properties":{"align":"center","color":"16776960","size":"18","text":"Setting up a Reverse Proxy (Nginx ..)"},"typeID":"TextInput","w":"447","x":"993","y":"1236","zOrder":"100"},{"ID":"300","measuredH":"32","measuredW":"74","properties":{"align":"center","color":"16770457","size":"18","text":"Tomcat"},"typeID":"TextInput","w":"182","x":"1105","y":"1020","zOrder":"101"},{"ID":"301","h":"48","measuredH":"47","measuredW":"61","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":77.00649323271382,"x":61,"y":47},"p1":{"length":0.5585454489562574,"x":0.5247892074198989,"y":0.19123102866779093},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"62","x":"1045","y":"991","zOrder":"102"},{"ID":"302","measuredH":"32","measuredW":"39","properties":{"align":"center","color":"16770457","size":"18","text":"IIS"},"typeID":"TextInput","w":"182","x":"1106","y":"1058","zOrder":"103"},{"ID":"303","h":"79","measuredH":"78","measuredW":"78","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":110.3086578651014,"x":78,"y":78},"p1":{"length":0.4797853179785701,"x":0.44230769230769235,"y":0.1858974358974359},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"79","x":"1028","y":"995","zOrder":"104"},{"ID":"304","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"831","y":"1220","zOrder":"105"},{"ID":"305","h":"10","measuredH":"8","measuredW":"138","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"true","p0":{"length":138.2316895650198,"x":138,"y":8},"p1":{"length":0.5,"x":0.5,"y":0},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"140","x":"857","y":"1244","zOrder":"106"},{"ID":"306","measuredH":"32","measuredW":"365","properties":{"align":"center","color":"16776960","size":"18","text":"Setting up caching Server (Squid, Nginx ..)"},"typeID":"TextInput","w":"446","x":"993","y":"1272","zOrder":"107"},{"ID":"307","h":"36","measuredH":"35","measuredW":"127","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":131.73458164050928,"x":127,"y":35},"p1":{"length":0.5754174316949375,"x":0.5710499020398756,"y":0.07076178402673736},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"128","x":"867","y":"1254","zOrder":"108"},{"ID":"308","measuredH":"32","measuredW":"387","properties":{"align":"center","color":"16776960","size":"18","text":"Setting up a load balancer (HAProxy, Nginx ..)"},"typeID":"TextInput","w":"444","x":"994","y":"1310","zOrder":"109"},{"ID":"309","h":"72","measuredH":"71","measuredW":"126","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":144.62710672622887,"x":126,"y":71},"p1":{"length":0.5556548491193326,"x":0.5375099057849784,"y":0.14083824953773005},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"127","x":"866","y":"1255","zOrder":"110"},{"ID":"310","measuredH":"32","measuredW":"535","properties":{"align":"center","color":"16776960","size":"18","text":"Compiling apps from source (gcc, make and other related stuff)"},"typeID":"TextInput","w":"550","x":"140","y":"1145","zOrder":"111"},{"ID":"311","h":"112","measuredH":"111","measuredW":"135","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":174.7741399635541,"x":135,"y":111},"p1":{"length":0.5556548491193327,"x":0.5375099057849785,"y":0.14083824953773005},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"136","x":"859","y":"1256","zOrder":"112"},{"ID":"312","measuredH":"32","measuredW":"333","properties":{"align":"center","color":"16776960","size":"18","text":"Knowledge about different file systems"},"typeID":"TextInput","w":"447","x":"993","y":"1199","zOrder":"113"},{"ID":"313","measuredH":"32","measuredW":"340","properties":{"align":"center","color":"16776960","size":"18","text":"OSI Model. TCP/IP/UDP Common ports"},"typeID":"TextInput","w":"447","x":"993","y":"1164","zOrder":"114"},{"ID":"314","h":"27","measuredH":"26","measuredW":"129","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":129.00387591076478,"x":129,"y":1},"p1":{"length":0.5534965054116332,"x":0.5491329479768786,"y":-0.06936416184971098},"p2":{"length":26,"x":0,"y":26},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"130","x":"864","y":"1214","zOrder":"115"},{"ID":"315","h":"57","measuredH":"56","measuredW":"129","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"length":129,"x":129,"y":0},"p1":{"length":0.5534965054116332,"x":0.5491329479768786,"y":-0.06936416184971089},"p2":{"length":56,"x":0,"y":56},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"130","x":"860","y":"1178","zOrder":"116"},{"ID":"316","h":"56","measuredH":"55","measuredW":"157","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.432857006945666,"x":0.3992980660256645,"y":-0.16711146857748693},"p2":{"length":165.38742394752995,"x":157,"y":52},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"158","x":"407","y":"1176","zOrder":"117"},{"ID":"317","measuredH":"32","measuredW":"177","properties":{"align":"center","color":"16776960","size":"18","text":"Setting up a firewall"},"typeID":"TextInput","w":"439","x":"999","y":"1345","zOrder":"118"},{"ID":"318","measuredH":"32","measuredW":"157","properties":{"align":"center","color":"16776960","size":"18","text":"Commands/Tools"},"typeID":"TextInput","w":"166","x":"315","y":"1348","zOrder":"119"},{"ID":"319","h":"87","measuredH":"86","measuredW":"92","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"true","p0":{"length":86.00581375697809,"x":1,"y":86},"p1":{"length":0.5625961582184792,"x":0.4916028285209192,"y":0.27357100766057746},"p2":{"length":92.00543462209176,"x":92,"y":1},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"93","x":"222","y":"1365","zOrder":"120"},{"ID":"320","h":"132","measuredH":"140","measuredW":"200","properties":{"size":"17","text":"awk, sed, grep, sort, uniq, cat, cut, echo, fmt, tr, nl, egrep, fgrep, wc ..etc"},"typeID":"TextArea","w":"185","x":"143","y":"1482","zOrder":"121"},{"ID":"321","measuredH":"32","measuredW":"157","properties":{"align":"center","color":"16776960","size":"18","text":"Text Manipulation"},"typeID":"TextInput","w":"184","x":"144","y":"1455","zOrder":"122"},{"ID":"322","h":"47","measuredH":"140","measuredW":"200","properties":{"size":"17","text":"ps, top, htop, atop ..etc"},"typeID":"TextArea","w":"194","x":"337","y":"1479","zOrder":"123"},{"ID":"323","measuredH":"32","measuredW":"172","properties":{"align":"center","color":"16776960","size":"18","text":"Process Monitoring"},"typeID":"TextInput","w":"194","x":"338","y":"1452","zOrder":"124"},{"ID":"324","h":"55","measuredH":"140","measuredW":"200","properties":{"size":"17","text":"nmon, iostat, sar, vmstat ..etc"},"typeID":"TextArea","w":"196","x":"337","y":"1559","zOrder":"125"},{"ID":"325","measuredH":"32","measuredW":"187","properties":{"align":"center","color":"16776960","size":"18","text":"System Performance"},"typeID":"TextInput","w":"194","x":"338","y":"1532","zOrder":"126"},{"ID":"326","h":"135","measuredH":"140","measuredW":"200","properties":{"size":"17","text":"nmap, tcpdump, ping, traceroute, airmon, airodump ..etc"},"typeID":"TextArea","w":"194","x":"540","y":"1479","zOrder":"127"},{"ID":"327","measuredH":"32","measuredW":"82","properties":{"align":"center","color":"16776960","size":"18","text":"Network"},"typeID":"TextInput","w":"194","x":"541","y":"1452","zOrder":"128"},{"ID":"328","h":"72","measuredH":"71","measuredW":"11","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":71.449282711585,"x":8,"y":71},"p1":{"length":0.5195492659651598,"x":0.5098922624877571,"y":-0.09970617042115572},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"12","x":"384","y":"1380","zOrder":"129"},{"ID":"329","h":"72","measuredH":"71","measuredW":"97","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"true","p0":{"length":120.20815280171308,"x":97,"y":71},"p1":{"length":0.4352941176470589,"x":0.43017301038062294,"y":-0.0665743944636678},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"98","x":"444","y":"1382","zOrder":"130"},{"ID":"330","measuredH":"32","measuredW":"473","properties":{"align":"center","color":"16776960","size":"18","text":"TLS, STARTTLS, SSL, HTTPS, SCP, SSH, SFTP, FTPS .."},"typeID":"TextInput","w":"438","x":"1002","y":"1380","zOrder":"131"},{"ID":"331","measuredH":"32","measuredW":"433","properties":{"align":"center","color":"16776960","size":"18","text":"Postmortem analysis when something bad happens"},"typeID":"TextInput","w":"439","x":"1002","y":"1415","zOrder":"132"},{"ID":"332","h":"141","measuredH":"140","measuredW":"146","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":202.27703774773843,"x":146,"y":140},"p1":{"length":0.525498727469184,"x":0.4908858561990645,"y":0.18756329266528424},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"147","x":"857","y":"1255","zOrder":"133"},{"ID":"333","h":"179","measuredH":"178","measuredW":"148","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":231.49082055234933,"x":148,"y":178},"p1":{"length":0.5254987274691845,"x":0.4908858561990649,"y":0.18756329266528457},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"149","x":"855","y":"1255","zOrder":"134"},{"ID":"334","measuredH":"32","measuredW":"67","properties":{"align":"center","color":"16770457","size":"18","text":"Caddy"},"typeID":"TextInput","w":"182","x":"1106","y":"1093","zOrder":"135"},{"ID":"335","h":"115","measuredH":"114","measuredW":"94","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":147.75655653811103,"x":94,"y":114},"p1":{"length":0.4797853179785701,"x":0.44230769230769235,"y":0.1858974358974359},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"95","x":"1010","y":"995","zOrder":"136"},{"ID":"336","measuredH":"32","measuredW":"50","properties":{"align":"center","color":"15658734","size":"18","text":"LXC"},"typeID":"TextInput","w":"182","x":"1124","y":"894","zOrder":"137"},{"ID":"337","h":"2","measuredH":"1","measuredW":"37","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":37.013511046643494,"x":37,"y":1},"p1":{"length":0.5787470059411219,"x":0.578546712802768,"y":0.015224913494809686},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"38","x":"1087","y":"909","zOrder":"138"},{"ID":"338","measuredH":"32","measuredW":"132","properties":{"align":"center","color":"15658734","size":"18","text":"Cloud Foundry"},"typeID":"TextInput","w":"182","x":"1055","y":"331","zOrder":"139"},{"ID":"339","h":"18","measuredH":"17","measuredW":"61","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":61.1310068623117,"x":61,"y":4},"p1":{"length":0.6415294809487804,"x":0.59004549103559,"y":0.2518062617072518},"p2":{"length":0,"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"62","x":"995","y":"339","zOrder":"140"},{"ID":"340","measuredH":"32","measuredW":"70","properties":{"align":"center","color":"15658734","size":"18","text":"Zabbix"},"typeID":"TextInput","w":"103","x":"606","y":"683","zOrder":"141"},{"ID":"341","h":"61","measuredH":"60","measuredW":"45","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"true","p0":{"length":45,"x":45,"y":0},"p1":{"length":0.5584104424365847,"x":0.5573333333333333,"y":0.034666666666666665},"p2":{"length":60,"x":0,"y":60},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"46","x":"582","y":"718","zOrder":"142"},{"ID":"342","measuredH":"32","measuredW":"62","properties":{"align":"center","color":"16770457","size":"18","text":"Munin"},"typeID":"TextInput","w":"101","x":"348","y":"576","zOrder":"143"},{"ID":"343","h":"163","measuredH":"162","measuredW":"114","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"x":0,"y":0},"p1":{"x":0.5402140672782875,"y":0.039602446483180426},"p2":{"x":114,"y":162},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"115","x":"280","y":"613","zOrder":"144"},{"ID":"344","measuredH":"32","measuredW":"95","properties":{"align":"center","color":"16770457","size":"18","text":"New Relic"},"typeID":"TextInput","w":"101","x":"154","y":"650","zOrder":"145"},{"ID":"345","h":"87","measuredH":"86","measuredW":"105","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"x":0,"y":0},"p1":{"x":0.4950759130077962,"y":0.040213377102995426},"p2":{"x":105,"y":86},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"106","x":"262","y":"687","zOrder":"146"},{"ID":"346","measuredH":"32","measuredW":"248","properties":{"align":"center","color":"16776960","size":"18","text":"Log Management & Analysis"},"typeID":"TextInput","w":"255","x":"355","y":"847","zOrder":"147"},{"ID":"347","h":"41","measuredH":"40","measuredW":"156","properties":{"color":"2848996","curvature":"0","direction":"bottom","leftArrow":"true","p0":{"x":0,"y":40},"p1":{"x":0.3805593199457928,"y":0.009301466058888753},"p2":{"x":156,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"157","x":"615","y":"824","zOrder":"148"},{"ID":"348","measuredH":"32","measuredW":"91","properties":{"align":"center","color":"15658734","size":"18","text":"Papertrail"},"typeID":"TextInput","w":"115","x":"147","y":"809","zOrder":"149"},{"ID":"349","measuredH":"32","measuredW":"48","properties":{"align":"center","color":"16776960","size":"18","text":"ELK"},"typeID":"TextInput","w":"115","x":"147","y":"846","zOrder":"150"},{"ID":"350","measuredH":"32","measuredW":"77","properties":{"align":"center","color":"15658734","size":"18","text":"Graylog"},"typeID":"TextInput","w":"115","x":"148","y":"883","zOrder":"151"},{"ID":"351","measuredH":"32","measuredW":"70","properties":{"align":"center","color":"15658734","size":"18","text":"Splunk"},"typeID":"TextInput","w":"115","x":"148","y":"919","zOrder":"152"},{"ID":"352","h":"22","measuredH":"21","measuredW":"90","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"true","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.4754473734474015,"x":0.47438524590163944,"y":0.031762295081967214},"p2":{"length":92.41753080449618,"x":90,"y":21},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"91","x":"269","y":"827","zOrder":"153"},{"ID":"353","h":"9","measuredH":"8","measuredW":"86","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"true","p0":{"x":0,"y":8},"p1":{"x":0.47438524590163944,"y":0.031762295081967214},"p2":{"x":86,"y":1},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"87","x":"267","y":"857","zOrder":"154"},{"ID":"354","h":"24","measuredH":"23","measuredW":"84","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"true","p0":{"x":0,"y":23},"p1":{"x":0.47438524590163944,"y":0.03176229508196722},"p2":{"x":84,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"85","x":"266","y":"875","zOrder":"155"},{"ID":"355","h":"54","measuredH":"53","measuredW":"96","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"x":0,"y":53},"p1":{"x":0.5139593094153135,"y":-0.07566908414094088},"p2":{"x":96,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"97","x":"267","y":"884","zOrder":"156"}]},"measuredH":"1731","measuredW":"1474","mockupH":"1715","mockupW":"1360","version":"1.0"}} \ No newline at end of file diff --git a/project-files/frontend-map.json b/project-files/frontend-map.json deleted file mode 100644 index bcea277077ac..000000000000 --- a/project-files/frontend-map.json +++ /dev/null @@ -1 +0,0 @@ -{"mockup":{"controls":{"control":[{"ID":"356","measuredH":"40","measuredW":"149","properties":{"bold":"true","size":"32","text":"Front-end"},"typeID":"Label","x":"546","y":"312","zOrder":"0"},{"ID":"357","h":"74","measuredH":"73","measuredW":"18","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":8,"y":0},"p1":{"x":0.4589494163424125,"y":0.1931906614785992},"p2":{"x":0,"y":73},"rightArrow":"false","shape":"bezier","stroke":"dotted"},"typeID":"Arrow","w":"19","x":"620","y":"238","zOrder":"1"},{"ID":"358","h":"58","measuredH":"57","measuredW":"11","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"length":3,"x":3,"y":0},"p1":{"length":0.4752342503759221,"x":0.4639175257731959,"y":-0.10309278350515466},"p2":{"length":58.05170109479997,"x":11,"y":57},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"12","x":"608","y":"368","zOrder":"2"},{"ID":"359","measuredH":"26","measuredW":"147","properties":{"bold":"true","size":"18","text":"Learn the Basics"},"typeID":"Label","x":"572","y":"435","zOrder":"3"},{"ID":"360","h":"98","measuredH":"97","measuredW":"17","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":4,"y":0},"p1":{"x":0.47967479674796737,"y":0.1544715447154471},"p2":{"x":0,"y":97},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"18","x":"636","y":"473","zOrder":"4"},{"ID":"361","measuredH":"32","measuredW":"63","properties":{"align":"center","color":"16776960","size":"18","text":"HTML"},"typeID":"TextInput","w":"103","x":"403","y":"488","zOrder":"5"},{"ID":"362","measuredH":"32","measuredW":"52","properties":{"align":"center","color":"16776960","size":"18","text":"CSS"},"typeID":"TextInput","w":"103","x":"403","y":"547","zOrder":"6"},{"ID":"363","measuredH":"32","measuredW":"101","properties":{"align":"center","color":"16776960","size":"18","text":"JavaScript"},"typeID":"TextInput","w":"102","x":"403","y":"598","zOrder":"7"},{"ID":"364","measuredH":"32","measuredW":"71","properties":{"align":"center","color":"15658734","size":"18","text":"jQuery"},"typeID":"TextInput","w":"102","x":"238","y":"598","zOrder":"8"},{"ID":"365","h":"1","measuredH":"0","measuredW":"41","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"false","p0":{"length":41,"x":41,"y":0},"p1":{"length":0.49999999999999994,"x":0.49999999999999994,"y":0},"p2":{"length":0,"x":0,"y":0},"shape":"bezier","size":"18"},"typeID":"Arrow","w":"42","x":"353","y":"614","zOrder":"9"},{"ID":"366","h":"57","measuredH":"56","measuredW":"109","properties":{"color":"2848996","curvature":"0","direction":"top","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.4124001894134802,"x":0.41239928081507593,"y":0.0008656855563694176},"p2":{"length":122.54386969571348,"x":109,"y":56},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"110","x":"518","y":"508","zOrder":"10"},{"ID":"367","h":"11","measuredH":"10","measuredW":"115","properties":{"color":"2848996","curvature":"1","direction":"top","p0":{"length":1,"x":0,"y":1},"p1":{"length":0.39856406750964574,"x":0.39823587063051297,"y":0.016171185886965058},"p2":{"length":115.43396380615197,"x":115,"y":10},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"116","x":"514","y":"563","zOrder":"11"},{"ID":"368","h":"29","measuredH":"28","measuredW":"99","properties":{"color":"2848996","curvature":"1","direction":"bottom","p0":{"length":28,"x":0,"y":28},"p1":{"length":0.5728876708569787,"x":0.5727916863486066,"y":-0.010486537553141368},"p2":{"length":99,"x":99,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"100","x":"519","y":"585","zOrder":"12"},{"ID":"369","h":"61","measuredH":"60","measuredW":"10","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"length":10,"x":10,"y":0},"p1":{"length":0.5310742620768895,"x":0.5188679245283019,"y":-0.11320754716981138},"p2":{"length":60.207972893961475,"x":5,"y":60},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"11","x":"623","y":"585","zOrder":"13"},{"ID":"370","measuredH":"26","measuredW":"134","properties":{"bold":"true","size":"18","text":"Getting Deeper"},"typeID":"Label","x":"583","y":"655","zOrder":"14"},{"ID":"371","h":"71","measuredH":"70","measuredW":"20","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":18,"y":0},"p1":{"x":0.4585365853658537,"y":0.12682926829268293},"p2":{"x":0,"y":70},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"21","x":"629","y":"686","zOrder":"15"},{"ID":"372","measuredH":"32","measuredW":"52","properties":{"align":"center","color":"16776960","size":"18","text":"CSS"},"typeID":"TextInput","w":"103","x":"743","y":"779","zOrder":"16"},{"ID":"373","h":"23","measuredH":"22","measuredW":"109","properties":{"color":"2848996","curvature":"-1","direction":"top","p0":{"x":109,"y":22},"p1":{"x":0.5727916863486068,"y":-0.01048653755314126},"p2":{"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"110","x":"630","y":"756","zOrder":"17"},{"ID":"374","measuredH":"32","measuredW":"262","properties":{"align":"center","color":"16776960","size":"18","text":"Responsive Web Development"},"typeID":"TextInput","w":"171","x":"854","y":"688","zOrder":"18"},{"ID":"375","h":"75","measuredH":"74","measuredW":"64","properties":{"color":"2848996","curvature":"1","direction":"bottom","p0":{"x":64,"y":0},"p1":{"x":0.44180269694819024,"y":-0.19481902058197303},"p2":{"x":0,"y":74},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"65","x":"788","y":"703","zOrder":"19"},{"ID":"376","h":"33","measuredH":"32","measuredW":"110","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":110,"y":32},"p1":{"x":0.4077586206896551,"y":-0.16810344827586204},"p2":{"x":0,"y":6},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"111","x":"847","y":"790","zOrder":"20"},{"ID":"377","measuredH":"26","measuredW":"124","properties":{"bold":"true","size":"18","text":"Preprocessors"},"typeID":"Label","x":"917","y":"820","zOrder":"21"},{"ID":"378","h":"60","measuredH":"59","measuredW":"11","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":6,"y":0},"p1":{"x":0.45839683023468447,"y":0.1301432490094483},"p2":{"x":0,"y":59},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"12","x":"967","y":"861","zOrder":"22"},{"ID":"379","measuredH":"32","measuredW":"56","properties":{"align":"center","color":"16776960","size":"18","text":"Sass"},"typeID":"TextInput","w":"136","x":"905","y":"930","zOrder":"23"},{"ID":"380","measuredH":"32","measuredW":"55","properties":{"align":"center","color":"15658734","size":"18","text":"Less"},"typeID":"TextInput","w":"136","x":"905","y":"966","zOrder":"24"},{"ID":"381","measuredH":"32","measuredW":"66","properties":{"align":"center","color":"15658734","size":"18","text":"Stylus"},"typeID":"TextInput","w":"136","x":"905","y":"1003","zOrder":"25"},{"ID":"382","measuredH":"32","measuredW":"88","properties":{"align":"center","color":"15658734","size":"18","text":"PostCSS"},"typeID":"TextInput","w":"136","x":"905","y":"1039","zOrder":"26"},{"ID":"383","measuredH":"26","measuredW":"161","properties":{"bold":"true","size":"18","text":"Choose Framework"},"typeID":"Label","x":"684","y":"853","zOrder":"27"},{"ID":"384","measuredH":"32","measuredW":"103","properties":{"align":"center","color":"15658734","size":"18","text":"Foundation"},"typeID":"TextInput","w":"149","x":"712","y":"944","zOrder":"28"},{"ID":"385","measuredH":"32","measuredW":"92","properties":{"align":"center","color":"16776960","size":"18","text":"Bootstrap"},"typeID":"TextInput","w":"149","x":"712","y":"981","zOrder":"29"},{"ID":"386","measuredH":"32","measuredW":"146","properties":{"align":"center","color":"16770457","size":"18","text":"Materialize CSS"},"typeID":"TextInput","w":"147","x":"714","y":"1018","zOrder":"30"},{"ID":"387","h":"55","measuredH":"54","measuredW":"6","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"length":6,"x":6,"y":0},"p1":{"length":0.4893501829289195,"x":0.48850574712643674,"y":-0.028735632183908053},"p2":{"length":54.00925846556311,"x":1,"y":54},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"7","x":"769","y":"882","zOrder":"31"},{"ID":"388","h":"68","measuredH":"67","measuredW":"94","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":94,"y":0},"p1":{"x":0.5011547344110855,"y":-0.09699769053117784},"p2":{"x":0,"y":67},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"95","x":"534","y":"759","zOrder":"32"},{"ID":"389","measuredH":"32","measuredW":"101","properties":{"align":"center","color":"16776960","size":"18","text":"JavaScript"},"typeID":"TextInput","w":"115","x":"419","y":"825","zOrder":"33"},{"ID":"390","h":"61","measuredH":"60","measuredW":"57","properties":{"color":"2848996","curvature":"0","direction":"top","p0":{"x":0,"y":0},"p1":{"x":0.48019756977061306,"y":0.00306051331777826},"p2":{"x":57,"y":60},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"58","x":"383","y":"767","zOrder":"34"},{"ID":"391","measuredH":"32","measuredW":"49","properties":{"align":"center","color":"16776960","size":"18","text":"ES6"},"typeID":"TextInput","w":"115","x":"297","y":"724","zOrder":"35"},{"ID":"392","h":"44","measuredH":"43","measuredW":"128","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.5213875686686007,"y":0.07610641318437134},"p2":{"x":128,"y":43},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"129","x":"290","y":"795","zOrder":"36"},{"ID":"393","measuredH":"26","measuredW":"115","properties":{"bold":"true","size":"18","text":"Task Runners"},"typeID":"Label","x":"166","y":"780","zOrder":"37"},{"ID":"394","measuredH":"32","measuredW":"50","properties":{"align":"center","color":"16776960","size":"18","text":"gulp"},"typeID":"TextInput","w":"120","x":"46","y":"868","zOrder":"38"},{"ID":"395","measuredH":"32","measuredW":"60","properties":{"align":"center","color":"16777215","size":"18","text":"Grunt"},"typeID":"TextInput","w":"120","x":"46","y":"904","zOrder":"39"},{"ID":"396","h":"32","measuredH":"31","measuredW":"49","properties":{"color":"2848996","curvature":"-1","direction":"bottom","p0":{"x":0,"y":31},"p1":{"x":0.5592427616926503,"y":0.1307349665924276},"p2":{"x":49,"y":1},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"50","x":"107","y":"792","zOrder":"40"},{"ID":"397","h":"118","measuredH":"117","measuredW":"257","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":117},"p1":{"x":0.44088219731588824,"y":0.144210880754245},"p2":{"x":257,"y":1},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"258","x":"160","y":"845","zOrder":"41"},{"ID":"398","measuredH":"26","measuredW":"151","properties":{"bold":"true","size":"18","text":"Package Manager"},"typeID":"Label","x":"84","y":"964","zOrder":"42"},{"ID":"399","h":"46","measuredH":"45","measuredW":"4","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"length":4,"x":4,"y":0},"p1":{"length":0.42650623827571654,"x":0.42477876106194695,"y":-0.038348082595870206},"p2":{"length":45.0111097397076,"x":1,"y":45},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"5","x":"142","y":"996","zOrder":"43"},{"ID":"400","measuredH":"32","measuredW":"51","properties":{"align":"center","color":"16776960","size":"18","text":"Yarn"},"typeID":"TextInput","w":"136","x":"76","y":"1051","zOrder":"44"},{"ID":"401","measuredH":"32","measuredW":"49","properties":{"align":"center","color":"16776960","size":"18","text":"npm"},"typeID":"TextInput","w":"136","x":"76","y":"1086","zOrder":"45"},{"ID":"402","measuredH":"26","measuredW":"177","properties":{"bold":"true","size":"18","text":"Choose a Framework"},"typeID":"Label","x":"166","y":"1153","zOrder":"46"},{"ID":"403","h":"68","measuredH":"67","measuredW":"8","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":4,"y":0},"p1":{"x":0.5307907627711687,"y":0.09027291812456265},"p2":{"x":0,"y":67},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"9","x":"244","y":"1183","zOrder":"47"},{"ID":"404","measuredH":"32","measuredW":"80","properties":{"align":"center","color":"16770457","size":"18","text":"Angular"},"typeID":"TextInput","w":"136","x":"128","y":"1253","zOrder":"48"},{"ID":"405","measuredH":"32","measuredW":"64","properties":{"align":"center","color":"16770457","size":"18","text":"React"},"typeID":"TextInput","w":"136","x":"128","y":"1289","zOrder":"49"},{"ID":"406","measuredH":"32","measuredW":"63","properties":{"align":"center","color":"16770457","size":"18","text":"Vue.js"},"typeID":"TextInput","w":"136","x":"128","y":"1324","zOrder":"50"},{"ID":"407","measuredH":"32","measuredW":"69","properties":{"align":"center","color":"15658734","size":"18","text":"Preact"},"typeID":"TextInput","w":"136","x":"128","y":"1394","zOrder":"51"},{"ID":"408","measuredH":"32","measuredW":"72","properties":{"align":"center","color":"15658734","size":"18","text":"Inferno"},"typeID":"TextInput","w":"136","x":"128","y":"1428","zOrder":"52"},{"ID":"409","h":"295","measuredH":"294","measuredW":"181","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":5,"y":294},"p1":{"x":0.4941991973732214,"y":0.2053265231667274},"p2":{"x":181,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"182","x":"240","y":"854","zOrder":"53"},{"ID":"410","measuredH":"26","measuredW":"63","properties":{"bold":"true","size":"18","text":"Testing"},"typeID":"Label","x":"363","y":"928","zOrder":"54"},{"ID":"411","h":"54","measuredH":"53","measuredW":"6","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":6,"y":0},"p1":{"x":0.4761061946902655,"y":-0.0584070796460177},"p2":{"x":2,"y":53},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"7","x":"393","y":"957","zOrder":"55"},{"ID":"412","measuredH":"32","measuredW":"50","properties":{"align":"center","color":"16770457","size":"18","text":"Jest"},"typeID":"TextInput","w":"162","x":"322","y":"1016","zOrder":"56"},{"ID":"413","measuredH":"32","measuredW":"67","properties":{"align":"center","color":"16770457","size":"18","text":"Mocha"},"typeID":"TextInput","w":"162","x":"323","y":"1051","zOrder":"57"},{"ID":"414","measuredH":"32","measuredW":"82","properties":{"align":"center","color":"15658734","size":"18","text":"Jasmine"},"typeID":"TextInput","w":"162","x":"323","y":"1086","zOrder":"58"},{"ID":"415","h":"68","measuredH":"67","measuredW":"30","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":0,"y":67},"p1":{"x":0.5267395745703641,"y":0.050594880423026095},"p2":{"x":30,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"31","x":"407","y":"860","zOrder":"59"},{"ID":"416","measuredH":"26","measuredW":"203","properties":{"bold":"true","size":"18","text":"Module Loader/Bundler"},"typeID":"Label","x":"407","y":"1179","zOrder":"60"},{"ID":"417","measuredH":"32","measuredW":"87","properties":{"align":"center","color":"16776960","size":"18","text":"webpack"},"typeID":"TextInput","w":"180","x":"391","y":"1282","zOrder":"61"},{"ID":"418","measuredH":"32","measuredW":"158","properties":{"align":"center","color":"16777215","size":"18","text":"RequireJS / AMD"},"typeID":"TextInput","w":"180","x":"391","y":"1352","zOrder":"62"},{"ID":"419","measuredH":"32","measuredW":"101","properties":{"align":"center","color":"16777215","size":"18","text":"Browserify"},"typeID":"TextInput","w":"180","x":"391","y":"1387","zOrder":"63"},{"ID":"420","h":"60","measuredH":"59","measuredW":"8","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":8,"y":0},"p1":{"x":0.4313335228888257,"y":-0.07477964174011942},"p2":{"x":2,"y":59},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"9","x":"462","y":"1210","zOrder":"64"},{"ID":"421","measuredH":"32","measuredW":"116","properties":{"align":"center","color":"16770457","size":"18","text":"Semantic UI"},"typeID":"TextInput","w":"150","x":"713","y":"1054","zOrder":"65"},{"ID":"422","h":"314","measuredH":"313","measuredW":"42","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":12,"y":313},"p1":{"x":0.40467624066127833,"y":-0.11136138941832376},"p2":{"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"43","x":"475","y":"859","zOrder":"66"},{"ID":"423","h":"38","measuredH":"37","measuredW":"2","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":1,"y":0},"p1":{"x":0.5090497737556562,"y":0.05995475113122172},"p2":{"x":0,"y":37},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"3","x":"778","y":"811","zOrder":"67"},{"ID":"424","h":"918","measuredH":"917","measuredW":"63","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"x":32,"y":0},"p1":{"x":0.4885713623052957,"y":0.04938508096555646},"p2":{"x":0,"y":917},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"64","x":"595","y":"758","zOrder":"68"},{"ID":"425","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"flag-checkered","size":"large"}},"typeID":"Icon","x":"560","y":"1687","zOrder":"69"},{"ID":"427","measuredH":"32","measuredW":"97","properties":{"align":"center","color":"15658734","size":"18","text":"Ember JS"},"typeID":"TextInput","w":"136","x":"128","y":"1359","zOrder":"70"},{"ID":"428","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"609","y":"547","zOrder":"71"},{"ID":"429","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"605","y":"731","zOrder":"72"},{"ID":"434","measuredH":"48","measuredW":"48","properties":{"color":"2848996","icon":{"ID":"circle","size":"large"}},"typeID":"Icon","x":"620","y":"1337","zOrder":"73"},{"ID":"435","measuredH":"32","measuredW":"51","properties":{"align":"center","color":"15658734","size":"18","text":"SVG"},"typeID":"TextInput","w":"103","x":"760","y":"1464","zOrder":"74"},{"ID":"436","h":"115","measuredH":"114","measuredW":"109","properties":{"color":"2848996","curvature":"1","direction":"top","p0":{"x":109,"y":114},"p1":{"x":0.4780721148048398,"y":0.07798367970414438},"p2":{"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"110","x":"644","y":"1363","zOrder":"75"},{"ID":"437","measuredH":"32","measuredW":"38","properties":{"align":"center","color":"15658734","size":"18","text":"D3"},"typeID":"TextInput","w":"103","x":"907","y":"1462","zOrder":"76"},{"ID":"438","h":"3","measuredH":"2","measuredW":"39","properties":{"color":"2848996","curvature":"1","direction":"bottom","p0":{"length":39.01281840626232,"x":39,"y":1},"p1":{"length":0.5728876708569789,"x":0.5727916863486068,"y":-0.010486537553141256},"p2":{"length":2,"x":0,"y":2},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"40","x":"864","y":"1476","zOrder":"77"},{"ID":"439","h":"213","measuredH":"212","measuredW":"56","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":55,"y":0},"p1":{"x":0.36199799755256423,"y":-0.25642451885638},"p2":{"x":56,"y":212},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"57","x":"72","y":"1304","zOrder":"78"},{"ID":"440","measuredH":"32","measuredW":"47","properties":{"align":"center","color":"16770457","size":"18","text":"Flux"},"typeID":"TextInput","w":"136","x":"84","y":"1526","zOrder":"79"},{"ID":"441","measuredH":"32","measuredW":"67","properties":{"align":"center","color":"16770457","size":"18","text":"Redux"},"typeID":"TextInput","w":"136","x":"84","y":"1561","zOrder":"80"},{"ID":"442","h":"70","measuredH":"69","measuredW":"46","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.4565634420389148,"y":0.0865990682378734},"p2":{"x":46,"y":69},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"47","x":"508","y":"860","zOrder":"81"},{"ID":"443","measuredH":"32","measuredW":"104","properties":{"align":"center","color":"16776960","size":"18","text":"TypeScript"},"typeID":"TextInput","w":"105","x":"528","y":"936","zOrder":"82"},{"ID":"444","measuredH":"32","measuredW":"146","properties":{"align":"center","color":"15658734","size":"18","text":"Design Patterns"},"typeID":"TextInput","w":"177","x":"905","y":"1503","zOrder":"83"},{"ID":"445","measuredH":"32","measuredW":"67","properties":{"align":"center","color":"15658734","size":"18","text":"Regex"},"typeID":"TextInput","w":"177","x":"905","y":"1538","zOrder":"84"},{"ID":"446","measuredH":"32","measuredW":"52","properties":{"align":"center","color":"16776960","size":"18","text":"CSS"},"typeID":"TextInput","w":"103","x":"760","y":"1427","zOrder":"85"},{"ID":"447","h":"90","measuredH":"89","measuredW":"109","properties":{"color":"2848996","curvature":"1","direction":"top","p0":{"x":109,"y":89},"p1":{"x":0.37703262296737705,"y":0.03262296737703262},"p2":{"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"110","x":"645","y":"1349","zOrder":"86"},{"ID":"448","h":"91","measuredH":"90","measuredW":"104","properties":{"color":"2848996","curvature":"1","direction":"bottom","p0":{"length":104.00480758118827,"x":104,"y":1},"p1":{"length":0.5709985878340978,"x":0.5207877461706784,"y":-0.2341356673960613},"p2":{"length":90,"x":0,"y":90},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"105","x":"813","y":"1332","zOrder":"87"},{"ID":"449","measuredH":"32","measuredW":"76","properties":{"align":"center","color":"15658734","size":"18","text":"Flexbox"},"typeID":"TextInput","w":"103","x":"925","y":"1350","zOrder":"88"},{"ID":"450","measuredH":"32","measuredW":"94","properties":{"align":"center","color":"15658734","size":"18","text":"Gradients"},"typeID":"TextInput","w":"103","x":"1032","y":"1350","zOrder":"89"},{"ID":"451","measuredH":"32","measuredW":"152","properties":{"align":"center","color":"16776960","size":"18","text":"Dive Deep CSS3"},"typeID":"TextInput","w":"316","x":"926","y":"1316","zOrder":"90"},{"ID":"452","measuredH":"32","measuredW":"69","properties":{"align":"center","color":"15658734","size":"18","text":"Rotate"},"typeID":"TextInput","w":"103","x":"925","y":"1385","zOrder":"91"},{"ID":"453","measuredH":"32","measuredW":"106","properties":{"align":"center","color":"15658734","size":"18","text":"Transforms"},"typeID":"TextInput","w":"103","x":"1032","y":"1385","zOrder":"92"},{"ID":"454","measuredH":"32","measuredW":"58","properties":{"align":"center","color":"15658734","size":"18","text":"Grids"},"typeID":"TextInput","w":"103","x":"1139","y":"1350","zOrder":"93"},{"ID":"455","measuredH":"32","measuredW":"58","properties":{"align":"center","color":"15658734","size":"18","text":"Skew"},"typeID":"TextInput","w":"103","x":"1139","y":"1385","zOrder":"94"},{"ID":"456","measuredH":"32","measuredW":"61","properties":{"align":"center","color":"15658734","size":"18","text":"Scale"},"typeID":"TextInput","w":"103","x":"925","y":"1419","zOrder":"95"},{"ID":"457","measuredH":"32","measuredW":"103","properties":{"align":"center","color":"15658734","size":"18","text":"Transitions"},"typeID":"TextInput","w":"103","x":"1032","y":"1419","zOrder":"96"},{"ID":"458","measuredH":"32","measuredW":"48","properties":{"align":"center","color":"15658734","size":"18","text":"..etc"},"typeID":"TextInput","w":"103","x":"1139","y":"1419","zOrder":"97"},{"ID":"459","measuredH":"32","measuredW":"101","properties":{"align":"center","color":"16776960","size":"18","text":"JavaScript"},"typeID":"TextInput","w":"103","x":"760","y":"1500","zOrder":"98"},{"ID":"460","h":"150","measuredH":"149","measuredW":"103","properties":{"color":"2848996","curvature":"1","direction":"top","p0":{"x":103,"y":149},"p1":{"x":0.39619018591892713,"y":0.1556537640963121},"p2":{"x":0,"y":0},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"104","x":"649","y":"1368","zOrder":"99"},{"ID":"461","h":"4","measuredH":"3","measuredW":"34","properties":{"color":"2848996","curvature":"-1","direction":"top","p0":{"length":34.132096331752024,"x":34,"y":3},"p1":{"length":0.5728876708569789,"x":0.5727916863486068,"y":-0.010486537553141256},"p2":{"length":1,"x":0,"y":1},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"35","x":"863","y":"1516","zOrder":"100"},{"ID":"462","measuredH":"32","measuredW":"111","properties":{"align":"center","color":"16776960","size":"18","text":"npm scripts"},"typeID":"TextInput","w":"120","x":"46","y":"834","zOrder":"101"},{"ID":"463","h":"160","measuredH":"159","measuredW":"55","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"x":55,"y":0},"p1":{"x":0.547975227880257,"y":-0.1968819007454881},"p2":{"x":17,"y":159},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"56","x":"775","y":"1265","zOrder":"102"},{"ID":"464","measuredH":"26","measuredW":"124","properties":{"bold":"true","size":"18","text":"Methodologies"},"typeID":"Label","x":"788","y":"1235","zOrder":"103"},{"ID":"465","h":"32","measuredH":"31","measuredW":"83","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"true","p0":{"x":83,"y":1},"p1":{"x":0.4532032353318783,"y":-0.07947104891513673},"p2":{"x":0,"y":31},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"84","x":"858","y":"1198","zOrder":"104"},{"ID":"466","measuredH":"32","measuredW":"80","properties":{"align":"center","color":"15658734","size":"18","text":"OOCSS"},"typeID":"TextInput","w":"159","x":"958","y":"1177","zOrder":"105"},{"ID":"467","measuredH":"32","measuredW":"51","properties":{"align":"center","color":"16776960","size":"18","text":"BEM"},"typeID":"TextInput","w":"159","x":"958","y":"1140","zOrder":"106"},{"ID":"468","measuredH":"32","measuredW":"89","properties":{"align":"center","color":"15658734","size":"18","text":"SMACSS"},"typeID":"TextInput","w":"159","x":"958","y":"1213","zOrder":"107"},{"ID":"469","measuredH":"32","measuredW":"95","properties":{"align":"center","color":"15658734","size":"18","text":"SUITCSS"},"typeID":"TextInput","w":"159","x":"958","y":"1105","zOrder":"108"},{"ID":"470","measuredH":"32","measuredW":"149","properties":{"align":"center","color":"15658734","size":"18","text":"Systematic CSS"},"typeID":"TextInput","w":"159","x":"958","y":"1247","zOrder":"109"},{"ID":"471","measuredH":"32","measuredW":"50","properties":{"align":"center","color":"15658734","size":"18","text":"Flow"},"typeID":"TextInput","w":"105","x":"528","y":"971","zOrder":"110"},{"ID":"472","h":"58","measuredH":"57","measuredW":"72","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":1,"y":0},"p1":{"x":0.4378769601930036,"y":-0.2822677925211098},"p2":{"x":72,"y":57},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"73","x":"831","y":"1533","zOrder":"111"},{"ID":"473","measuredH":"32","measuredW":"188","properties":{"align":"center","color":"15658734","size":"18","text":"GOF Design Patterns"},"typeID":"TextInput","w":"316","x":"905","y":"1576","zOrder":"112"},{"ID":"474","measuredH":"32","measuredW":"294","properties":{"align":"center","borderStyle":"rectangle","color":"15658734","size":"18","text":"Learn different testing techniques"},"typeID":"TextInput","w":"316","x":"905","y":"1612","zOrder":"113"},{"ID":"475","h":"95","measuredH":"94","measuredW":"96","properties":{"color":"2848996","curvature":"-1","direction":"top","leftArrow":"false","p0":{"x":0,"y":0},"p1":{"x":0.5342344338577443,"y":-0.24772878351429203},"p2":{"x":96,"y":94},"rightArrow":"true","shape":"bezier"},"typeID":"Arrow","w":"97","x":"805","y":"1531","zOrder":"114"},{"ID":"476","measuredH":"32","measuredW":"58","properties":{"align":"center","color":"16770457","size":"18","text":"rollup"},"typeID":"TextInput","w":"180","x":"391","y":"1317","zOrder":"115"}]},"measuredH":"1735","measuredW":"1242","mockupH":"1497","mockupW":"1196","version":"1.0"}} \ No newline at end of file diff --git a/project-files/intro-map.json b/project-files/intro-map.json deleted file mode 100644 index ec05172eac96..000000000000 --- a/project-files/intro-map.json +++ /dev/null @@ -1 +0,0 @@ -{"mockup":{"controls":{"control":[{"ID":"477","measuredH":"40","measuredW":"347","properties":{"bold":"true","size":"32","text":"Web Developer in 2017"},"typeID":"Label","x":"441","y":"74","zOrder":"0"},{"ID":"478","h":"128","measuredH":"127","measuredW":"54","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.5202613499660683,"x":0.4809160305343512,"y":0.198473282442748},"p2":{"length":136.12494260788506,"x":49,"y":127},"shape":"bezier"},"typeID":"Arrow","w":"55","x":"633","y":"230","zOrder":"1"},{"ID":"479","h":"130","measuredH":"129","measuredW":"131","properties":{"color":"2848996","curvature":"1","direction":"bottom","leftArrow":"false","p0":{"length":131,"x":131,"y":0},"p1":{"length":0.6087375480965977,"x":0.5684088130944218,"y":-0.21788259145523384},"p2":{"length":129.00387591076478,"x":1,"y":129},"shape":"bezier"},"typeID":"Arrow","w":"132","x":"468","y":"229","zOrder":"2"},{"ID":"480","measuredH":"32","measuredW":"93","properties":{"align":"center","color":"16767334","size":"18","text":"Front-end"},"typeID":"TextInput","w":"132","x":"391","y":"367","zOrder":"3"},{"ID":"481","measuredH":"28","measuredW":"167","properties":{"bold":"true","size":"20","text":"Choose your path"},"typeID":"Label","x":"539","y":"189","zOrder":"4"},{"ID":"482","measuredH":"32","measuredW":"179","properties":{"align":"center","color":"16767334","size":"18","text":"Git - Version Control"},"typeID":"TextInput","w":"258","x":"68","y":"85","zOrder":"5"},{"ID":"483","measuredH":"32","measuredW":"50","properties":{"align":"center","color":"16767334","size":"18","text":"SSH"},"typeID":"TextInput","w":"259","x":"67","y":"120","zOrder":"6"},{"ID":"484","measuredH":"32","measuredW":"209","properties":{"align":"center","color":"16767334","size":"18","text":"HTTP/HTTPS and APIs"},"typeID":"TextInput","w":"259","x":"67","y":"157","zOrder":"7"},{"ID":"485","measuredH":"25","measuredW":"175","properties":{"bold":"true","size":"17","text":"Required for any path"},"typeID":"Label","x":"67","y":"45","zOrder":"8"},{"ID":"486","measuredH":"32","measuredW":"192","properties":{"align":"center","color":"16767334","size":"18","text":"Basic Terminal Usage"},"typeID":"TextInput","w":"259","x":"67","y":"195","zOrder":"9"},{"ID":"487","measuredH":"25","measuredW":"69","properties":{"bold":"true","size":"17","text":"Legends"},"typeID":"Label","x":"956","y":"41","zOrder":"10"},{"ID":"488","measuredH":"32","measuredW":"234","properties":{"align":"center","color":"16776960","size":"18","text":"Personal Recommendation!"},"typeID":"TextInput","w":"240","x":"956","y":"78","zOrder":"11"},{"ID":"489","measuredH":"32","measuredW":"109","properties":{"align":"center","color":"15658734","size":"18","text":"Possibilities"},"typeID":"TextInput","w":"240","x":"956","y":"114","zOrder":"12"},{"ID":"490","measuredH":"32","measuredW":"87","properties":{"align":"center","color":"16770457","size":"18","text":"Pick any!"},"typeID":"TextInput","w":"240","x":"956","y":"150","zOrder":"13"},{"ID":"491","h":"47","measuredH":"46","measuredW":"0","properties":{"color":"6710886","curvature":"0","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.5,"x":0.5,"y":0},"p2":{"length":46,"x":0,"y":46},"rightArrow":"false","shape":"bezier"},"typeID":"Arrow","w":"1","x":"614","y":"135","zOrder":"14"},{"ID":"492","measuredH":"32","measuredW":"92","properties":{"align":"center","color":"16767334","size":"18","text":"Back-end"},"typeID":"TextInput","w":"121","x":"599","y":"368","zOrder":"15"},{"ID":"493","h":"70","measuredH":"69","measuredW":"0","properties":{"color":"2848996","curvature":"0","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.5621697290198284,"x":0.5621504039776257,"y":0.004661280298321849},"p2":{"length":69,"x":0,"y":69},"rightArrow":"false","shape":"bezier","stroke":"dotted"},"typeID":"Arrow","w":"1","x":"459","y":"407","zOrder":"16"},{"ID":"494","h":"12","measuredH":"11","measuredW":"122","properties":{"color":"2848996","curvature":"-1","direction":"bottom","leftArrow":"false","p0":{"length":11,"x":0,"y":11},"p1":{"length":0.4574898035968877,"x":0.45357350377687367,"y":0.059732713538640264},"p2":{"length":122.06555615733704,"x":122,"y":4},"shape":"bezier","stroke":"solid"},"typeID":"Arrow","w":"123","x":"731","y":"373","zOrder":"17"},{"ID":"495","measuredH":"32","measuredW":"81","properties":{"align":"center","color":"16767334","size":"18","text":"DevOps"},"typeID":"TextInput","w":"112","x":"866","y":"361","zOrder":"18"},{"ID":"496","h":"70","measuredH":"69","measuredW":"0","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.46105410579324535,"x":0.4608695652173913,"y":0.01304347826086956},"p2":{"length":69,"x":0,"y":69},"rightArrow":"false","shape":"bezier","stroke":"dotted"},"typeID":"Arrow","w":"1","x":"649","y":"410","zOrder":"19"},{"ID":"497","h":"77","measuredH":"76","measuredW":"0","properties":{"color":"2848996","curvature":"1","direction":"top","leftArrow":"false","p0":{"length":0,"x":0,"y":0},"p1":{"length":0.4539180376844135,"x":0.4537465672812867,"y":0.01247548058061985},"p2":{"length":76,"x":0,"y":76},"rightArrow":"false","shape":"bezier","stroke":"dotted"},"typeID":"Arrow","w":"1","x":"917","y":"403","zOrder":"20"},{"ID":"498","measuredH":"32","measuredW":"166","properties":{"align":"center","color":"16767334","size":"18","text":"Learn to Research"},"typeID":"TextInput","w":"258","x":"68","y":"232","zOrder":"21"},{"ID":"499","h":"121","measuredH":"140","measuredW":"200","properties":{"color":"15658734","text":" \nCreate a profile. Explore relevant open source projects. Make a habit of looking under the hood of projects you like. Create and contribute to open source projects."},"typeID":"TextArea","w":"258","x":"68","y":"366","zOrder":"22"},{"ID":"500","measuredH":"32","measuredW":"70","properties":{"align":"center","borderStyle":"rectangle","color":"16767334","size":"18","text":"GitHub"},"typeID":"TextInput","w":"258","x":"68","y":"341","zOrder":"23"},{"ID":"501","measuredH":"32","measuredW":"255","properties":{"align":"center","color":"16767334","size":"18","text":"Data Structures & Algorithms"},"typeID":"TextInput","w":"258","x":"68","y":"269","zOrder":"24"},{"ID":"502","measuredH":"32","measuredW":"188","properties":{"align":"center","color":"16767334","size":"18","text":"Character Encodings"},"typeID":"TextInput","w":"258","x":"68","y":"305","zOrder":"25"},{"ID":"504","measuredH":"32","measuredW":"32","properties":{"color":"2848996","icon":{"ID":"circle","size":"medium"}},"typeID":"Icon","x":"956","y":"194","zOrder":"26"},{"ID":"505","measuredH":"28","measuredW":"146","properties":{"size":"20","text":"Build Something"},"typeID":"Label","x":"994","y":"196","zOrder":"27"}]},"measuredH":"487","measuredW":"1196","mockupH":"446","mockupW":"1129","version":"1.0"}} \ No newline at end of file diff --git a/public/authors/danielgruesso.jpeg b/public/authors/danielgruesso.jpeg new file mode 100644 index 000000000000..038f8d4d99e6 Binary files /dev/null and b/public/authors/danielgruesso.jpeg differ diff --git a/public/authors/dmytrobol.png b/public/authors/dmytrobol.png new file mode 100644 index 000000000000..4ff2ccb336e4 Binary files /dev/null and b/public/authors/dmytrobol.png differ diff --git a/public/authors/ebrahimbharmal007.png b/public/authors/ebrahimbharmal007.png new file mode 100644 index 000000000000..31cf45d5d9fc Binary files /dev/null and b/public/authors/ebrahimbharmal007.png differ diff --git a/public/authors/ekene-eze.jpg b/public/authors/ekene-eze.jpg new file mode 100644 index 000000000000..b04cf7127a6a Binary files /dev/null and b/public/authors/ekene-eze.jpg differ diff --git a/public/authors/fernando.jpeg b/public/authors/fernando.jpeg new file mode 100644 index 000000000000..fe5b9471c85b Binary files /dev/null and b/public/authors/fernando.jpeg differ diff --git a/public/authors/jesse.png b/public/authors/jesse.png new file mode 100644 index 000000000000..2cc1e31d9bd6 Binary files /dev/null and b/public/authors/jesse.png differ diff --git a/public/authors/kamran.jpeg b/public/authors/kamran.jpeg new file mode 100644 index 000000000000..7c12b2df911c Binary files /dev/null and b/public/authors/kamran.jpeg differ diff --git a/public/authors/kamranahmedse.jpeg b/public/authors/kamranahmedse.jpeg new file mode 100644 index 000000000000..5c743b583491 Binary files /dev/null and b/public/authors/kamranahmedse.jpeg differ diff --git a/public/authors/lesovsky.jpeg b/public/authors/lesovsky.jpeg new file mode 100644 index 000000000000..c62c8b4586b7 Binary files /dev/null and b/public/authors/lesovsky.jpeg differ diff --git a/public/authors/peter-thaleikis.png b/public/authors/peter-thaleikis.png new file mode 100644 index 000000000000..fbefc2962cd3 Binary files /dev/null and b/public/authors/peter-thaleikis.png differ diff --git a/public/authors/spekulatius.jpg b/public/authors/spekulatius.jpg new file mode 100644 index 000000000000..9061fe242d09 Binary files /dev/null and b/public/authors/spekulatius.jpg differ diff --git a/public/authors/william-imoh.jpg b/public/authors/william-imoh.jpg new file mode 100644 index 000000000000..b2a9a9ff8a44 Binary files /dev/null and b/public/authors/william-imoh.jpg differ diff --git a/public/best-practices/api-security.png b/public/best-practices/api-security.png new file mode 100644 index 000000000000..00669b03ba12 Binary files /dev/null and b/public/best-practices/api-security.png differ diff --git a/public/best-practices/aws.png b/public/best-practices/aws.png new file mode 100644 index 000000000000..61bfbe75760b Binary files /dev/null and b/public/best-practices/aws.png differ diff --git a/public/best-practices/backend-performance.png b/public/best-practices/backend-performance.png new file mode 100644 index 000000000000..7364471a1699 Binary files /dev/null and b/public/best-practices/backend-performance.png differ diff --git a/public/best-practices/frontend-performance.png b/public/best-practices/frontend-performance.png new file mode 100644 index 000000000000..e6eccf4b3b38 Binary files /dev/null and b/public/best-practices/frontend-performance.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 000000000000..3dca3a22c154 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/fonts/BalsamiqSans-Regular.ttf b/public/fonts/BalsamiqSans-Regular.ttf new file mode 100644 index 000000000000..4fc9f82e920c Binary files /dev/null and b/public/fonts/BalsamiqSans-Regular.ttf differ diff --git a/public/fonts/balsamiq.woff2 b/public/fonts/balsamiq.woff2 new file mode 100644 index 000000000000..f33cdb733db2 Binary files /dev/null and b/public/fonts/balsamiq.woff2 differ diff --git a/public/img/brand-square.png b/public/img/brand-square.png new file mode 100644 index 000000000000..e4ec894712c5 Binary files /dev/null and b/public/img/brand-square.png differ diff --git a/public/img/brand.png b/public/img/brand.png new file mode 100644 index 000000000000..8ccbb4fd8b8b Binary files /dev/null and b/public/img/brand.png differ diff --git a/public/img/brand.svg b/public/img/brand.svg new file mode 100644 index 000000000000..3e1321787246 --- /dev/null +++ b/public/img/brand.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/img/cursors/add.svg b/public/img/cursors/add.svg new file mode 100644 index 000000000000..64f4b753991f --- /dev/null +++ b/public/img/cursors/add.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/img/cursors/remove.svg b/public/img/cursors/remove.svg new file mode 100644 index 000000000000..78c1c775fdf7 --- /dev/null +++ b/public/img/cursors/remove.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/img/default-avatar.png b/public/img/default-avatar.png new file mode 100644 index 000000000000..8bf3235fd06f Binary files /dev/null and b/public/img/default-avatar.png differ diff --git a/public/img/features/in-progress.png b/public/img/features/in-progress.png new file mode 100644 index 000000000000..a14373714c38 Binary files /dev/null and b/public/img/features/in-progress.png differ diff --git a/public/img/gifs/bot.gif b/public/img/gifs/bot.gif new file mode 100644 index 000000000000..b2a7b834faa1 Binary files /dev/null and b/public/img/gifs/bot.gif differ diff --git a/public/img/gifs/party-popper.gif b/public/img/gifs/party-popper.gif new file mode 100644 index 000000000000..a95fe2e4f583 Binary files /dev/null and b/public/img/gifs/party-popper.gif differ diff --git a/public/img/gifs/rocket.gif b/public/img/gifs/rocket.gif new file mode 100644 index 000000000000..d9fdba8d3e32 Binary files /dev/null and b/public/img/gifs/rocket.gif differ diff --git a/public/img/gifs/star.gif b/public/img/gifs/star.gif new file mode 100644 index 000000000000..8ba6cd590d9f Binary files /dev/null and b/public/img/gifs/star.gif differ diff --git a/public/img/gifs/starstruck.gif b/public/img/gifs/starstruck.gif new file mode 100644 index 000000000000..53878edc7946 Binary files /dev/null and b/public/img/gifs/starstruck.gif differ diff --git a/public/img/gifs/sunglasses.gif b/public/img/gifs/sunglasses.gif new file mode 100644 index 000000000000..092280cb6201 Binary files /dev/null and b/public/img/gifs/sunglasses.gif differ diff --git a/public/img/gifs/wave.gif b/public/img/gifs/wave.gif new file mode 100644 index 000000000000..4066643d63d0 Binary files /dev/null and b/public/img/gifs/wave.gif differ diff --git a/public/img/graph.svg b/public/img/graph.svg new file mode 100644 index 000000000000..51f61aa1cacb --- /dev/null +++ b/public/img/graph.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/img/hackernews.svg b/public/img/hackernews.svg new file mode 100644 index 000000000000..ae8cacccacb4 --- /dev/null +++ b/public/img/hackernews.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/img/icons8-wand.gif b/public/img/icons8-wand.gif new file mode 100644 index 000000000000..53222141c176 Binary files /dev/null and b/public/img/icons8-wand.gif differ diff --git a/public/img/og-img.png b/public/img/og-img.png new file mode 100644 index 000000000000..aadb393ca9be Binary files /dev/null and b/public/img/og-img.png differ diff --git a/public/img/partners/ambassador-graphic-1.png b/public/img/partners/ambassador-graphic-1.png new file mode 100644 index 000000000000..71ef0ebfd5d0 Binary files /dev/null and b/public/img/partners/ambassador-graphic-1.png differ diff --git a/public/img/partners/ambassador-graphic-2.png b/public/img/partners/ambassador-graphic-2.png new file mode 100644 index 000000000000..17bd629e687e Binary files /dev/null and b/public/img/partners/ambassador-graphic-2.png differ diff --git a/public/img/partners/apollo-event.jpg b/public/img/partners/apollo-event.jpg new file mode 100644 index 000000000000..a63d913f9302 Binary files /dev/null and b/public/img/partners/apollo-event.jpg differ diff --git a/public/img/partners/apollo-learning.jpg b/public/img/partners/apollo-learning.jpg new file mode 100644 index 000000000000..233e4d1a265b Binary files /dev/null and b/public/img/partners/apollo-learning.jpg differ diff --git a/public/img/partners/apollo-workshop.png b/public/img/partners/apollo-workshop.png new file mode 100644 index 000000000000..beecb62ef5a0 Binary files /dev/null and b/public/img/partners/apollo-workshop.png differ diff --git a/public/img/partners/graphql-summit.png b/public/img/partners/graphql-summit.png new file mode 100644 index 000000000000..d58efa2177b0 Binary files /dev/null and b/public/img/partners/graphql-summit.png differ diff --git a/public/img/partners/honeycomb-ebook.jpg b/public/img/partners/honeycomb-ebook.jpg new file mode 100644 index 000000000000..525590aea70c Binary files /dev/null and b/public/img/partners/honeycomb-ebook.jpg differ diff --git a/public/img/partners/nginx.png b/public/img/partners/nginx.png new file mode 100644 index 000000000000..87cae3e40405 Binary files /dev/null and b/public/img/partners/nginx.png differ diff --git a/public/img/partners/spring-tile.png b/public/img/partners/spring-tile.png new file mode 100644 index 000000000000..8802e85a75cc Binary files /dev/null and b/public/img/partners/spring-tile.png differ diff --git a/public/img/partners/zilliz.png b/public/img/partners/zilliz.png new file mode 100644 index 000000000000..e2142261b0c0 Binary files /dev/null and b/public/img/partners/zilliz.png differ diff --git a/public/img/party.gif b/public/img/party.gif new file mode 100644 index 000000000000..e9af04534236 Binary files /dev/null and b/public/img/party.gif differ diff --git a/public/img/reddit.svg b/public/img/reddit.svg new file mode 100644 index 000000000000..062a4936b988 --- /dev/null +++ b/public/img/reddit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/roadmap-editor.jpeg b/public/img/roadmap-editor.jpeg new file mode 100644 index 000000000000..f0ae1ba37f83 Binary files /dev/null and b/public/img/roadmap-editor.jpeg differ diff --git a/public/img/system-design.png b/public/img/system-design.png new file mode 100644 index 000000000000..7839665d3fb6 Binary files /dev/null and b/public/img/system-design.png differ diff --git a/public/img/team-promo/contact.png b/public/img/team-promo/contact.png new file mode 100644 index 000000000000..ba84d37dc02f Binary files /dev/null and b/public/img/team-promo/contact.png differ diff --git a/public/img/team-promo/documentation.png b/public/img/team-promo/documentation.png new file mode 100644 index 000000000000..71399990a7a0 Binary files /dev/null and b/public/img/team-promo/documentation.png differ diff --git a/public/img/team-promo/growth-plans.png b/public/img/team-promo/growth-plans.png new file mode 100644 index 000000000000..3043324adec8 Binary files /dev/null and b/public/img/team-promo/growth-plans.png differ diff --git a/public/img/team-promo/hero-img.png b/public/img/team-promo/hero-img.png new file mode 100644 index 000000000000..18c0ebe6f536 Binary files /dev/null and b/public/img/team-promo/hero-img.png differ diff --git a/public/img/team-promo/hero.png b/public/img/team-promo/hero.png new file mode 100644 index 000000000000..8b525e90c9f2 Binary files /dev/null and b/public/img/team-promo/hero.png differ diff --git a/public/img/team-promo/invite-members.png b/public/img/team-promo/invite-members.png new file mode 100644 index 000000000000..42af447c1912 Binary files /dev/null and b/public/img/team-promo/invite-members.png differ diff --git a/public/img/team-promo/many-roadmaps.png b/public/img/team-promo/many-roadmaps.png new file mode 100644 index 000000000000..b5bffc37464e Binary files /dev/null and b/public/img/team-promo/many-roadmaps.png differ diff --git a/public/img/team-promo/onboarding.png b/public/img/team-promo/onboarding.png new file mode 100644 index 000000000000..056d988aa75d Binary files /dev/null and b/public/img/team-promo/onboarding.png differ diff --git a/public/img/team-promo/our-roadmaps.png b/public/img/team-promo/our-roadmaps.png new file mode 100644 index 000000000000..aaf748377daa Binary files /dev/null and b/public/img/team-promo/our-roadmaps.png differ diff --git a/public/img/team-promo/progress-tracking.png b/public/img/team-promo/progress-tracking.png new file mode 100644 index 000000000000..288b9581133c Binary files /dev/null and b/public/img/team-promo/progress-tracking.png differ diff --git a/public/img/team-promo/roadmap-editor.png b/public/img/team-promo/roadmap-editor.png new file mode 100644 index 000000000000..0da30037c9a8 Binary files /dev/null and b/public/img/team-promo/roadmap-editor.png differ diff --git a/public/img/team-promo/sharing-settings.png b/public/img/team-promo/sharing-settings.png new file mode 100644 index 000000000000..093bbd1edfd8 Binary files /dev/null and b/public/img/team-promo/sharing-settings.png differ diff --git a/public/img/team-promo/skill-gap.png b/public/img/team-promo/skill-gap.png new file mode 100644 index 000000000000..96e344989e38 Binary files /dev/null and b/public/img/team-promo/skill-gap.png differ diff --git a/public/img/team-promo/team-dashboard.png b/public/img/team-promo/team-dashboard.png new file mode 100644 index 000000000000..04144c69182a Binary files /dev/null and b/public/img/team-promo/team-dashboard.png differ diff --git a/public/img/team-promo/team-insights.png b/public/img/team-promo/team-insights.png new file mode 100644 index 000000000000..17e8169e62fe Binary files /dev/null and b/public/img/team-promo/team-insights.png differ diff --git a/public/img/team-promo/update-progress.png b/public/img/team-promo/update-progress.png new file mode 100644 index 000000000000..84c1864de2e8 Binary files /dev/null and b/public/img/team-promo/update-progress.png differ diff --git a/public/img/tns-sm.png b/public/img/tns-sm.png new file mode 100644 index 000000000000..830b3758a1df Binary files /dev/null and b/public/img/tns-sm.png differ diff --git a/public/img/tns.png b/public/img/tns.png new file mode 100644 index 000000000000..5e423d0fb109 Binary files /dev/null and b/public/img/tns.png differ diff --git a/public/img/twitter-img.png b/public/img/twitter-img.png new file mode 100644 index 000000000000..b950fe7d98c6 Binary files /dev/null and b/public/img/twitter-img.png differ diff --git a/public/manifest/apple-touch-icon.png b/public/manifest/apple-touch-icon.png new file mode 100644 index 000000000000..1177db3a32f4 Binary files /dev/null and b/public/manifest/apple-touch-icon.png differ diff --git a/public/manifest/favicon.ico b/public/manifest/favicon.ico new file mode 100644 index 000000000000..3dca3a22c154 Binary files /dev/null and b/public/manifest/favicon.ico differ diff --git a/public/manifest/icon152.png b/public/manifest/icon152.png new file mode 100644 index 000000000000..3fa1a99a7334 Binary files /dev/null and b/public/manifest/icon152.png differ diff --git a/public/manifest/icon16.png b/public/manifest/icon16.png new file mode 100644 index 000000000000..043b2b27527b Binary files /dev/null and b/public/manifest/icon16.png differ diff --git a/public/manifest/icon196.png b/public/manifest/icon196.png new file mode 100644 index 000000000000..3369c0729335 Binary files /dev/null and b/public/manifest/icon196.png differ diff --git a/public/manifest/icon32.png b/public/manifest/icon32.png new file mode 100644 index 000000000000..06a7807ccb76 Binary files /dev/null and b/public/manifest/icon32.png differ diff --git a/public/manifest/manifest.json b/public/manifest/manifest.json new file mode 100644 index 000000000000..815f086622cd --- /dev/null +++ b/public/manifest/manifest.json @@ -0,0 +1,27 @@ +{ + "dir": "ltr", + "lang": "en", + "name": "Roadmap", + "scope": "/", + "display": "standalone", + "start_url": "https://roadmap.sh/", + "short_name": "Roadmap", + "theme_color": "#EDD07E", + "description": "Roadmaps to becoming a Modern Developer – roadmap.sh", + "orientation": "any", + "background_color": "#101010", + "related_applications": [], + "prefer_related_applications": false, + "icons": [ + { + "src": "/manifest/icon152.png", + "sizes": "152x152", + "type": "image/png" + }, + { + "src": "/manifest/icon196.png", + "sizes": "196x196", + "type": "image/png" + } + ] +} diff --git a/public/og-images/ai-tutor.png b/public/og-images/ai-tutor.png new file mode 100644 index 000000000000..0172cd7080c9 Binary files /dev/null and b/public/og-images/ai-tutor.png differ diff --git a/public/og-images/best-practices/api-security.png b/public/og-images/best-practices/api-security.png new file mode 100644 index 000000000000..edec25565dab Binary files /dev/null and b/public/og-images/best-practices/api-security.png differ diff --git a/public/og-images/best-practices/aws.png b/public/og-images/best-practices/aws.png new file mode 100644 index 000000000000..bc587253c8c3 Binary files /dev/null and b/public/og-images/best-practices/aws.png differ diff --git a/public/og-images/best-practices/backend-performance.png b/public/og-images/best-practices/backend-performance.png new file mode 100644 index 000000000000..4a3db82429df Binary files /dev/null and b/public/og-images/best-practices/backend-performance.png differ diff --git a/public/og-images/best-practices/code-review.png b/public/og-images/best-practices/code-review.png new file mode 100644 index 000000000000..3a8e419fe2ad Binary files /dev/null and b/public/og-images/best-practices/code-review.png differ diff --git a/public/og-images/best-practices/frontend-performance.png b/public/og-images/best-practices/frontend-performance.png new file mode 100644 index 000000000000..aa179766aebe Binary files /dev/null and b/public/og-images/best-practices/frontend-performance.png differ diff --git a/public/og-images/guides/asymptotic-notation.png b/public/og-images/guides/asymptotic-notation.png new file mode 100644 index 000000000000..8a7563af9508 Binary files /dev/null and b/public/og-images/guides/asymptotic-notation.png differ diff --git a/public/og-images/guides/avoid-render-blocking-javascript-with-async-defer.png b/public/og-images/guides/avoid-render-blocking-javascript-with-async-defer.png new file mode 100644 index 000000000000..78ff8f00caff Binary files /dev/null and b/public/og-images/guides/avoid-render-blocking-javascript-with-async-defer.png differ diff --git a/public/og-images/guides/backend-developer-skills.png b/public/og-images/guides/backend-developer-skills.png new file mode 100644 index 000000000000..456cd4db62cd Binary files /dev/null and b/public/og-images/guides/backend-developer-skills.png differ diff --git a/public/og-images/guides/backend-developer-tools.png b/public/og-images/guides/backend-developer-tools.png new file mode 100644 index 000000000000..689aa04f8d09 Binary files /dev/null and b/public/og-images/guides/backend-developer-tools.png differ diff --git a/public/og-images/guides/backend-languages.png b/public/og-images/guides/backend-languages.png new file mode 100644 index 000000000000..bdcbed3f13e1 Binary files /dev/null and b/public/og-images/guides/backend-languages.png differ diff --git a/public/og-images/guides/basic-authentication.png b/public/og-images/guides/basic-authentication.png new file mode 100644 index 000000000000..f12760325101 Binary files /dev/null and b/public/og-images/guides/basic-authentication.png differ diff --git a/public/og-images/guides/basics-of-authentication.png b/public/og-images/guides/basics-of-authentication.png new file mode 100644 index 000000000000..ec91f7153657 Binary files /dev/null and b/public/og-images/guides/basics-of-authentication.png differ diff --git a/public/og-images/guides/big-o-notation.png b/public/og-images/guides/big-o-notation.png new file mode 100644 index 000000000000..9c4b60f24858 Binary files /dev/null and b/public/og-images/guides/big-o-notation.png differ diff --git a/public/og-images/guides/character-encodings.png b/public/og-images/guides/character-encodings.png new file mode 100644 index 000000000000..8bd6c5cdeb05 Binary files /dev/null and b/public/og-images/guides/character-encodings.png differ diff --git a/public/og-images/guides/ci-cd.png b/public/og-images/guides/ci-cd.png new file mode 100644 index 000000000000..5b961759dd26 Binary files /dev/null and b/public/og-images/guides/ci-cd.png differ diff --git a/public/og-images/guides/consistency-patterns-in-distributed-systems.png b/public/og-images/guides/consistency-patterns-in-distributed-systems.png new file mode 100644 index 000000000000..8c1d60515c71 Binary files /dev/null and b/public/og-images/guides/consistency-patterns-in-distributed-systems.png differ diff --git a/public/og-images/guides/design-patterns-for-humans.png b/public/og-images/guides/design-patterns-for-humans.png new file mode 100644 index 000000000000..c35eceadd66a Binary files /dev/null and b/public/og-images/guides/design-patterns-for-humans.png differ diff --git a/public/og-images/guides/dhcp-in-one-picture.png b/public/og-images/guides/dhcp-in-one-picture.png new file mode 100644 index 000000000000..2b6dc91f91c5 Binary files /dev/null and b/public/og-images/guides/dhcp-in-one-picture.png differ diff --git a/public/og-images/guides/dns-in-one-picture.png b/public/og-images/guides/dns-in-one-picture.png new file mode 100644 index 000000000000..5705bf1ba260 Binary files /dev/null and b/public/og-images/guides/dns-in-one-picture.png differ diff --git a/public/og-images/guides/free-resources-to-learn-llms.png b/public/og-images/guides/free-resources-to-learn-llms.png new file mode 100644 index 000000000000..285f41d28730 Binary files /dev/null and b/public/og-images/guides/free-resources-to-learn-llms.png differ diff --git a/public/og-images/guides/history-of-javascript.png b/public/og-images/guides/history-of-javascript.png new file mode 100644 index 000000000000..f0a500962919 Binary files /dev/null and b/public/og-images/guides/history-of-javascript.png differ diff --git a/public/og-images/guides/how-to-setup-a-jump-server.png b/public/og-images/guides/how-to-setup-a-jump-server.png new file mode 100644 index 000000000000..5956397dcd54 Binary files /dev/null and b/public/og-images/guides/how-to-setup-a-jump-server.png differ diff --git a/public/og-images/guides/http-basic-authentication.png b/public/og-images/guides/http-basic-authentication.png new file mode 100644 index 000000000000..e4fd57091d0d Binary files /dev/null and b/public/og-images/guides/http-basic-authentication.png differ diff --git a/public/og-images/guides/http-caching.png b/public/og-images/guides/http-caching.png new file mode 100644 index 000000000000..30e42bec59a7 Binary files /dev/null and b/public/og-images/guides/http-caching.png differ diff --git a/public/og-images/guides/introduction-to-llms.png b/public/og-images/guides/introduction-to-llms.png new file mode 100644 index 000000000000..0c67a92433d6 Binary files /dev/null and b/public/og-images/guides/introduction-to-llms.png differ diff --git a/public/og-images/guides/journey-to-http2.png b/public/og-images/guides/journey-to-http2.png new file mode 100644 index 000000000000..6aaafe73d339 Binary files /dev/null and b/public/og-images/guides/journey-to-http2.png differ diff --git a/public/og-images/guides/jwt-authentication.png b/public/og-images/guides/jwt-authentication.png new file mode 100644 index 000000000000..1443c59d9eea Binary files /dev/null and b/public/og-images/guides/jwt-authentication.png differ diff --git a/public/og-images/guides/levels-of-seniority.png b/public/og-images/guides/levels-of-seniority.png new file mode 100644 index 000000000000..73eef6edac48 Binary files /dev/null and b/public/og-images/guides/levels-of-seniority.png differ diff --git a/public/og-images/guides/oauth.png b/public/og-images/guides/oauth.png new file mode 100644 index 000000000000..38c14d42ab42 Binary files /dev/null and b/public/og-images/guides/oauth.png differ diff --git a/public/og-images/guides/proxy-servers.png b/public/og-images/guides/proxy-servers.png new file mode 100644 index 000000000000..249bb1eb248b Binary files /dev/null and b/public/og-images/guides/proxy-servers.png differ diff --git a/public/og-images/guides/random-numbers.png b/public/og-images/guides/random-numbers.png new file mode 100644 index 000000000000..86d7cc2ebcf9 Binary files /dev/null and b/public/og-images/guides/random-numbers.png differ diff --git a/public/og-images/guides/scaling-databases.png b/public/og-images/guides/scaling-databases.png new file mode 100644 index 000000000000..ae390ef6d8c6 Binary files /dev/null and b/public/og-images/guides/scaling-databases.png differ diff --git a/public/og-images/guides/session-authentication.png b/public/og-images/guides/session-authentication.png new file mode 100644 index 000000000000..3fbc401ecf3d Binary files /dev/null and b/public/og-images/guides/session-authentication.png differ diff --git a/public/og-images/guides/session-based-authentication.png b/public/og-images/guides/session-based-authentication.png new file mode 100644 index 000000000000..961494edc0f3 Binary files /dev/null and b/public/og-images/guides/session-based-authentication.png differ diff --git a/public/og-images/guides/setup-and-auto-renew-ssl-certificates.png b/public/og-images/guides/setup-and-auto-renew-ssl-certificates.png new file mode 100644 index 000000000000..8f6a39674e7c Binary files /dev/null and b/public/og-images/guides/setup-and-auto-renew-ssl-certificates.png differ diff --git a/public/og-images/guides/single-command-database-setup.png b/public/og-images/guides/single-command-database-setup.png new file mode 100644 index 000000000000..2a01e9438aff Binary files /dev/null and b/public/og-images/guides/single-command-database-setup.png differ diff --git a/public/og-images/guides/ssl-tls-https-ssh.png b/public/og-images/guides/ssl-tls-https-ssh.png new file mode 100644 index 000000000000..eb73e5dd8ee3 Binary files /dev/null and b/public/og-images/guides/ssl-tls-https-ssh.png differ diff --git a/public/og-images/guides/sso.png b/public/og-images/guides/sso.png new file mode 100644 index 000000000000..dce149d8e18b Binary files /dev/null and b/public/og-images/guides/sso.png differ diff --git a/public/og-images/guides/token-authentication.png b/public/og-images/guides/token-authentication.png new file mode 100644 index 000000000000..35db620bdcb8 Binary files /dev/null and b/public/og-images/guides/token-authentication.png differ diff --git a/public/og-images/guides/torrent-client.png b/public/og-images/guides/torrent-client.png new file mode 100644 index 000000000000..6dcb81b0275b Binary files /dev/null and b/public/og-images/guides/torrent-client.png differ diff --git a/public/og-images/guides/unfamiliar-codebase.png b/public/og-images/guides/unfamiliar-codebase.png new file mode 100644 index 000000000000..b87a59b26b05 Binary files /dev/null and b/public/og-images/guides/unfamiliar-codebase.png differ diff --git a/public/og-images/guides/what-are-web-vitals.png b/public/og-images/guides/what-are-web-vitals.png new file mode 100644 index 000000000000..f4ed7e104e9a Binary files /dev/null and b/public/og-images/guides/what-are-web-vitals.png differ diff --git a/public/og-images/guides/what-is-internet.png b/public/og-images/guides/what-is-internet.png new file mode 100644 index 000000000000..4b116b7bab5c Binary files /dev/null and b/public/og-images/guides/what-is-internet.png differ diff --git a/public/og-images/guides/what-is-sli-slo-sla.png b/public/og-images/guides/what-is-sli-slo-sla.png new file mode 100644 index 000000000000..375eeff3a95b Binary files /dev/null and b/public/og-images/guides/what-is-sli-slo-sla.png differ diff --git a/public/og-images/guides/why-build-it-and-they-will-come-wont-work-anymore.png b/public/og-images/guides/why-build-it-and-they-will-come-wont-work-anymore.png new file mode 100644 index 000000000000..70bb0ba3daa6 Binary files /dev/null and b/public/og-images/guides/why-build-it-and-they-will-come-wont-work-anymore.png differ diff --git a/public/og-images/roadmaps/ai-data-scientist.png b/public/og-images/roadmaps/ai-data-scientist.png new file mode 100644 index 000000000000..195e701157ee Binary files /dev/null and b/public/og-images/roadmaps/ai-data-scientist.png differ diff --git a/public/og-images/roadmaps/android.png b/public/og-images/roadmaps/android.png new file mode 100644 index 000000000000..c7d7674b1ea8 Binary files /dev/null and b/public/og-images/roadmaps/android.png differ diff --git a/public/og-images/roadmaps/angular.png b/public/og-images/roadmaps/angular.png new file mode 100644 index 000000000000..cd593f85e749 Binary files /dev/null and b/public/og-images/roadmaps/angular.png differ diff --git a/public/og-images/roadmaps/aspnet-core.png b/public/og-images/roadmaps/aspnet-core.png new file mode 100644 index 000000000000..cb061ef0b622 Binary files /dev/null and b/public/og-images/roadmaps/aspnet-core.png differ diff --git a/public/og-images/roadmaps/aws.png b/public/og-images/roadmaps/aws.png new file mode 100644 index 000000000000..b8d6697c0958 Binary files /dev/null and b/public/og-images/roadmaps/aws.png differ diff --git a/public/og-images/roadmaps/backend.png b/public/og-images/roadmaps/backend.png new file mode 100644 index 000000000000..71f2a2c94516 Binary files /dev/null and b/public/og-images/roadmaps/backend.png differ diff --git a/public/og-images/roadmaps/blockchain.png b/public/og-images/roadmaps/blockchain.png new file mode 100644 index 000000000000..854ff9fa31ef Binary files /dev/null and b/public/og-images/roadmaps/blockchain.png differ diff --git a/public/og-images/roadmaps/code-review.png b/public/og-images/roadmaps/code-review.png new file mode 100644 index 000000000000..a8d5c610ffdc Binary files /dev/null and b/public/og-images/roadmaps/code-review.png differ diff --git a/public/og-images/roadmaps/computer-science.png b/public/og-images/roadmaps/computer-science.png new file mode 100644 index 000000000000..27835513e879 Binary files /dev/null and b/public/og-images/roadmaps/computer-science.png differ diff --git a/public/og-images/roadmaps/cpp.png b/public/og-images/roadmaps/cpp.png new file mode 100644 index 000000000000..68254db40929 Binary files /dev/null and b/public/og-images/roadmaps/cpp.png differ diff --git a/public/og-images/roadmaps/cyber-security.png b/public/og-images/roadmaps/cyber-security.png new file mode 100644 index 000000000000..0fa8c4db8c40 Binary files /dev/null and b/public/og-images/roadmaps/cyber-security.png differ diff --git a/public/og-images/roadmaps/data-analyst.png b/public/og-images/roadmaps/data-analyst.png new file mode 100644 index 000000000000..8514bced7100 Binary files /dev/null and b/public/og-images/roadmaps/data-analyst.png differ diff --git a/public/og-images/roadmaps/datastructures-and-algorithms.png b/public/og-images/roadmaps/datastructures-and-algorithms.png new file mode 100644 index 000000000000..eff90c4d2b0a Binary files /dev/null and b/public/og-images/roadmaps/datastructures-and-algorithms.png differ diff --git a/public/og-images/roadmaps/design-system.png b/public/og-images/roadmaps/design-system.png new file mode 100644 index 000000000000..0d36da247783 Binary files /dev/null and b/public/og-images/roadmaps/design-system.png differ diff --git a/public/og-images/roadmaps/devops.png b/public/og-images/roadmaps/devops.png new file mode 100644 index 000000000000..cebc2757d3ed Binary files /dev/null and b/public/og-images/roadmaps/devops.png differ diff --git a/public/og-images/roadmaps/docker.png b/public/og-images/roadmaps/docker.png new file mode 100644 index 000000000000..5808a51f34d5 Binary files /dev/null and b/public/og-images/roadmaps/docker.png differ diff --git a/public/og-images/roadmaps/flutter.png b/public/og-images/roadmaps/flutter.png new file mode 100644 index 000000000000..b24cbb6c42ce Binary files /dev/null and b/public/og-images/roadmaps/flutter.png differ diff --git a/public/og-images/roadmaps/frontend.png b/public/og-images/roadmaps/frontend.png new file mode 100644 index 000000000000..24c238eae63c Binary files /dev/null and b/public/og-images/roadmaps/frontend.png differ diff --git a/public/og-images/roadmaps/full-stack.png b/public/og-images/roadmaps/full-stack.png new file mode 100644 index 000000000000..c8fd6d841ee3 Binary files /dev/null and b/public/og-images/roadmaps/full-stack.png differ diff --git a/public/og-images/roadmaps/game-developer.png b/public/og-images/roadmaps/game-developer.png new file mode 100644 index 000000000000..b5d5d191a45f Binary files /dev/null and b/public/og-images/roadmaps/game-developer.png differ diff --git a/public/og-images/roadmaps/golang.png b/public/og-images/roadmaps/golang.png new file mode 100644 index 000000000000..9863bd8c55a1 Binary files /dev/null and b/public/og-images/roadmaps/golang.png differ diff --git a/public/og-images/roadmaps/graphql.png b/public/og-images/roadmaps/graphql.png new file mode 100644 index 000000000000..e53d26523f97 Binary files /dev/null and b/public/og-images/roadmaps/graphql.png differ diff --git a/public/og-images/roadmaps/java.png b/public/og-images/roadmaps/java.png new file mode 100644 index 000000000000..566bd93c109c Binary files /dev/null and b/public/og-images/roadmaps/java.png differ diff --git a/public/og-images/roadmaps/javascript.png b/public/og-images/roadmaps/javascript.png new file mode 100644 index 000000000000..269608713c6e Binary files /dev/null and b/public/og-images/roadmaps/javascript.png differ diff --git a/public/og-images/roadmaps/kubernetes.png b/public/og-images/roadmaps/kubernetes.png new file mode 100644 index 000000000000..583d166fb00b Binary files /dev/null and b/public/og-images/roadmaps/kubernetes.png differ diff --git a/public/og-images/roadmaps/linux.png b/public/og-images/roadmaps/linux.png new file mode 100644 index 000000000000..6bc3dba272af Binary files /dev/null and b/public/og-images/roadmaps/linux.png differ diff --git a/public/og-images/roadmaps/mlops.png b/public/og-images/roadmaps/mlops.png new file mode 100644 index 000000000000..3bb6e9e6e27d Binary files /dev/null and b/public/og-images/roadmaps/mlops.png differ diff --git a/public/og-images/roadmaps/mongodb.png b/public/og-images/roadmaps/mongodb.png new file mode 100644 index 000000000000..e2b6f80d4a50 Binary files /dev/null and b/public/og-images/roadmaps/mongodb.png differ diff --git a/public/og-images/roadmaps/nodejs.png b/public/og-images/roadmaps/nodejs.png new file mode 100644 index 000000000000..b4396fe03b35 Binary files /dev/null and b/public/og-images/roadmaps/nodejs.png differ diff --git a/public/og-images/roadmaps/postgresql-dba.png b/public/og-images/roadmaps/postgresql-dba.png new file mode 100644 index 000000000000..67b0816f11c2 Binary files /dev/null and b/public/og-images/roadmaps/postgresql-dba.png differ diff --git a/public/og-images/roadmaps/prompt-engineering.png b/public/og-images/roadmaps/prompt-engineering.png new file mode 100644 index 000000000000..37ddec03e43d Binary files /dev/null and b/public/og-images/roadmaps/prompt-engineering.png differ diff --git a/public/og-images/roadmaps/python.png b/public/og-images/roadmaps/python.png new file mode 100644 index 000000000000..6725d90fca17 Binary files /dev/null and b/public/og-images/roadmaps/python.png differ diff --git a/public/og-images/roadmaps/qa.png b/public/og-images/roadmaps/qa.png new file mode 100644 index 000000000000..ddc5d8d4d9d8 Binary files /dev/null and b/public/og-images/roadmaps/qa.png differ diff --git a/public/og-images/roadmaps/react-native.png b/public/og-images/roadmaps/react-native.png new file mode 100644 index 000000000000..ffd72bef445c Binary files /dev/null and b/public/og-images/roadmaps/react-native.png differ diff --git a/public/og-images/roadmaps/react.png b/public/og-images/roadmaps/react.png new file mode 100644 index 000000000000..8221c8003eb2 Binary files /dev/null and b/public/og-images/roadmaps/react.png differ diff --git a/public/og-images/roadmaps/rust.png b/public/og-images/roadmaps/rust.png new file mode 100644 index 000000000000..8e46b0c7d5f4 Binary files /dev/null and b/public/og-images/roadmaps/rust.png differ diff --git a/public/og-images/roadmaps/server-side-game-developer.png b/public/og-images/roadmaps/server-side-game-developer.png new file mode 100644 index 000000000000..e3e1f95798d7 Binary files /dev/null and b/public/og-images/roadmaps/server-side-game-developer.png differ diff --git a/public/og-images/roadmaps/software-architect.png b/public/og-images/roadmaps/software-architect.png new file mode 100644 index 000000000000..23a07a325082 Binary files /dev/null and b/public/og-images/roadmaps/software-architect.png differ diff --git a/public/og-images/roadmaps/software-design-architecture.png b/public/og-images/roadmaps/software-design-architecture.png new file mode 100644 index 000000000000..731077b2429b Binary files /dev/null and b/public/og-images/roadmaps/software-design-architecture.png differ diff --git a/public/og-images/roadmaps/spring-boot.png b/public/og-images/roadmaps/spring-boot.png new file mode 100644 index 000000000000..99b939764bd4 Binary files /dev/null and b/public/og-images/roadmaps/spring-boot.png differ diff --git a/public/og-images/roadmaps/sql.png b/public/og-images/roadmaps/sql.png new file mode 100644 index 000000000000..3333757fccf0 Binary files /dev/null and b/public/og-images/roadmaps/sql.png differ diff --git a/public/og-images/roadmaps/system-design.png b/public/og-images/roadmaps/system-design.png new file mode 100644 index 000000000000..c099f4fd93dc Binary files /dev/null and b/public/og-images/roadmaps/system-design.png differ diff --git a/public/og-images/roadmaps/technical-writer.png b/public/og-images/roadmaps/technical-writer.png new file mode 100644 index 000000000000..f52989f5a9ac Binary files /dev/null and b/public/og-images/roadmaps/technical-writer.png differ diff --git a/public/og-images/roadmaps/typescript.png b/public/og-images/roadmaps/typescript.png new file mode 100644 index 000000000000..44a659ec2fa8 Binary files /dev/null and b/public/og-images/roadmaps/typescript.png differ diff --git a/public/og-images/roadmaps/ux-design.png b/public/og-images/roadmaps/ux-design.png new file mode 100644 index 000000000000..48e5227468fb Binary files /dev/null and b/public/og-images/roadmaps/ux-design.png differ diff --git a/public/og-images/roadmaps/vue.png b/public/og-images/roadmaps/vue.png new file mode 100644 index 000000000000..4dd43d8d068b Binary files /dev/null and b/public/og-images/roadmaps/vue.png differ diff --git a/public/og-images/sql-roadmap.png b/public/og-images/sql-roadmap.png new file mode 100644 index 000000000000..fd35764b90ad Binary files /dev/null and b/public/og-images/sql-roadmap.png differ diff --git a/public/pdfs/best-practices/api-security.pdf b/public/pdfs/best-practices/api-security.pdf new file mode 100644 index 000000000000..523b6f748d0c Binary files /dev/null and b/public/pdfs/best-practices/api-security.pdf differ diff --git a/public/pdfs/best-practices/aws.pdf b/public/pdfs/best-practices/aws.pdf new file mode 100644 index 000000000000..d4da9d4c5060 Binary files /dev/null and b/public/pdfs/best-practices/aws.pdf differ diff --git a/public/pdfs/best-practices/backend-performance.pdf b/public/pdfs/best-practices/backend-performance.pdf new file mode 100644 index 000000000000..8ba3aa62fdef Binary files /dev/null and b/public/pdfs/best-practices/backend-performance.pdf differ diff --git a/public/pdfs/best-practices/code-review.pdf b/public/pdfs/best-practices/code-review.pdf new file mode 100644 index 000000000000..c592499a8772 Binary files /dev/null and b/public/pdfs/best-practices/code-review.pdf differ diff --git a/public/pdfs/best-practices/frontend-performance.pdf b/public/pdfs/best-practices/frontend-performance.pdf new file mode 100644 index 000000000000..fe2eedc70eef Binary files /dev/null and b/public/pdfs/best-practices/frontend-performance.pdf differ diff --git a/public/pdfs/roadmaps/ai-agents.pdf b/public/pdfs/roadmaps/ai-agents.pdf new file mode 100644 index 000000000000..20261b522a67 Binary files /dev/null and b/public/pdfs/roadmaps/ai-agents.pdf differ diff --git a/public/pdfs/roadmaps/ai-data-scientist.pdf b/public/pdfs/roadmaps/ai-data-scientist.pdf new file mode 100644 index 000000000000..ee81b7779791 Binary files /dev/null and b/public/pdfs/roadmaps/ai-data-scientist.pdf differ diff --git a/public/pdfs/roadmaps/ai-engineer.pdf b/public/pdfs/roadmaps/ai-engineer.pdf new file mode 100644 index 000000000000..cbce3ac4b573 Binary files /dev/null and b/public/pdfs/roadmaps/ai-engineer.pdf differ diff --git a/public/pdfs/roadmaps/ai-red-teaming.pdf b/public/pdfs/roadmaps/ai-red-teaming.pdf new file mode 100644 index 000000000000..ce150961d94e Binary files /dev/null and b/public/pdfs/roadmaps/ai-red-teaming.pdf differ diff --git a/public/pdfs/roadmaps/android.pdf b/public/pdfs/roadmaps/android.pdf new file mode 100644 index 000000000000..50eecbff6257 Binary files /dev/null and b/public/pdfs/roadmaps/android.pdf differ diff --git a/public/pdfs/roadmaps/angular.pdf b/public/pdfs/roadmaps/angular.pdf new file mode 100644 index 000000000000..4cda91dc230b Binary files /dev/null and b/public/pdfs/roadmaps/angular.pdf differ diff --git a/public/pdfs/roadmaps/api-design.pdf b/public/pdfs/roadmaps/api-design.pdf new file mode 100644 index 000000000000..fb6e077d9cb5 Binary files /dev/null and b/public/pdfs/roadmaps/api-design.pdf differ diff --git a/public/pdfs/roadmaps/api-security-best-practices.pdf b/public/pdfs/roadmaps/api-security-best-practices.pdf new file mode 100644 index 000000000000..1937f2ddc127 Binary files /dev/null and b/public/pdfs/roadmaps/api-security-best-practices.pdf differ diff --git a/public/pdfs/roadmaps/aspnet-core.pdf b/public/pdfs/roadmaps/aspnet-core.pdf new file mode 100644 index 000000000000..cab46efa9d40 Binary files /dev/null and b/public/pdfs/roadmaps/aspnet-core.pdf differ diff --git a/public/pdfs/roadmaps/aws-best-practices.pdf b/public/pdfs/roadmaps/aws-best-practices.pdf new file mode 100644 index 000000000000..4527f12eb70d Binary files /dev/null and b/public/pdfs/roadmaps/aws-best-practices.pdf differ diff --git a/public/pdfs/roadmaps/aws.pdf b/public/pdfs/roadmaps/aws.pdf new file mode 100644 index 000000000000..03de7c20e129 Binary files /dev/null and b/public/pdfs/roadmaps/aws.pdf differ diff --git a/public/pdfs/roadmaps/backend-beginner.pdf b/public/pdfs/roadmaps/backend-beginner.pdf new file mode 100644 index 000000000000..4c99204de15c Binary files /dev/null and b/public/pdfs/roadmaps/backend-beginner.pdf differ diff --git a/public/pdfs/roadmaps/backend-performance-best-practices.pdf b/public/pdfs/roadmaps/backend-performance-best-practices.pdf new file mode 100644 index 000000000000..8fd9007e8810 Binary files /dev/null and b/public/pdfs/roadmaps/backend-performance-best-practices.pdf differ diff --git a/public/pdfs/roadmaps/backend.pdf b/public/pdfs/roadmaps/backend.pdf new file mode 100644 index 000000000000..4931c277df07 Binary files /dev/null and b/public/pdfs/roadmaps/backend.pdf differ diff --git a/public/pdfs/roadmaps/bi-analyst.pdf b/public/pdfs/roadmaps/bi-analyst.pdf new file mode 100644 index 000000000000..dc09e00f76d9 Binary files /dev/null and b/public/pdfs/roadmaps/bi-analyst.pdf differ diff --git a/public/pdfs/roadmaps/blockchain.pdf b/public/pdfs/roadmaps/blockchain.pdf new file mode 100644 index 000000000000..c4aad08bdd37 Binary files /dev/null and b/public/pdfs/roadmaps/blockchain.pdf differ diff --git a/public/pdfs/roadmaps/cloudflare.pdf b/public/pdfs/roadmaps/cloudflare.pdf new file mode 100644 index 000000000000..93295023a758 Binary files /dev/null and b/public/pdfs/roadmaps/cloudflare.pdf differ diff --git a/public/pdfs/roadmaps/code-review-best-practices.pdf b/public/pdfs/roadmaps/code-review-best-practices.pdf new file mode 100644 index 000000000000..2ba668c60614 Binary files /dev/null and b/public/pdfs/roadmaps/code-review-best-practices.pdf differ diff --git a/public/pdfs/roadmaps/code-review.pdf b/public/pdfs/roadmaps/code-review.pdf new file mode 100644 index 000000000000..89cb69a65de5 Binary files /dev/null and b/public/pdfs/roadmaps/code-review.pdf differ diff --git a/public/pdfs/roadmaps/computer-science.pdf b/public/pdfs/roadmaps/computer-science.pdf new file mode 100644 index 000000000000..0b53ef676055 Binary files /dev/null and b/public/pdfs/roadmaps/computer-science.pdf differ diff --git a/public/pdfs/roadmaps/cpp.pdf b/public/pdfs/roadmaps/cpp.pdf new file mode 100644 index 000000000000..0b6035cba276 Binary files /dev/null and b/public/pdfs/roadmaps/cpp.pdf differ diff --git a/public/pdfs/roadmaps/css.pdf b/public/pdfs/roadmaps/css.pdf new file mode 100644 index 000000000000..d73a5bf9e1b9 Binary files /dev/null and b/public/pdfs/roadmaps/css.pdf differ diff --git a/public/pdfs/roadmaps/cyber-security.pdf b/public/pdfs/roadmaps/cyber-security.pdf new file mode 100644 index 000000000000..9155d7ff8aa2 Binary files /dev/null and b/public/pdfs/roadmaps/cyber-security.pdf differ diff --git a/public/pdfs/roadmaps/data-analyst.pdf b/public/pdfs/roadmaps/data-analyst.pdf new file mode 100644 index 000000000000..b91b395e5b5f Binary files /dev/null and b/public/pdfs/roadmaps/data-analyst.pdf differ diff --git a/public/pdfs/roadmaps/data-engineer.pdf b/public/pdfs/roadmaps/data-engineer.pdf new file mode 100644 index 000000000000..7157dd37339c Binary files /dev/null and b/public/pdfs/roadmaps/data-engineer.pdf differ diff --git a/public/pdfs/roadmaps/datastructures-and-algorithms.pdf b/public/pdfs/roadmaps/datastructures-and-algorithms.pdf new file mode 100644 index 000000000000..b2460a891f96 Binary files /dev/null and b/public/pdfs/roadmaps/datastructures-and-algorithms.pdf differ diff --git a/public/pdfs/roadmaps/design-system.pdf b/public/pdfs/roadmaps/design-system.pdf new file mode 100644 index 000000000000..d6f186aecdd6 Binary files /dev/null and b/public/pdfs/roadmaps/design-system.pdf differ diff --git a/public/pdfs/roadmaps/devops-beginner.pdf b/public/pdfs/roadmaps/devops-beginner.pdf new file mode 100644 index 000000000000..974d5c494de7 Binary files /dev/null and b/public/pdfs/roadmaps/devops-beginner.pdf differ diff --git a/public/pdfs/roadmaps/devops.pdf b/public/pdfs/roadmaps/devops.pdf new file mode 100644 index 000000000000..eba5ce91856b Binary files /dev/null and b/public/pdfs/roadmaps/devops.pdf differ diff --git a/public/pdfs/roadmaps/devrel.pdf b/public/pdfs/roadmaps/devrel.pdf new file mode 100644 index 000000000000..4c9d0b840b8a Binary files /dev/null and b/public/pdfs/roadmaps/devrel.pdf differ diff --git a/public/pdfs/roadmaps/docker.pdf b/public/pdfs/roadmaps/docker.pdf new file mode 100644 index 000000000000..c9b46c2f693b Binary files /dev/null and b/public/pdfs/roadmaps/docker.pdf differ diff --git a/public/pdfs/roadmaps/engineering-manager.pdf b/public/pdfs/roadmaps/engineering-manager.pdf new file mode 100644 index 000000000000..5a57bf2924d5 Binary files /dev/null and b/public/pdfs/roadmaps/engineering-manager.pdf differ diff --git a/public/pdfs/roadmaps/flutter.pdf b/public/pdfs/roadmaps/flutter.pdf new file mode 100644 index 000000000000..1143b2463557 Binary files /dev/null and b/public/pdfs/roadmaps/flutter.pdf differ diff --git a/public/pdfs/roadmaps/frontend-beginner.pdf b/public/pdfs/roadmaps/frontend-beginner.pdf new file mode 100644 index 000000000000..bf980626c155 Binary files /dev/null and b/public/pdfs/roadmaps/frontend-beginner.pdf differ diff --git a/public/pdfs/roadmaps/frontend-performance-best-practices.pdf b/public/pdfs/roadmaps/frontend-performance-best-practices.pdf new file mode 100644 index 000000000000..5a5bd332fd04 Binary files /dev/null and b/public/pdfs/roadmaps/frontend-performance-best-practices.pdf differ diff --git a/public/pdfs/roadmaps/frontend.pdf b/public/pdfs/roadmaps/frontend.pdf new file mode 100644 index 000000000000..9c554f5dba7a Binary files /dev/null and b/public/pdfs/roadmaps/frontend.pdf differ diff --git a/public/pdfs/roadmaps/full-stack.pdf b/public/pdfs/roadmaps/full-stack.pdf new file mode 100644 index 000000000000..775a5481369d Binary files /dev/null and b/public/pdfs/roadmaps/full-stack.pdf differ diff --git a/public/pdfs/roadmaps/game-developer.pdf b/public/pdfs/roadmaps/game-developer.pdf new file mode 100644 index 000000000000..e12e784717c6 Binary files /dev/null and b/public/pdfs/roadmaps/game-developer.pdf differ diff --git a/public/pdfs/roadmaps/git-github-beginner.pdf b/public/pdfs/roadmaps/git-github-beginner.pdf new file mode 100644 index 000000000000..b1fe407f400b Binary files /dev/null and b/public/pdfs/roadmaps/git-github-beginner.pdf differ diff --git a/public/pdfs/roadmaps/git-github.pdf b/public/pdfs/roadmaps/git-github.pdf new file mode 100644 index 000000000000..b44dd4d32247 Binary files /dev/null and b/public/pdfs/roadmaps/git-github.pdf differ diff --git a/public/pdfs/roadmaps/golang.pdf b/public/pdfs/roadmaps/golang.pdf new file mode 100644 index 000000000000..b7e00263a06e Binary files /dev/null and b/public/pdfs/roadmaps/golang.pdf differ diff --git a/public/pdfs/roadmaps/graphql.pdf b/public/pdfs/roadmaps/graphql.pdf new file mode 100644 index 000000000000..b83120e32442 Binary files /dev/null and b/public/pdfs/roadmaps/graphql.pdf differ diff --git a/public/pdfs/roadmaps/html.pdf b/public/pdfs/roadmaps/html.pdf new file mode 100644 index 000000000000..96057130951c Binary files /dev/null and b/public/pdfs/roadmaps/html.pdf differ diff --git a/public/pdfs/roadmaps/ios.pdf b/public/pdfs/roadmaps/ios.pdf new file mode 100644 index 000000000000..211ba290a42f Binary files /dev/null and b/public/pdfs/roadmaps/ios.pdf differ diff --git a/public/pdfs/roadmaps/java.pdf b/public/pdfs/roadmaps/java.pdf new file mode 100644 index 000000000000..9346e9b22173 Binary files /dev/null and b/public/pdfs/roadmaps/java.pdf differ diff --git a/public/pdfs/roadmaps/javascript.pdf b/public/pdfs/roadmaps/javascript.pdf new file mode 100644 index 000000000000..e24c2995c641 Binary files /dev/null and b/public/pdfs/roadmaps/javascript.pdf differ diff --git a/public/pdfs/roadmaps/kotlin.pdf b/public/pdfs/roadmaps/kotlin.pdf new file mode 100644 index 000000000000..b86e2666875b Binary files /dev/null and b/public/pdfs/roadmaps/kotlin.pdf differ diff --git a/public/pdfs/roadmaps/kubernetes.pdf b/public/pdfs/roadmaps/kubernetes.pdf new file mode 100644 index 000000000000..3df27deec88c Binary files /dev/null and b/public/pdfs/roadmaps/kubernetes.pdf differ diff --git a/public/pdfs/roadmaps/laravel.pdf b/public/pdfs/roadmaps/laravel.pdf new file mode 100644 index 000000000000..5597fe07a624 Binary files /dev/null and b/public/pdfs/roadmaps/laravel.pdf differ diff --git a/public/pdfs/roadmaps/linux.pdf b/public/pdfs/roadmaps/linux.pdf new file mode 100644 index 000000000000..52fc38cd644f Binary files /dev/null and b/public/pdfs/roadmaps/linux.pdf differ diff --git a/public/pdfs/roadmaps/machine-learning.pdf b/public/pdfs/roadmaps/machine-learning.pdf new file mode 100644 index 000000000000..efe832b74ebd Binary files /dev/null and b/public/pdfs/roadmaps/machine-learning.pdf differ diff --git a/public/pdfs/roadmaps/mlops.pdf b/public/pdfs/roadmaps/mlops.pdf new file mode 100644 index 000000000000..471b441fe40e Binary files /dev/null and b/public/pdfs/roadmaps/mlops.pdf differ diff --git a/public/pdfs/roadmaps/mongodb.pdf b/public/pdfs/roadmaps/mongodb.pdf new file mode 100644 index 000000000000..af3e9c932ed9 Binary files /dev/null and b/public/pdfs/roadmaps/mongodb.pdf differ diff --git a/public/pdfs/roadmaps/nextjs.pdf b/public/pdfs/roadmaps/nextjs.pdf new file mode 100644 index 000000000000..95d37115ccac Binary files /dev/null and b/public/pdfs/roadmaps/nextjs.pdf differ diff --git a/public/pdfs/roadmaps/nodejs.pdf b/public/pdfs/roadmaps/nodejs.pdf new file mode 100644 index 000000000000..cde4ecee4ceb Binary files /dev/null and b/public/pdfs/roadmaps/nodejs.pdf differ diff --git a/public/pdfs/roadmaps/php.pdf b/public/pdfs/roadmaps/php.pdf new file mode 100644 index 000000000000..4677b137b2f9 Binary files /dev/null and b/public/pdfs/roadmaps/php.pdf differ diff --git a/public/pdfs/roadmaps/postgresql-dba.pdf b/public/pdfs/roadmaps/postgresql-dba.pdf new file mode 100644 index 000000000000..069ccfc13ee0 Binary files /dev/null and b/public/pdfs/roadmaps/postgresql-dba.pdf differ diff --git a/public/pdfs/roadmaps/product-manager.pdf b/public/pdfs/roadmaps/product-manager.pdf new file mode 100644 index 000000000000..6d7152771b8c Binary files /dev/null and b/public/pdfs/roadmaps/product-manager.pdf differ diff --git a/public/pdfs/roadmaps/prompt-engineering.pdf b/public/pdfs/roadmaps/prompt-engineering.pdf new file mode 100644 index 000000000000..e8cf6a6ce445 Binary files /dev/null and b/public/pdfs/roadmaps/prompt-engineering.pdf differ diff --git a/public/pdfs/roadmaps/python.pdf b/public/pdfs/roadmaps/python.pdf new file mode 100644 index 000000000000..0b1301b345c6 Binary files /dev/null and b/public/pdfs/roadmaps/python.pdf differ diff --git a/public/pdfs/roadmaps/qa.pdf b/public/pdfs/roadmaps/qa.pdf new file mode 100644 index 000000000000..b477e1cdf609 Binary files /dev/null and b/public/pdfs/roadmaps/qa.pdf differ diff --git a/public/pdfs/roadmaps/react-native.pdf b/public/pdfs/roadmaps/react-native.pdf new file mode 100644 index 000000000000..edf9bb20533e Binary files /dev/null and b/public/pdfs/roadmaps/react-native.pdf differ diff --git a/public/pdfs/roadmaps/react.pdf b/public/pdfs/roadmaps/react.pdf new file mode 100644 index 000000000000..12e8d219188a Binary files /dev/null and b/public/pdfs/roadmaps/react.pdf differ diff --git a/public/pdfs/roadmaps/redis.pdf b/public/pdfs/roadmaps/redis.pdf new file mode 100644 index 000000000000..ae594851ddad Binary files /dev/null and b/public/pdfs/roadmaps/redis.pdf differ diff --git a/public/pdfs/roadmaps/rust.pdf b/public/pdfs/roadmaps/rust.pdf new file mode 100644 index 000000000000..05d8f2cd2a14 Binary files /dev/null and b/public/pdfs/roadmaps/rust.pdf differ diff --git a/public/pdfs/roadmaps/server-side-game-developer.pdf b/public/pdfs/roadmaps/server-side-game-developer.pdf new file mode 100644 index 000000000000..f22df05eaea9 Binary files /dev/null and b/public/pdfs/roadmaps/server-side-game-developer.pdf differ diff --git a/public/pdfs/roadmaps/shell-bash.pdf b/public/pdfs/roadmaps/shell-bash.pdf new file mode 100644 index 000000000000..22eb9e81003d Binary files /dev/null and b/public/pdfs/roadmaps/shell-bash.pdf differ diff --git a/public/pdfs/roadmaps/software-architect.pdf b/public/pdfs/roadmaps/software-architect.pdf new file mode 100644 index 000000000000..035d6d898072 Binary files /dev/null and b/public/pdfs/roadmaps/software-architect.pdf differ diff --git a/public/pdfs/roadmaps/software-design-architecture.pdf b/public/pdfs/roadmaps/software-design-architecture.pdf new file mode 100644 index 000000000000..8b49d1f0b007 Binary files /dev/null and b/public/pdfs/roadmaps/software-design-architecture.pdf differ diff --git a/public/pdfs/roadmaps/spring-boot.pdf b/public/pdfs/roadmaps/spring-boot.pdf new file mode 100644 index 000000000000..84599fb4492c Binary files /dev/null and b/public/pdfs/roadmaps/spring-boot.pdf differ diff --git a/public/pdfs/roadmaps/sql.pdf b/public/pdfs/roadmaps/sql.pdf new file mode 100644 index 000000000000..48530b08d335 Binary files /dev/null and b/public/pdfs/roadmaps/sql.pdf differ diff --git a/public/pdfs/roadmaps/swift-ui.pdf b/public/pdfs/roadmaps/swift-ui.pdf new file mode 100644 index 000000000000..058fc996095f Binary files /dev/null and b/public/pdfs/roadmaps/swift-ui.pdf differ diff --git a/public/pdfs/roadmaps/system-design.pdf b/public/pdfs/roadmaps/system-design.pdf new file mode 100644 index 000000000000..18abd7906ad9 Binary files /dev/null and b/public/pdfs/roadmaps/system-design.pdf differ diff --git a/public/pdfs/roadmaps/technical-writer.pdf b/public/pdfs/roadmaps/technical-writer.pdf new file mode 100644 index 000000000000..1ee101db7d35 Binary files /dev/null and b/public/pdfs/roadmaps/technical-writer.pdf differ diff --git a/public/pdfs/roadmaps/terraform.pdf b/public/pdfs/roadmaps/terraform.pdf new file mode 100644 index 000000000000..d944516da201 Binary files /dev/null and b/public/pdfs/roadmaps/terraform.pdf differ diff --git a/public/pdfs/roadmaps/typescript.pdf b/public/pdfs/roadmaps/typescript.pdf new file mode 100644 index 000000000000..7b50198d12d3 Binary files /dev/null and b/public/pdfs/roadmaps/typescript.pdf differ diff --git a/public/pdfs/roadmaps/ux-design.pdf b/public/pdfs/roadmaps/ux-design.pdf new file mode 100644 index 000000000000..7a7e24c1028a Binary files /dev/null and b/public/pdfs/roadmaps/ux-design.pdf differ diff --git a/public/pdfs/roadmaps/vue.pdf b/public/pdfs/roadmaps/vue.pdf new file mode 100644 index 000000000000..0a998e7d2dcc Binary files /dev/null and b/public/pdfs/roadmaps/vue.pdf differ diff --git a/public/roadmaps/ai-agents.png b/public/roadmaps/ai-agents.png new file mode 100644 index 000000000000..9b29b8d05c32 Binary files /dev/null and b/public/roadmaps/ai-agents.png differ diff --git a/public/roadmaps/ai-data-scientist.png b/public/roadmaps/ai-data-scientist.png new file mode 100644 index 000000000000..8573998fea67 Binary files /dev/null and b/public/roadmaps/ai-data-scientist.png differ diff --git a/public/roadmaps/ai-engineer.png b/public/roadmaps/ai-engineer.png new file mode 100644 index 000000000000..223aabf91ef0 Binary files /dev/null and b/public/roadmaps/ai-engineer.png differ diff --git a/public/roadmaps/ai-red-teaming.png b/public/roadmaps/ai-red-teaming.png new file mode 100644 index 000000000000..a610b1db7584 Binary files /dev/null and b/public/roadmaps/ai-red-teaming.png differ diff --git a/public/roadmaps/android.png b/public/roadmaps/android.png new file mode 100644 index 000000000000..b595a08275a1 Binary files /dev/null and b/public/roadmaps/android.png differ diff --git a/public/roadmaps/android/build-an-application.png b/public/roadmaps/android/build-an-application.png new file mode 100644 index 000000000000..d2861edefd9c Binary files /dev/null and b/public/roadmaps/android/build-an-application.png differ diff --git a/public/roadmaps/android/git-github.png b/public/roadmaps/android/git-github.png new file mode 100644 index 000000000000..f019ca83743f Binary files /dev/null and b/public/roadmaps/android/git-github.png differ diff --git a/public/roadmaps/android/pick-language.png b/public/roadmaps/android/pick-language.png new file mode 100644 index 000000000000..5736f869fdbd Binary files /dev/null and b/public/roadmaps/android/pick-language.png differ diff --git a/public/roadmaps/android/pick-language.svg b/public/roadmaps/android/pick-language.svg new file mode 100644 index 000000000000..03451210a627 --- /dev/null +++ b/public/roadmaps/android/pick-language.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/roadmaps/android/roadmap.png b/public/roadmaps/android/roadmap.png new file mode 100644 index 000000000000..911cc560d793 Binary files /dev/null and b/public/roadmaps/android/roadmap.png differ diff --git a/public/roadmaps/android/roadmap.svg b/public/roadmaps/android/roadmap.svg new file mode 100644 index 000000000000..5ee78b50dd43 --- /dev/null +++ b/public/roadmaps/android/roadmap.svg @@ -0,0 +1,559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/roadmaps/android/the-fundamentals.png b/public/roadmaps/android/the-fundamentals.png new file mode 100644 index 000000000000..e00368e32827 Binary files /dev/null and b/public/roadmaps/android/the-fundamentals.png differ diff --git a/public/roadmaps/angular.png b/public/roadmaps/angular.png new file mode 100644 index 000000000000..d75611143c62 Binary files /dev/null and b/public/roadmaps/angular.png differ diff --git a/public/roadmaps/api-design.png b/public/roadmaps/api-design.png new file mode 100644 index 000000000000..9e6c33b1c1a9 Binary files /dev/null and b/public/roadmaps/api-design.png differ diff --git a/public/roadmaps/api-security-best-practices.png b/public/roadmaps/api-security-best-practices.png new file mode 100644 index 000000000000..cee65e724802 Binary files /dev/null and b/public/roadmaps/api-security-best-practices.png differ diff --git a/public/roadmaps/aspnet-core.png b/public/roadmaps/aspnet-core.png new file mode 100644 index 000000000000..5fe7ff5d9456 Binary files /dev/null and b/public/roadmaps/aspnet-core.png differ diff --git a/public/roadmaps/aws-best-practices.png b/public/roadmaps/aws-best-practices.png new file mode 100644 index 000000000000..8baff4bfeca9 Binary files /dev/null and b/public/roadmaps/aws-best-practices.png differ diff --git a/public/roadmaps/aws.png b/public/roadmaps/aws.png new file mode 100644 index 000000000000..3c0dee5828f4 Binary files /dev/null and b/public/roadmaps/aws.png differ diff --git a/public/roadmaps/backend-beginner.png b/public/roadmaps/backend-beginner.png new file mode 100644 index 000000000000..8a4b1b7e9a47 Binary files /dev/null and b/public/roadmaps/backend-beginner.png differ diff --git a/public/roadmaps/backend-performance-best-practices.png b/public/roadmaps/backend-performance-best-practices.png new file mode 100644 index 000000000000..0efdbcf23c94 Binary files /dev/null and b/public/roadmaps/backend-performance-best-practices.png differ diff --git a/public/roadmaps/backend.png b/public/roadmaps/backend.png new file mode 100644 index 000000000000..843a7df67994 Binary files /dev/null and b/public/roadmaps/backend.png differ diff --git a/public/roadmaps/bi-analyst.png b/public/roadmaps/bi-analyst.png new file mode 100644 index 000000000000..0f9a762fdf60 Binary files /dev/null and b/public/roadmaps/bi-analyst.png differ diff --git a/public/roadmaps/blockchain.png b/public/roadmaps/blockchain.png new file mode 100644 index 000000000000..83be2f8a8d0d Binary files /dev/null and b/public/roadmaps/blockchain.png differ diff --git a/public/roadmaps/cloudflare.png b/public/roadmaps/cloudflare.png new file mode 100644 index 000000000000..347d5a0278e5 Binary files /dev/null and b/public/roadmaps/cloudflare.png differ diff --git a/public/roadmaps/code-review-best-practices.png b/public/roadmaps/code-review-best-practices.png new file mode 100644 index 000000000000..8d99b8e43cba Binary files /dev/null and b/public/roadmaps/code-review-best-practices.png differ diff --git a/public/roadmaps/code-review.png b/public/roadmaps/code-review.png new file mode 100644 index 000000000000..796325f24f32 Binary files /dev/null and b/public/roadmaps/code-review.png differ diff --git a/public/roadmaps/computer-science.png b/public/roadmaps/computer-science.png new file mode 100644 index 000000000000..2384c29aac74 Binary files /dev/null and b/public/roadmaps/computer-science.png differ diff --git a/public/roadmaps/cpp.png b/public/roadmaps/cpp.png new file mode 100644 index 000000000000..0663ddcbe821 Binary files /dev/null and b/public/roadmaps/cpp.png differ diff --git a/public/roadmaps/css.png b/public/roadmaps/css.png new file mode 100644 index 000000000000..f44a87bb7e8e Binary files /dev/null and b/public/roadmaps/css.png differ diff --git a/public/roadmaps/cyber-security.png b/public/roadmaps/cyber-security.png new file mode 100644 index 000000000000..4cc754c29518 Binary files /dev/null and b/public/roadmaps/cyber-security.png differ diff --git a/public/roadmaps/data-analyst.png b/public/roadmaps/data-analyst.png new file mode 100644 index 000000000000..59522c4d1da2 Binary files /dev/null and b/public/roadmaps/data-analyst.png differ diff --git a/public/roadmaps/data-engineer.png b/public/roadmaps/data-engineer.png new file mode 100644 index 000000000000..8de4d008e967 Binary files /dev/null and b/public/roadmaps/data-engineer.png differ diff --git a/public/roadmaps/datastructures-and-algorithms.png b/public/roadmaps/datastructures-and-algorithms.png new file mode 100644 index 000000000000..61797184e778 Binary files /dev/null and b/public/roadmaps/datastructures-and-algorithms.png differ diff --git a/public/roadmaps/design-system.png b/public/roadmaps/design-system.png new file mode 100644 index 000000000000..0b087dd32f13 Binary files /dev/null and b/public/roadmaps/design-system.png differ diff --git a/public/roadmaps/devops-beginner.png b/public/roadmaps/devops-beginner.png new file mode 100644 index 000000000000..bbf89500496a Binary files /dev/null and b/public/roadmaps/devops-beginner.png differ diff --git a/public/roadmaps/devops.png b/public/roadmaps/devops.png new file mode 100644 index 000000000000..c9c1a5cd693c Binary files /dev/null and b/public/roadmaps/devops.png differ diff --git a/public/roadmaps/devrel.png b/public/roadmaps/devrel.png new file mode 100644 index 000000000000..a59810ca0513 Binary files /dev/null and b/public/roadmaps/devrel.png differ diff --git a/public/roadmaps/docker.png b/public/roadmaps/docker.png new file mode 100644 index 000000000000..395889b0ab27 Binary files /dev/null and b/public/roadmaps/docker.png differ diff --git a/public/roadmaps/engineering-manager.png b/public/roadmaps/engineering-manager.png new file mode 100644 index 000000000000..1d37aaaafa03 Binary files /dev/null and b/public/roadmaps/engineering-manager.png differ diff --git a/public/roadmaps/flutter.png b/public/roadmaps/flutter.png new file mode 100644 index 000000000000..88006ea74f43 Binary files /dev/null and b/public/roadmaps/flutter.png differ diff --git a/public/roadmaps/frontend-beginner.png b/public/roadmaps/frontend-beginner.png new file mode 100644 index 000000000000..36b05034e4ac Binary files /dev/null and b/public/roadmaps/frontend-beginner.png differ diff --git a/public/roadmaps/frontend-performance-best-practices.png b/public/roadmaps/frontend-performance-best-practices.png new file mode 100644 index 000000000000..03af889a457d Binary files /dev/null and b/public/roadmaps/frontend-performance-best-practices.png differ diff --git a/public/roadmaps/frontend.png b/public/roadmaps/frontend.png new file mode 100644 index 000000000000..21f9acb30445 Binary files /dev/null and b/public/roadmaps/frontend.png differ diff --git a/public/roadmaps/full-stack.png b/public/roadmaps/full-stack.png new file mode 100644 index 000000000000..d8c1d5ca2aa8 Binary files /dev/null and b/public/roadmaps/full-stack.png differ diff --git a/public/roadmaps/game-developer.png b/public/roadmaps/game-developer.png new file mode 100644 index 000000000000..5cd41c8ec2b9 Binary files /dev/null and b/public/roadmaps/game-developer.png differ diff --git a/public/roadmaps/git-github-beginner.png b/public/roadmaps/git-github-beginner.png new file mode 100644 index 000000000000..d7d3b21a4706 Binary files /dev/null and b/public/roadmaps/git-github-beginner.png differ diff --git a/public/roadmaps/git-github.png b/public/roadmaps/git-github.png new file mode 100644 index 000000000000..e954495728b7 Binary files /dev/null and b/public/roadmaps/git-github.png differ diff --git a/public/roadmaps/golang.png b/public/roadmaps/golang.png new file mode 100644 index 000000000000..eb1a1d0a168b Binary files /dev/null and b/public/roadmaps/golang.png differ diff --git a/public/roadmaps/graphql.png b/public/roadmaps/graphql.png new file mode 100644 index 000000000000..cf8eb0cebe4f Binary files /dev/null and b/public/roadmaps/graphql.png differ diff --git a/public/roadmaps/html.png b/public/roadmaps/html.png new file mode 100644 index 000000000000..e40b22bdf497 Binary files /dev/null and b/public/roadmaps/html.png differ diff --git a/public/roadmaps/intro.png b/public/roadmaps/intro.png new file mode 100644 index 000000000000..d298db124cd6 Binary files /dev/null and b/public/roadmaps/intro.png differ diff --git a/public/roadmaps/ios.png b/public/roadmaps/ios.png new file mode 100644 index 000000000000..4ca63facbf1f Binary files /dev/null and b/public/roadmaps/ios.png differ diff --git a/public/roadmaps/java.png b/public/roadmaps/java.png new file mode 100644 index 000000000000..be46293e6d74 Binary files /dev/null and b/public/roadmaps/java.png differ diff --git a/public/roadmaps/javascript.png b/public/roadmaps/javascript.png new file mode 100644 index 000000000000..2e70ce778dcf Binary files /dev/null and b/public/roadmaps/javascript.png differ diff --git a/public/roadmaps/kotlin.png b/public/roadmaps/kotlin.png new file mode 100644 index 000000000000..14c910f5add6 Binary files /dev/null and b/public/roadmaps/kotlin.png differ diff --git a/public/roadmaps/kubernetes.png b/public/roadmaps/kubernetes.png new file mode 100644 index 000000000000..b8cbf76abc47 Binary files /dev/null and b/public/roadmaps/kubernetes.png differ diff --git a/public/roadmaps/laravel.png b/public/roadmaps/laravel.png new file mode 100644 index 000000000000..dd4c44b13800 Binary files /dev/null and b/public/roadmaps/laravel.png differ diff --git a/public/roadmaps/linux.png b/public/roadmaps/linux.png new file mode 100644 index 000000000000..32310285cdd2 Binary files /dev/null and b/public/roadmaps/linux.png differ diff --git a/public/roadmaps/machine-learning.png b/public/roadmaps/machine-learning.png new file mode 100644 index 000000000000..48f33f68f307 Binary files /dev/null and b/public/roadmaps/machine-learning.png differ diff --git a/public/roadmaps/mlops.png b/public/roadmaps/mlops.png new file mode 100644 index 000000000000..5e2dd47c54f0 Binary files /dev/null and b/public/roadmaps/mlops.png differ diff --git a/public/roadmaps/mongodb.png b/public/roadmaps/mongodb.png new file mode 100644 index 000000000000..ba644f0edf78 Binary files /dev/null and b/public/roadmaps/mongodb.png differ diff --git a/public/roadmaps/nextjs.png b/public/roadmaps/nextjs.png new file mode 100644 index 000000000000..de412fbf885a Binary files /dev/null and b/public/roadmaps/nextjs.png differ diff --git a/public/roadmaps/nodejs.png b/public/roadmaps/nodejs.png new file mode 100644 index 000000000000..cc6f554e2ecc Binary files /dev/null and b/public/roadmaps/nodejs.png differ diff --git a/public/roadmaps/php.png b/public/roadmaps/php.png new file mode 100644 index 000000000000..8f1744305efd Binary files /dev/null and b/public/roadmaps/php.png differ diff --git a/public/roadmaps/postgresql-dba.png b/public/roadmaps/postgresql-dba.png new file mode 100644 index 000000000000..699741432b67 Binary files /dev/null and b/public/roadmaps/postgresql-dba.png differ diff --git a/public/roadmaps/product-manager.png b/public/roadmaps/product-manager.png new file mode 100644 index 000000000000..d404052faa5a Binary files /dev/null and b/public/roadmaps/product-manager.png differ diff --git a/public/roadmaps/prompt-engineering.png b/public/roadmaps/prompt-engineering.png new file mode 100644 index 000000000000..075ea10082ec Binary files /dev/null and b/public/roadmaps/prompt-engineering.png differ diff --git a/public/roadmaps/python.png b/public/roadmaps/python.png new file mode 100644 index 000000000000..061cea1f9776 Binary files /dev/null and b/public/roadmaps/python.png differ diff --git a/public/roadmaps/qa.png b/public/roadmaps/qa.png new file mode 100644 index 000000000000..fee75448a97b Binary files /dev/null and b/public/roadmaps/qa.png differ diff --git a/public/roadmaps/react-native.png b/public/roadmaps/react-native.png new file mode 100644 index 000000000000..d99229115b2c Binary files /dev/null and b/public/roadmaps/react-native.png differ diff --git a/public/roadmaps/react.png b/public/roadmaps/react.png new file mode 100644 index 000000000000..802bdb524fb3 Binary files /dev/null and b/public/roadmaps/react.png differ diff --git a/public/roadmaps/redis.png b/public/roadmaps/redis.png new file mode 100644 index 000000000000..f4a48b9e35ae Binary files /dev/null and b/public/roadmaps/redis.png differ diff --git a/public/roadmaps/rust.png b/public/roadmaps/rust.png new file mode 100644 index 000000000000..10deba88eedf Binary files /dev/null and b/public/roadmaps/rust.png differ diff --git a/public/roadmaps/server-side-game-developer.png b/public/roadmaps/server-side-game-developer.png new file mode 100644 index 000000000000..30e45be69b47 Binary files /dev/null and b/public/roadmaps/server-side-game-developer.png differ diff --git a/public/roadmaps/shell-bash.png b/public/roadmaps/shell-bash.png new file mode 100644 index 000000000000..6b7a7ed29ad8 Binary files /dev/null and b/public/roadmaps/shell-bash.png differ diff --git a/public/roadmaps/software-architect.png b/public/roadmaps/software-architect.png new file mode 100644 index 000000000000..528b1aa1ec3e Binary files /dev/null and b/public/roadmaps/software-architect.png differ diff --git a/public/roadmaps/software-design-architecture.png b/public/roadmaps/software-design-architecture.png new file mode 100644 index 000000000000..2ed24ee3bcb8 Binary files /dev/null and b/public/roadmaps/software-design-architecture.png differ diff --git a/public/roadmaps/spring-boot.png b/public/roadmaps/spring-boot.png new file mode 100644 index 000000000000..75d3ad505ea8 Binary files /dev/null and b/public/roadmaps/spring-boot.png differ diff --git a/public/roadmaps/sql.png b/public/roadmaps/sql.png new file mode 100644 index 000000000000..7deb0cac4f1c Binary files /dev/null and b/public/roadmaps/sql.png differ diff --git a/public/roadmaps/swift-ui.png b/public/roadmaps/swift-ui.png new file mode 100644 index 000000000000..d53387fff828 Binary files /dev/null and b/public/roadmaps/swift-ui.png differ diff --git a/public/roadmaps/system-design.png b/public/roadmaps/system-design.png new file mode 100644 index 000000000000..5638f1ed81c3 Binary files /dev/null and b/public/roadmaps/system-design.png differ diff --git a/public/roadmaps/technical-writer.png b/public/roadmaps/technical-writer.png new file mode 100644 index 000000000000..b42aeccf102a Binary files /dev/null and b/public/roadmaps/technical-writer.png differ diff --git a/public/roadmaps/terraform.png b/public/roadmaps/terraform.png new file mode 100644 index 000000000000..3164f91f9fd8 Binary files /dev/null and b/public/roadmaps/terraform.png differ diff --git a/public/roadmaps/typescript.png b/public/roadmaps/typescript.png new file mode 100644 index 000000000000..5dac3e491dac Binary files /dev/null and b/public/roadmaps/typescript.png differ diff --git a/public/roadmaps/ux-design.png b/public/roadmaps/ux-design.png new file mode 100644 index 000000000000..250a7880e94a Binary files /dev/null and b/public/roadmaps/ux-design.png differ diff --git a/public/roadmaps/vue.png b/public/roadmaps/vue.png new file mode 100644 index 000000000000..15db7a4f9b70 Binary files /dev/null and b/public/roadmaps/vue.png differ diff --git a/readme.md b/readme.md new file mode 100644 index 000000000000..dd109c59e36d --- /dev/null +++ b/readme.md @@ -0,0 +1,179 @@ +

+ +

roadmap.sh

+

Community driven roadmaps, articles and resources for developers

+

+ + roadmaps + + + best practices + + + videos + + + roadmaps + +

+

+ +
+ +![](https://i.imgur.com/waxVImv.png) + +Roadmaps are now interactive, you can click the nodes to read more about the topics. + +### [View all Roadmaps](https://roadmap.sh)  ·  [Best Practices](https://roadmap.sh/best-practices)  ·  [Questions](https://roadmap.sh/questions) + +![](https://i.imgur.com/waxVImv.png) + +Here is the list of available roadmaps with more being actively worked upon. + +> Have a look at the [get started](https://roadmap.sh/get-started) page that might help you pick up a path. + +- [Frontend Roadmap](https://roadmap.sh/frontend) / [Frontend Beginner Roadmap](https://roadmap.sh/frontend?r=frontend-beginner) +- [Backend Roadmap](https://roadmap.sh/backend) / [Backend Beginner Roadmap](https://roadmap.sh/backend?r=backend-beginner) +- [DevOps Roadmap](https://roadmap.sh/devops) / [DevOps Beginner Roadmap](https://roadmap.sh/devops?r=devops-beginner) +- [DevSecOps Roadmap](https://roadmap.sh/devsecops) +- [Full Stack Roadmap](https://roadmap.sh/full-stack) +- [Claude Code Roadmap](https://roadmap.sh/claude-code) +- [OpenClaw Roadmap](https://roadmap.sh/openclaw) +- [Vibe Coding Roadmap](https://roadmap.sh/vibe-coding) +- [HTML Roadmap](https://roadmap.sh/html) +- [CSS Roadmap](https://roadmap.sh/css) +- [JavaScript Roadmap](https://roadmap.sh/javascript) +- [TypeScript Roadmap](https://roadmap.sh/typescript) +- [Git and GitHub](https://roadmap.sh/git-github) / [Git and GitHub Beginner](https://roadmap.sh/git-github?r=git-github-beginner) +- [API Design Roadmap](https://roadmap.sh/api-design) +- [Computer Science Roadmap](https://roadmap.sh/computer-science) +- [Data Structures and Algorithms Roadmap](https://roadmap.sh/datastructures-and-algorithms) +- [AI and Data Scientist Roadmap](https://roadmap.sh/ai-data-scientist) +- [AI Engineer Roadmap](https://roadmap.sh/ai-engineer) +- [AWS Roadmap](https://roadmap.sh/aws) +- [Cloudflare Roadmap](https://roadmap.sh/cloudflare) +- [Linux Roadmap](https://roadmap.sh/linux) +- [Leetcode Roadmap](https://roadmap.sh/leetcode) +- [Terraform Roadmap](https://roadmap.sh/terraform) +- [Data Analyst Roadmap](https://roadmap.sh/data-analyst) +- [BI Analyst Roadmap](https://roadmap.sh/bi-analyst) +- [Data Engineer Roadmap](https://roadmap.sh/data-engineer) +- [Machine Learning Roadmap](https://roadmap.sh/machine-learning) +- [MLOps Roadmap](https://roadmap.sh/mlops) +- [Product Manager Roadmap](https://roadmap.sh/product-manager) +- [Engineering Manager Roadmap](https://roadmap.sh/engineering-manager) +- [QA Roadmap](https://roadmap.sh/qa) +- [Python Roadmap](https://roadmap.sh/python) +- [Django Roadmap](https://roadmap.sh/django) +- [Software Architect Roadmap](https://roadmap.sh/software-architect) +- [Game Developer Roadmap](https://roadmap.sh/game-developer) / [Server Side Game Developer](https://roadmap.sh/server-side-game-developer) +- [Software Design and Architecture Roadmap](https://roadmap.sh/software-design-architecture) +- [C++ Roadmap](https://roadmap.sh/cpp) +- [React Roadmap](https://roadmap.sh/react) +- [Next.js Roadmap](https://roadmap.sh/nextjs) +- [React Native Roadmap](https://roadmap.sh/react-native) +- [Vue Roadmap](https://roadmap.sh/vue) +- [Angular Roadmap](https://roadmap.sh/angular) +- [Node.js Roadmap](https://roadmap.sh/nodejs) +- [PHP Roadmap](https://roadmap.sh/php) +- [WordPress Roadmap](https://roadmap.sh/wordpress) +- [Laravel Roadmap](https://roadmap.sh/laravel) +- [GraphQL Roadmap](https://roadmap.sh/graphql) +- [Android Roadmap](https://roadmap.sh/android) +- [iOS Roadmap](https://roadmap.sh/ios) +- [Swift/Swift UI Roadmap](https://roadmap.sh/swift-ui) +- [Flutter Roadmap](https://roadmap.sh/flutter) +- [Go Roadmap](https://roadmap.sh/golang) +- [Rust Roadmap](https://roadmap.sh/rust) +- [Java Roadmap](https://roadmap.sh/java) +- [Kotlin Roadmap](https://roadmap.sh/kotlin) +- [Spring Boot Roadmap](https://roadmap.sh/spring-boot) +- [Design System Roadmap](https://roadmap.sh/design-system) +- [PostgreSQL Roadmap](https://roadmap.sh/postgresql-dba) +- [ElasticSearch Roadmap](https://roadmap.sh/elasticsearch) +- [SQL Roadmap](https://roadmap.sh/sql) +- [Redis Roadmap](https://roadmap.sh/redis) +- [Blockchain Roadmap](https://roadmap.sh/blockchain) +- [ASP.NET Core Roadmap](https://roadmap.sh/aspnet-core) +- [System Design Roadmap](https://roadmap.sh/system-design) +- [Kubernetes Roadmap](https://roadmap.sh/kubernetes) +- [Cyber Security Roadmap](https://roadmap.sh/cyber-security) +- [MongoDB Roadmap](https://roadmap.sh/mongodb) +- [UX Design Roadmap](https://roadmap.sh/ux-design) +- [Docker Roadmap](https://roadmap.sh/docker) +- [Prompt Engineering Roadmap](https://roadmap.sh/prompt-engineering) +- [Technical Writer Roadmap](https://roadmap.sh/technical-writer) +- [DevRel Engineer Roadmap](https://roadmap.sh/devrel) +- [AI Red Teaming Roadmap](https://roadmap.sh/ai-red-teaming) +- [AI Agents Roadmap](https://roadmap.sh/ai-agents) +- [Bash/Shell Roadmap](https://roadmap.sh/shell-bash) +- [Ruby Roadmap](https://roadmap.sh/ruby) +- [Ruby on Rails Roadmap](https://roadmap.sh/ruby-on-rails) +- [Scala Roadmap](https://roadmap.sh/scala) + + +There are also interactive best practices: + +- [Backend Performance Best Practices](https://roadmap.sh/best-practices/backend-performance) +- [Frontend Performance Best Practices](https://roadmap.sh/best-practices/frontend-performance) +- [Code Review Best Practices](https://roadmap.sh/best-practices/code-review) +- [API Security Best Practices](https://roadmap.sh/best-practices/api-security) +- [AWS Best Practices](https://roadmap.sh/best-practices/aws) + +..and questions to help you test, rate and improve your knowledge + +- [JavaScript Questions](https://roadmap.sh/questions/javascript) +- [Node.js Questions](https://roadmap.sh/questions/nodejs) +- [React Questions](https://roadmap.sh/questions/react) +- [Backend Questions](https://roadmap.sh/questions/backend) +- [Frontend Questions](https://roadmap.sh/questions/frontend) + +![](https://i.imgur.com/waxVImv.png) + +## Share with the community + +Please consider sharing a post about [roadmap.sh](https://roadmap.sh) and the value it provides. It really does help! + +[![GitHub Repo stars](https://img.shields.io/badge/share%20on-reddit-red?logo=reddit)](https://reddit.com/submit?url=https://roadmap.sh&title=Interactive%20roadmaps,%20guides%20and%20other%20educational%20content%20for%20Developers) +[![GitHub Repo stars](https://img.shields.io/badge/share%20on-hacker%20news-orange?logo=ycombinator)](https://news.ycombinator.com/submitlink?u=https://roadmap.sh) +[![GitHub Repo stars](https://img.shields.io/badge/share%20on-twitter-03A9F4?logo=twitter)](https://twitter.com/share?url=https://roadmap.sh&text=Interactive%20roadmaps,%20guides%20and%20other%20educational%20content%20for%20Developers) +[![GitHub Repo stars](https://img.shields.io/badge/share%20on-facebook-1976D2?logo=facebook)](https://www.facebook.com/sharer/sharer.php?u=https://roadmap.sh) +[![GitHub Repo stars](https://img.shields.io/badge/share%20on-linkedin-3949AB?logo=linkedin)](https://www.linkedin.com/shareArticle?url=https://roadmap.sh&title=Interactive%20roadmaps,%20guides%20and%20other%20educational%20content%20for%20Developers) + +## Development + +Clone the repository, install the dependencies and start the application + +```bash +git clone git@github.com:kamranahmedse/developer-roadmap.git --depth 1 +cd developer-roadmap +pnpm add @roadmapsh/editor@npm:@roadmapsh/dummy-editor -w +pnpm install +``` + +Run the development server with: + +```bash +pnpm dev +``` +> Make sure to rename `.env.example` to `.env` before running the app. + +## Contribution + +> Have a look at [contribution docs](./contributing.md) for how to update any of the roadmaps + +- Add content to roadmaps +- Add new roadmaps +- Suggest changes to existing roadmaps +- Discuss ideas in issues +- Spread the word + +## Thanks to all contributors ❤ + + + + + +## License + +Have a look at the [license file](./license) for details diff --git a/scripts/assign-label-types.cjs b/scripts/assign-label-types.cjs new file mode 100644 index 000000000000..72ce641246fb --- /dev/null +++ b/scripts/assign-label-types.cjs @@ -0,0 +1,189 @@ +const fs = require('node:fs'); +const path = require('node:path'); + +const allRoadmapDirs = fs.readdirSync( + path.join(__dirname, '../src/data/roadmaps'), +); + +allRoadmapDirs.forEach((roadmapId) => { + const roadmapDir = path.join( + __dirname, + `../src/data/roadmaps/${roadmapId}/content`, + ); + + function getHostNameWithoutTld(hostname) { + const parts = hostname.split('.'); + return parts.slice(0, parts.length - 1).join('.'); + } + + function isOfficialWebsite(hostname, fileName, roadmapId) { + fileName = fileName.replace('/index.md', '').replace('.md', ''); + + const parts = fileName.split('/'); + const lastPart = parts[parts.length - 1]; + + const normalizedFilename = lastPart.replace(/\d+/g, '').replace(/-/g, ''); + const normalizedHostname = getHostNameWithoutTld(hostname); + + if (normalizedFilename === normalizedHostname) { + return true; + } + + if (normalizedFilename.includes(normalizedHostname)) { + return true; + } + + return !!roadmapId.includes(normalizedHostname); + } + + // websites are educational websites that are of following types: + // - @official@ + // - @article@ + // - @course@ + // - @opensource@ + // - @podcast@ + // - @video@ + // - @website@ + // content is only educational websites + function getTypeFromHostname(hostname, fileName, roadmapId) { + hostname = hostname.replace('www.', ''); + + const videoHostnames = ['youtube.com', 'vimeo.com', 'youtu.be']; + const courseHostnames = ['coursera.org', 'udemy.com', 'edx.org']; + const podcastHostnames = ['spotify.com', 'apple.com']; + const opensourceHostnames = ['github.com', 'gitlab.com']; + const articleHostnames = [ + 'neilpatel.com', + 'learningseo.io', + 'htmlreference.io', + 'docs.gitlab.com', + 'docs.github.com', + 'skills.github.com', + 'cloudflare.com', + 'w3schools.com', + 'medium.com', + 'dev.to', + 'web.dev', + 'css-tricks.com', + 'developer.mozilla.org', + 'smashingmagazine.com', + 'freecodecamp.org', + 'cs.fyi', + 'thenewstack.io', + 'html5rocks.com', + 'html.com', + 'javascript.info', + 'css-tricks.com', + 'developer.apple.com', + ]; + + if (articleHostnames.includes(hostname)) { + return 'article'; + } + + if (videoHostnames.includes(hostname)) { + return 'video'; + } + + if (courseHostnames.includes(hostname)) { + return 'course'; + } + + if (podcastHostnames.includes(hostname)) { + return 'podcast'; + } + + if (opensourceHostnames.includes(hostname)) { + return 'opensource'; + } + + if (hostname === 'roadmap.sh') { + return 'roadmap.sh'; + } + + if (isOfficialWebsite(hostname, fileName, roadmapId)) { + return 'official'; + } + + return 'article'; + } + + function readNestedMarkdownFiles(dir, files = []) { + const dirEnts = fs.readdirSync(dir, { withFileTypes: true }); + + for (const dirent of dirEnts) { + const fullPath = path.join(dir, dirent.name); + if (dirent.isDirectory()) { + readNestedMarkdownFiles(fullPath, files); + } else { + if (path.extname(fullPath) === '.md') { + files.push(fullPath); + } + } + } + + return files; + } + + const files = readNestedMarkdownFiles(roadmapDir); + + // for each of the files, assign the type of link to the beginning of each markdown link + // i.e. - [@article@abc](xyz) where @article@ is the type of link. Possible types: + // - @official@ + // - @opensource@ + // - @article@ + // - @course@ + // - @opensource@ + // - @podcast@ + // - @video@ + files.forEach((file) => { + const content = fs.readFileSync(file, 'utf-8'); + const lines = content.split('\n'); + + const newContent = lines + .map((line) => { + if (line.startsWith('- [') && !line.startsWith('- [@')) { + const type = line.match(/@(\w+)@/); + if (type) { + return line; + } + + let urlMatches = line.match(/\((https?:\/\/[^)]+)\)/); + let fullUrl = urlMatches?.[1]; + + if (!fullUrl) { + // is it slashed URL i.e. - [abc](/xyz) + fullUrl = line.match(/\((\/[^)]+)\)/)?.[1]; + if (fullUrl) { + fullUrl = `https://roadmap.sh${fullUrl}`; + } + + if (!fullUrl) { + console.error('Invalid URL found in:', file); + return line; + } + } + + const url = new URL(fullUrl); + const hostname = url.hostname; + + let urlType = getTypeFromHostname(hostname, file, roadmapId); + const linkText = line.match(/\[([^\]]+)\]/)[1]; + + if ( + linkText.toLowerCase().startsWith('visit dedicated') && + linkText.toLowerCase().endsWith('roadmap') + ) { + urlType = 'roadmap'; + } + + return line.replace('- [', `- [@${urlType}@`).replace('](', ']('); + } + + return line; + }) + .join('\n'); + + fs.writeFileSync(file, newContent); + }); +}); diff --git a/scripts/best-practice-content.cjs b/scripts/best-practice-content.cjs new file mode 100644 index 000000000000..7436741704b1 --- /dev/null +++ b/scripts/best-practice-content.cjs @@ -0,0 +1,181 @@ +const fs = require('fs'); +const path = require('path'); + +const OPEN_AI_API_KEY = process.env.OPEN_AI_API_KEY; +const ALL_BEST_PRACTICES_DIR = path.join( + __dirname, + '../src/data/best-practices', +); + +const bestPracticeId = process.argv[2]; +const bestPracticeTitle = bestPracticeId.replace(/-/g, ' '); + +const allowedBestPracticeIds = fs.readdirSync(ALL_BEST_PRACTICES_DIR); +if (!bestPracticeId) { + console.error('bestPracticeId is required'); + process.exit(1); +} + +if (!allowedBestPracticeIds.includes(bestPracticeId)) { + console.error(`Invalid bestPractice key ${bestPracticeId}`); + console.error(`Allowed keys are ${allowedBestPracticeIds.join(', ')}`); + process.exit(1); +} + +const BEST_PRACTICE_CONTENT_DIR = path.join( + ALL_BEST_PRACTICES_DIR, + bestPracticeId, + 'content', +); +const OpenAI = require('openai'); + +const openai = new OpenAI({ + apiKey: OPEN_AI_API_KEY, +}); + +function getFilesInFolder(folderPath, fileList = {}) { + const files = fs.readdirSync(folderPath); + + files.forEach((file) => { + const filePath = path.join(folderPath, file); + const stats = fs.statSync(filePath); + + if (stats.isDirectory()) { + getFilesInFolder(filePath, fileList); + } else if (stats.isFile()) { + const fileUrl = filePath + .replace(BEST_PRACTICE_CONTENT_DIR, '') // Remove the content folder + .replace(/\/\d+-/g, '/') // Remove ordering info `/101-ecosystem` + .replace(/\/index\.md$/, '') // Make the `/index.md` to become the parent folder only + .replace(/\.md$/, ''); // Remove `.md` from the end of file + + fileList[fileUrl] = filePath; + } + }); + + return fileList; +} + +function writeTopicContent(topicTitle) { + let prompt = `I will give you a topic and you need to write a brief paragraph with examples (if possible) about why it is important for the "${bestPracticeTitle}". Just reply to the question without adding any other information about the prompt and use simple language. Also do not start your sentences with "XYZ is important because..". Your format should be as follows: + +# (Put a heading for the topic) + +(Write a brief paragraph about why it is important for the "${bestPracticeTitle}) + +First topic is: ${topicTitle}`; + + console.log(`Generating '${topicTitle}'...`); + + return new Promise((resolve, reject) => { + openai.chat.completions + .create({ + model: 'gpt-4', + messages: [ + { + role: 'user', + content: prompt, + }, + ], + }) + .then((response) => { + const article = response.choices[0].message.content; + + resolve(article); + }) + .catch((err) => { + reject(err); + }); + }); +} + +async function writeFileForGroup(group, topicUrlToPathMapping) { + const topicId = group?.properties?.controlName; + const topicTitle = group?.children?.controls?.control + ?.filter((control) => control?.typeID === 'Label') + .map((control) => control?.properties?.text) + .join(' ') + .toLowerCase(); + + const currTopicUrl = `/${topicId}`; + if (currTopicUrl.startsWith('/check:')) { + return; + } + + const contentFilePath = topicUrlToPathMapping[currTopicUrl]; + + if (!contentFilePath) { + console.log(`Missing file for: ${currTopicUrl}`); + return; + } + + const currentFileContent = fs.readFileSync(contentFilePath, 'utf8'); + const isFileEmpty = currentFileContent.replace(/^#.+/, ``).trim() === ''; + + if (!isFileEmpty) { + console.log(`Ignoring ${topicId}. Not empty.`); + return; + } + + let newFileContent = `# ${topicTitle}`; + + if (!OPEN_AI_API_KEY) { + console.log(`Writing ${topicId}..`); + + fs.writeFileSync(contentFilePath, newFileContent, 'utf8'); + return; + } + + if (!topicTitle) { + console.log(`Skipping ${topicId}. No title.`); + return; + } + + const topicContent = await writeTopicContent(topicTitle); + newFileContent = `${topicContent}`; + + console.log(`Writing ${topicId}..`); + fs.writeFileSync(contentFilePath, newFileContent, 'utf8'); + + // console.log(currentFileContent); + // console.log(currTopicUrl); + // console.log(topicTitle); + // console.log(topicUrlToPathMapping[currTopicUrl]); +} + +async function run() { + const topicUrlToPathMapping = getFilesInFolder(BEST_PRACTICE_CONTENT_DIR); + + const bestPracticeJson = require( + path.join(ALL_BEST_PRACTICES_DIR, `${bestPracticeId}/${bestPracticeId}`), + ); + + const groups = bestPracticeJson?.mockup?.controls?.control?.filter( + (control) => + control.typeID === '__group__' && + !control.properties?.controlName?.startsWith('ext_link'), + ); + + if (!OPEN_AI_API_KEY) { + console.log('----------------------------------------'); + console.log('OPEN_AI_API_KEY not found. Skipping openai api calls...'); + console.log('----------------------------------------'); + } + + const writePromises = []; + for (let group of groups) { + writePromises.push(writeFileForGroup(group, topicUrlToPathMapping)); + } + + console.log('Waiting for all files to be written...'); + await Promise.all(writePromises); +} + +run() + .then(() => { + console.log('Done'); + }) + .catch((err) => { + console.error(err); + process.exit(1); + }); diff --git a/scripts/best-practice-dirs.cjs b/scripts/best-practice-dirs.cjs new file mode 100644 index 000000000000..a55efee22f65 --- /dev/null +++ b/scripts/best-practice-dirs.cjs @@ -0,0 +1,157 @@ +const fs = require('fs'); +const path = require('path'); + +const CONTENT_DIR = path.join(__dirname, '../content'); +// Directory containing the best-practices +const BEST_PRACTICE_CONTENT_DIR = path.join( + __dirname, + '../src/data/best-practices', +); +const bestPracticeId = process.argv[2]; + +const allowedBestPracticeId = fs.readdirSync(BEST_PRACTICE_CONTENT_DIR); +if (!bestPracticeId) { + console.error('bestPractice is required'); + process.exit(1); +} + +if (!allowedBestPracticeId.includes(bestPracticeId)) { + console.error(`Invalid best practice key ${bestPracticeId}`); + console.error(`Allowed keys are ${allowedBestPracticeId.join(', ')}`); + process.exit(1); +} + +// Directory holding the best parctice content files +const bestPracticeDirName = fs + .readdirSync(BEST_PRACTICE_CONTENT_DIR) + .find((dirName) => dirName.replace(/\d+-/, '') === bestPracticeId); + +if (!bestPracticeDirName) { + console.error('Best practice directory not found'); + process.exit(1); +} + +const bestPracticeDirPath = path.join( + BEST_PRACTICE_CONTENT_DIR, + bestPracticeDirName, +); +const bestPracticeContentDirPath = path.join( + BEST_PRACTICE_CONTENT_DIR, + bestPracticeDirName, + 'content', +); + +// If best practice content already exists do not proceed as it would override the files +if (fs.existsSync(bestPracticeContentDirPath)) { + console.error( + `Best Practice content already exists @ ${bestPracticeContentDirPath}`, + ); + process.exit(1); +} + +function prepareDirTree(control, dirTree) { + // Directories are only created for groups + if (control.typeID !== '__group__') { + return; + } + + // e.g. 104-testing-your-apps:other-options + const controlName = control?.properties?.controlName || ''; + + // No directory for a group without control name + if ( + !controlName || + controlName.startsWith('check:') || + controlName.startsWith('ext_link:') + ) { + return; + } + + // e.g. ['testing-your-apps', 'other-options'] + const dirParts = controlName.split(':'); + + // Nest the dir path in the dirTree + let currDirTree = dirTree; + dirParts.forEach((dirPart) => { + currDirTree[dirPart] = currDirTree[dirPart] || {}; + currDirTree = currDirTree[dirPart]; + }); + + const childrenControls = control.children.controls.control; + // No more children + if (childrenControls.length) { + childrenControls.forEach((childControl) => { + prepareDirTree(childControl, dirTree); + }); + } + + return { dirTree }; +} + +const bestPractice = require( + path.join( + __dirname, + `../src/data/best-practices/${bestPracticeId}/${bestPracticeId}`, + ), +); +const controls = bestPractice.mockup.controls.control; + +// Prepare the dir tree that we will be creating +const dirTree = {}; + +controls.forEach((control) => { + prepareDirTree(control, dirTree); +}); + +/** + * @param parentDir Parent directory in which directory is to be created + * @param dirTree Nested dir tree to be created + * @param filePaths The mapping from groupName to file path + */ +function createDirTree(parentDir, dirTree, filePaths = {}) { + const childrenDirNames = Object.keys(dirTree); + const hasChildren = childrenDirNames.length !== 0; + + // @todo write test for this, yolo for now + const groupName = parentDir + .replace(bestPracticeContentDirPath, '') // Remove base dir path + .replace(/(^\/)|(\/$)/g, '') // Remove trailing slashes + .replaceAll('/', ':') // Replace slashes with `:` + .replace(/:\d+-/, ':'); + + const humanizedGroupName = groupName + .split(':') + .pop() + ?.replaceAll('-', ' ') + .replace(/^\w/, ($0) => $0.toUpperCase()); + + // If no children, create a file for this under the parent directory + if (!hasChildren) { + let fileName = `${parentDir}.md`; + fs.writeFileSync(fileName, `# ${humanizedGroupName}`); + + filePaths[groupName || 'home'] = fileName.replace(CONTENT_DIR, ''); + return filePaths; + } + + // There *are* children, so create the parent as a directory + // and create `index.md` as the content file for this + fs.mkdirSync(parentDir); + + let readmeFilePath = path.join(parentDir, 'index.md'); + fs.writeFileSync(readmeFilePath, `# ${humanizedGroupName}`); + + filePaths[groupName || 'home'] = readmeFilePath.replace(CONTENT_DIR, ''); + + // For each of the directory names, create a + // directory inside the given directory + childrenDirNames.forEach((dirName) => { + createDirTree(path.join(parentDir, dirName), dirTree[dirName], filePaths); + }); + + return filePaths; +} + +// Create directories and get back the paths for created directories +createDirTree(bestPracticeContentDirPath, dirTree); +console.log('Created best practice content directory structure'); diff --git a/scripts/cleanup-orphaned-content.ts b/scripts/cleanup-orphaned-content.ts new file mode 100644 index 000000000000..ad14f31bfc3d --- /dev/null +++ b/scripts/cleanup-orphaned-content.ts @@ -0,0 +1,259 @@ +import type { Node } from '@roadmapsh/editor'; +import matter from 'gray-matter'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { slugify } from '../src/lib/slugger'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); + +const args = process.argv.slice(2); +const roadmapSlug = args?.[0]?.replace('--roadmap-slug=', ''); + +if (!roadmapSlug) { + console.error('Usage: tsx scripts/cleanup-orphaned-content.ts --roadmap-slug='); + process.exit(1); +} + +interface OrphanEntry { + file: string; + reason: string; + duplicateOf: string; + action: 'deleted' | 'renamed'; + renamedTo?: string; +} + +async function fetchRoadmapJson(slug: string): Promise<{ nodes: Node[] }> { + try { + const response = await fetch( + `https://roadmap.sh/api/v1-official-roadmap/${slug}`, + ); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); + } + + const data = await response.json(); + if (data.error) { + throw new Error(data.error); + } + + return data; + } catch (err) { + console.log(` API fetch failed for ${slug}, falling back to local JSON`); + const localPath = path.join(ROADMAP_CONTENT_DIR, slug, `${slug}.json`); + const raw = await fs.readFile(localPath, 'utf-8'); + return JSON.parse(raw); + } +} + +async function isEditorRoadmap(slug: string): Promise { + const mdPath = path.join(ROADMAP_CONTENT_DIR, slug, `${slug}.md`); + try { + const raw = await fs.readFile(mdPath, 'utf-8'); + const { data } = matter(raw); + return data.renderer === 'editor'; + } catch { + return false; + } +} + +async function getEditorRoadmapSlugs(): Promise { + const allDirs = await fs.readdir(ROADMAP_CONTENT_DIR); + const results: string[] = []; + + for (const dir of allDirs) { + const stat = await fs.stat(path.join(ROADMAP_CONTENT_DIR, dir)).catch(() => null); + if (!stat?.isDirectory()) { + continue; + } + if (await isEditorRoadmap(dir)) { + results.push(dir); + } + } + + return results; +} + +function parseContentFilename(filename: string): { slug: string; nodeId: string } | null { + const match = filename.match(/^(.+)@([^.]+)\.md$/); + if (!match) { + return null; + } + return { slug: match[1], nodeId: match[2] }; +} + +async function cleanupRoadmap(slug: string): Promise { + console.log(`\nProcessing: ${slug}`); + + const contentDir = path.join(ROADMAP_CONTENT_DIR, slug, 'content'); + const stat = await fs.stat(contentDir).catch(() => null); + if (!stat?.isDirectory()) { + console.log(` No content directory found, skipping`); + return []; + } + + const roadmapData = await fetchRoadmapJson(slug); + if (!roadmapData?.nodes) { + console.log(` No nodes found in roadmap JSON, skipping`); + return []; + } + + const topicNodes = roadmapData.nodes.filter( + (node) => + node?.type && + ['topic', 'subtopic'].includes(node.type) && + node.data?.label, + ); + + const validNodeIds = new Set(); + const nodeIdToExpectedSlug = new Map(); + + for (const node of topicNodes) { + validNodeIds.add(node.id); + nodeIdToExpectedSlug.set(node.id, slugify(node.data.label as string)); + } + + const files = await fs.readdir(contentDir); + const orphans: OrphanEntry[] = []; + + const validFilesBySlug = new Map(); + for (const file of files) { + const parsed = parseContentFilename(file); + if (!parsed) { + continue; + } + if (validNodeIds.has(parsed.nodeId) && nodeIdToExpectedSlug.get(parsed.nodeId) === parsed.slug) { + validFilesBySlug.set(parsed.slug, file); + } + } + + for (const file of files) { + const parsed = parseContentFilename(file); + if (!parsed) { + continue; + } + + const { slug: fileSlug, nodeId } = parsed; + + if (validNodeIds.has(nodeId)) { + const expectedSlug = nodeIdToExpectedSlug.get(nodeId)!; + if (fileSlug === expectedSlug) { + continue; + } + + const correctFile = `${expectedSlug}@${nodeId}.md`; + const correctFileExists = files.includes(correctFile); + + if (correctFileExists) { + orphans.push({ + file, + reason: 'Same nodeId, old slug', + duplicateOf: correctFile, + action: 'deleted', + }); + } else { + orphans.push({ + file, + reason: 'Same nodeId, old slug', + duplicateOf: correctFile, + action: 'renamed', + renamedTo: correctFile, + }); + } + continue; + } + + const validFile = validFilesBySlug.get(fileSlug); + if (validFile) { + orphans.push({ + file, + reason: 'Same slug, old nodeId', + duplicateOf: validFile, + action: 'deleted', + }); + } else { + orphans.push({ + file, + reason: 'Topic removed from roadmap', + duplicateOf: 'N/A', + action: 'deleted', + }); + } + } + + for (const orphan of orphans) { + const filePath = path.join(contentDir, orphan.file); + if (orphan.action === 'renamed') { + const newPath = path.join(contentDir, orphan.renamedTo!); + await fs.rename(filePath, newPath); + console.log(` Renamed: ${orphan.file} -> ${orphan.renamedTo} (${orphan.reason})`); + } else { + await fs.unlink(filePath); + console.log(` Deleted: ${orphan.file} (${orphan.reason})`); + } + } + + if (orphans.length === 0) { + console.log(` No orphans found`); + } + + return orphans; +} + +async function main() { + const slugs = + roadmapSlug === '__all__' + ? await getEditorRoadmapSlugs() + : [roadmapSlug]; + + if (roadmapSlug !== '__all__') { + if (!(await isEditorRoadmap(roadmapSlug))) { + console.error(`${roadmapSlug} is not an editor-rendered roadmap`); + process.exit(1); + } + } + + console.log(`Processing ${slugs.length} roadmap(s)...`); + + const allOrphans = new Map(); + let totalOrphans = 0; + + for (const slug of slugs) { + const orphans = await cleanupRoadmap(slug); + if (orphans.length > 0) { + allOrphans.set(slug, orphans); + totalOrphans += orphans.length; + } + } + + const roadmapsAffected = allOrphans.size; + + let summary = `## Orphaned Content Cleanup\n\n`; + summary += `Cleaned up **${totalOrphans}** orphaned content file(s) across **${roadmapsAffected}** roadmap(s).\n\n`; + + for (const [slug, orphans] of allOrphans) { + summary += `### ${slug}\n\n`; + summary += `| File | Action | Reason | Duplicate Of |\n`; + summary += `|---|---|---|---|\n`; + for (const orphan of orphans) { + const action = orphan.action === 'renamed' ? `Renamed to \`${orphan.renamedTo}\`` : 'Deleted'; + const dupOf = orphan.duplicateOf === 'N/A' ? 'N/A' : `\`${orphan.duplicateOf}\``; + summary += `| \`${orphan.file}\` | ${action} | ${orphan.reason} | ${dupOf} |\n`; + } + summary += `\n`; + } + + const summaryPath = path.join(__dirname, '..', '.cleanup-summary.md'); + await fs.writeFile(summaryPath, summary); + console.log(`\nSummary written to .cleanup-summary.md`); + console.log(`Total: ${totalOrphans} orphaned file(s) cleaned up across ${roadmapsAffected} roadmap(s)`); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/scripts/close-issues.sh b/scripts/close-issues.sh new file mode 100755 index 000000000000..8e4e9822534f --- /dev/null +++ b/scripts/close-issues.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Fetch issues JSON data and parse it properly +issues=$(gh issue list --repo kamranahmedse/developer-roadmap --search "sort:created-asc" --state open --limit 500 --json number,title,createdAt,updatedAt,state,url,comments,reactionGroups,body | jq -c '.[]') + +# Loop through the issues and delete the ones created in 2022 and not updated in the past year +while IFS= read -r issue; do + created_at=$(echo "$issue" | jq -r '.createdAt') + updated_at=$(echo "$issue" | jq -r '.updatedAt') + issue_number=$(echo "$issue" | jq -r '.number') + issue_title=$(echo "$issue" | jq -r '.title') + reaction_groups=$(echo "$issue" | jq -r '.reactionGroups') + has_reactions=$(echo "$issue" | jq -r '.reactionGroups | length') + comment_count=$(echo "$issue" | jq -r '.comments | length') + body_characters=$(echo "$issue" | jq -r '.body | length') + + # if has empty body + if [[ "$created_at" == 2024-01* ]]; then + + comment="Hey there! + +Looks like this issue has been hanging around for a bit without much action. Our roadmaps have evolved quite a bit since then, and a bunch of older issues aren't really applicable anymore. So, we're tidying things up by closing out the older ones to keep our issue tracker nice and organized for future feedback. + +If you still think this problem needs addressing, don't hesitate to reopen the issue. We're here to help! + +Thanks a bunch!" + + gh issue comment "$issue_number" --body "$comment" + gh issue close "$issue_number" + fi +done <<< "$issues" diff --git a/scripts/compress-images.ts b/scripts/compress-images.ts new file mode 100644 index 000000000000..a155735eb5c0 --- /dev/null +++ b/scripts/compress-images.ts @@ -0,0 +1,153 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import sharp from 'sharp'; + +// ERROR: `__dirname` is not defined in ES module scope +// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const allowedFileExtensions = [ + '.avif', + '.gif', + '.heif', + '.jpeg', + '.png', + '.raw', + '.tiff', + '.webp', +] as const; +type AllowedFileExtension = (typeof allowedFileExtensions)[number]; + +const publicDir = path.join(__dirname, '../public'); +const cacheFile = path.join(__dirname, '/compressed-images.json'); + +const KB_IN_BYTES = 1024; +const COMPRESS_CONFIG = { + avif: { + chromaSubsampling: '4:4:4', + effort: 9.0, + }, + gif: { + effort: 10.0, + }, + jpeg: { + chromaSubsampling: '4:4:4', + mozjpeg: true, + trellisQuantisation: true, + overshootDeringing: true, + optimiseScans: true, + }, + png: { + compressionLevel: 9.0, + palette: true, + }, + raw: {}, + tiff: { + compression: 'lzw', + }, + webp: { + effort: 6.0, + }, +}; + +(async () => { + let cache: string[] = []; + const isCacheFileExists = await fs + .access(cacheFile) + .then(() => true) + .catch(() => false); + + if (isCacheFileExists) { + const cacheFileContent = await fs.readFile(cacheFile, 'utf8'); + cache = JSON.parse(cacheFileContent); + } + + const images = await recursiveGetImages(publicDir); + for (const image of images) { + const extname = path.extname(image).toLowerCase() as AllowedFileExtension; + if ( + !allowedFileExtensions.includes(extname) || + image.includes('node_modules') || + image.includes('.astro') || + image.includes('.vscode') || + image.includes('.git') + ) { + continue; + } + + const stats = await fs.stat(image); + const relativeImagePath = path.relative(path.join(__dirname, '..'), image); + if (cache.includes(relativeImagePath)) { + continue; + } + + const prevSize = stats.size / KB_IN_BYTES; + + let imageBuffer: Buffer | undefined; + switch (extname) { + case '.avif': + imageBuffer = await sharp(image).avif(COMPRESS_CONFIG.avif).toBuffer(); + break; + case '.heif': + imageBuffer = await sharp(image).heif().toBuffer(); + break; + case '.jpeg': + imageBuffer = await sharp(image).jpeg(COMPRESS_CONFIG.jpeg).toBuffer(); + break; + case '.png': + imageBuffer = await sharp(image).png(COMPRESS_CONFIG.png).toBuffer(); + break; + case '.raw': + imageBuffer = await sharp(image).raw().toBuffer(); + break; + case '.tiff': + imageBuffer = await sharp(image).tiff(COMPRESS_CONFIG.tiff).toBuffer(); + break; + case '.webp': + imageBuffer = await sharp(image).webp(COMPRESS_CONFIG.webp).toBuffer(); + break; + case '.gif': + continue; + } + + if (!imageBuffer) { + console.error(`❌ ${image} Compressing failed!`); + continue; + } + + const newSize = imageBuffer.length / KB_IN_BYTES; + const diff = prevSize - newSize; + if (diff <= 0) { + console.log(`📦 Skipped ${relativeImagePath}`); + continue; + } + + const diffPercent = ((diff / prevSize) * 100).toFixed(2); + console.log( + `📦 Reduced ${prevSize.toFixed(2)}KB → ${newSize.toFixed(2)}KB (${diff.toFixed(2)}KB, ${diffPercent}%) for ${relativeImagePath}`, + ); + + await fs.writeFile(image, imageBuffer); + cache.push(relativeImagePath); + + // So that we don't lose the cache if the script crashes + await fs.writeFile(cacheFile, JSON.stringify(cache, null, 2), 'utf8'); + } + + await fs.writeFile(cacheFile, JSON.stringify(cache, null, 2), 'utf8'); +})(); + +async function recursiveGetImages(dir: string): Promise { + const subdirs = await fs.readdir(dir, { withFileTypes: true }); + + const files = await Promise.all( + subdirs.map((dirent) => { + const res = path.resolve(dir, dirent.name); + return dirent.isDirectory() ? recursiveGetImages(res) : res; + }), + ); + + return Array.prototype.concat(...files); +} diff --git a/scripts/compressed-images.json b/scripts/compressed-images.json new file mode 100644 index 000000000000..a90d63ed088d --- /dev/null +++ b/scripts/compressed-images.json @@ -0,0 +1,199 @@ +[ + "public/authors/dmytrobol.png", + "public/authors/ebrahimbharmal007.png", + "public/authors/jesse.png", + "public/authors/peter-thaleikis.png", + "public/best-practices/api-security.png", + "public/best-practices/aws.png", + "public/best-practices/backend-performance.png", + "public/best-practices/frontend-performance.png", + "public/guides/asymptotic-notation.png", + "public/guides/avoid-render-blocking-javascript-with-async-defer.png", + "public/guides/backend-languages/back-vs-front.png", + "public/guides/backend-languages/backend-roadmap-part.png", + "public/guides/backend-languages/javascript-interest.png", + "public/guides/backend-languages/pypl-go-index.png", + "public/guides/bash-vs-shell.jpeg", + "public/guides/basic-authentication/chrome-basic-auth.png", + "public/guides/basic-authentication/safari-basic-auth.png", + "public/guides/basic-authentication.png", + "public/guides/big-o-notation.png", + "public/guides/character-encodings.png", + "public/guides/ci-cd.png", + "public/guides/dhcp.png", + "public/guides/jwt-authentication.png", + "public/guides/llms.png", + "public/guides/project-history.png", + "public/guides/proxy/forward-proxy.png", + "public/guides/proxy/proxy-example.png", + "public/guides/proxy/reverse-proxy.png", + "public/guides/random-numbers.png", + "public/guides/session-authentication.png", + "public/guides/sli-slo-sla.jpeg", + "public/guides/ssl-tls-https-ssh.png", + "public/guides/token-authentication.png", + "public/guides/torrent-client/download.png", + "public/guides/torrent-client/pipelining.png", + "public/guides/unfamiliar-codebase.png", + "public/guides/web-vitals.png", + "public/img/brand.png", + "public/img/default-avatar.png", + "public/img/features/in-progress.png", + "public/img/icons8-wand.gif", + "public/img/partners/ambassador-graphic-1.png", + "public/img/partners/ambassador-graphic-2.png", + "public/img/partners/apollo-workshop.png", + "public/img/partners/graphql-summit.png", + "public/img/partners/nginx.png", + "public/img/roadmap-editor.jpeg", + "public/img/system-design.png", + "public/img/team-promo/contact.png", + "public/img/team-promo/documentation.png", + "public/img/team-promo/growth-plans.png", + "public/img/team-promo/hero-img.png", + "public/img/team-promo/hero.png", + "public/img/team-promo/invite-members.png", + "public/img/team-promo/many-roadmaps.png", + "public/img/team-promo/onboarding.png", + "public/img/team-promo/our-roadmaps.png", + "public/img/team-promo/progress-tracking.png", + "public/img/team-promo/roadmap-editor.png", + "public/img/team-promo/sharing-settings.png", + "public/img/team-promo/skill-gap.png", + "public/img/team-promo/team-dashboard.png", + "public/img/team-promo/team-insights.png", + "public/img/team-promo/update-progress.png", + "public/manifest/apple-touch-icon.png", + "public/manifest/icon152.png", + "public/manifest/icon196.png", + "public/manifest/icon32.png", + "public/og-images/best-practices/api-security.png", + "public/og-images/best-practices/aws.png", + "public/og-images/best-practices/backend-performance.png", + "public/og-images/best-practices/code-review.png", + "public/og-images/best-practices/frontend-performance.png", + "public/og-images/guides/asymptotic-notation.png", + "public/og-images/guides/avoid-render-blocking-javascript-with-async-defer.png", + "public/og-images/guides/backend-developer-skills.png", + "public/og-images/guides/backend-developer-tools.png", + "public/og-images/guides/backend-languages.png", + "public/og-images/guides/basic-authentication.png", + "public/og-images/guides/basics-of-authentication.png", + "public/og-images/guides/big-o-notation.png", + "public/og-images/guides/character-encodings.png", + "public/og-images/guides/ci-cd.png", + "public/og-images/guides/consistency-patterns-in-distributed-systems.png", + "public/og-images/guides/design-patterns-for-humans.png", + "public/og-images/guides/dhcp-in-one-picture.png", + "public/og-images/guides/dns-in-one-picture.png", + "public/og-images/guides/free-resources-to-learn-llms.png", + "public/og-images/guides/history-of-javascript.png", + "public/og-images/guides/how-to-setup-a-jump-server.png", + "public/og-images/guides/http-basic-authentication.png", + "public/og-images/guides/http-caching.png", + "public/og-images/guides/introduction-to-llms.png", + "public/og-images/guides/journey-to-http2.png", + "public/og-images/guides/jwt-authentication.png", + "public/og-images/guides/levels-of-seniority.png", + "public/og-images/guides/oauth.png", + "public/og-images/guides/proxy-servers.png", + "public/og-images/guides/random-numbers.png", + "public/og-images/guides/scaling-databases.png", + "public/og-images/guides/session-authentication.png", + "public/og-images/guides/session-based-authentication.png", + "public/og-images/guides/setup-and-auto-renew-ssl-certificates.png", + "public/og-images/guides/single-command-database-setup.png", + "public/og-images/guides/ssl-tls-https-ssh.png", + "public/og-images/guides/sso.png", + "public/og-images/guides/token-authentication.png", + "public/og-images/guides/torrent-client.png", + "public/og-images/guides/unfamiliar-codebase.png", + "public/og-images/guides/what-are-web-vitals.png", + "public/og-images/guides/what-is-internet.png", + "public/og-images/guides/what-is-sli-slo-sla.png", + "public/og-images/guides/why-build-it-and-they-will-come-wont-work-anymore.png", + "public/og-images/roadmaps/android.png", + "public/og-images/roadmaps/angular.png", + "public/og-images/roadmaps/aspnet-core.png", + "public/og-images/roadmaps/aws.png", + "public/og-images/roadmaps/backend.png", + "public/og-images/roadmaps/blockchain.png", + "public/og-images/roadmaps/code-review.png", + "public/og-images/roadmaps/computer-science.png", + "public/og-images/roadmaps/cpp.png", + "public/og-images/roadmaps/cyber-security.png", + "public/og-images/roadmaps/data-analyst.png", + "public/og-images/roadmaps/datastructures-and-algorithms.png", + "public/og-images/roadmaps/design-system.png", + "public/og-images/roadmaps/devops.png", + "public/og-images/roadmaps/docker.png", + "public/og-images/roadmaps/flutter.png", + "public/og-images/roadmaps/frontend.png", + "public/og-images/roadmaps/full-stack.png", + "public/og-images/roadmaps/game-developer.png", + "public/og-images/roadmaps/golang.png", + "public/og-images/roadmaps/graphql.png", + "public/og-images/roadmaps/java.png", + "public/og-images/roadmaps/javascript.png", + "public/og-images/roadmaps/kubernetes.png", + "public/og-images/roadmaps/mlops.png", + "public/og-images/roadmaps/mongodb.png", + "public/og-images/roadmaps/nodejs.png", + "public/og-images/roadmaps/postgresql-dba.png", + "public/og-images/roadmaps/prompt-engineering.png", + "public/og-images/roadmaps/python.png", + "public/og-images/roadmaps/qa.png", + "public/og-images/roadmaps/react-native.png", + "public/og-images/roadmaps/react.png", + "public/og-images/roadmaps/rust.png", + "public/og-images/roadmaps/server-side-game-developer.png", + "public/og-images/roadmaps/software-architect.png", + "public/og-images/roadmaps/software-design-architecture.png", + "public/og-images/roadmaps/spring-boot.png", + "public/og-images/roadmaps/sql.png", + "public/og-images/roadmaps/system-design.png", + "public/og-images/roadmaps/technical-writer.png", + "public/og-images/roadmaps/typescript.png", + "public/og-images/roadmaps/ux-design.png", + "public/og-images/roadmaps/vue.png", + "public/og-images/sql-roadmap.png", + "public/roadmaps/android.png", + "public/roadmaps/aspnet-core.png", + "public/roadmaps/aws.png", + "public/roadmaps/backend.png", + "public/roadmaps/blockchain.png", + "public/roadmaps/computer-science.png", + "public/roadmaps/cpp.png", + "public/roadmaps/cyber-security.png", + "public/roadmaps/data-analyst.png", + "public/roadmaps/design-system.png", + "public/roadmaps/devops.png", + "public/roadmaps/docker.png", + "public/roadmaps/flutter.png", + "public/roadmaps/frontend.png", + "public/roadmaps/full-stack.png", + "public/roadmaps/game-developer.png", + "public/roadmaps/graphql.png", + "public/roadmaps/intro.png", + "public/roadmaps/java.png", + "public/roadmaps/javascript.png", + "public/roadmaps/kubernetes.png", + "public/roadmaps/mlops.png", + "public/roadmaps/mongodb.png", + "public/roadmaps/nodejs.png", + "public/roadmaps/python.png", + "public/roadmaps/qa.png", + "public/roadmaps/react.png", + "public/roadmaps/rust.png", + "public/roadmaps/software-architect.png", + "public/roadmaps/software-design-architecture.png", + "public/roadmaps/sql.png", + "public/roadmaps/technical-writer.png", + "public/roadmaps/typescript.png", + "public/roadmaps/ux-design.png", + "public/roadmaps/vue.png", + "public/og-images/roadmaps/ai-data-scientist.png", + "public/og-images/roadmaps/linux.png", + "public/roadmaps/ai-data-scientist.png", + "public/roadmaps/linux.png" +] \ No newline at end of file diff --git a/scripts/create-roadmap-labels.sh b/scripts/create-roadmap-labels.sh new file mode 100755 index 000000000000..12c908d3491d --- /dev/null +++ b/scripts/create-roadmap-labels.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +# get all the folder names inside src/data/roadmaps +roadmap_ids=$(ls src/data/roadmaps) + +# create a label for each roadmap name on github issues using gh cli +for roadmap_id in $roadmap_ids +do + random_color=$(openssl rand -hex 3) + gh label create "$roadmap_id" --color $random_color --description "Roadmap: $roadmap_id" +done \ No newline at end of file diff --git a/scripts/editor-roadmap-assets.ts b/scripts/editor-roadmap-assets.ts new file mode 100644 index 000000000000..ceeebcf0af2a --- /dev/null +++ b/scripts/editor-roadmap-assets.ts @@ -0,0 +1,60 @@ +import playwright from 'playwright'; + +// Usage: tsx ./scripts/editor-roadmap-dirs.ts + +const roadmapId = process.argv[2]; + +if (!roadmapId) { + console.error('Roadmap Id is required'); + process.exit(1); +} + +// Fetch roadmap data from API +const apiUrl = `https://roadmap.sh/api/v1-official-roadmap/${roadmapId}`; +console.log(`Fetching roadmap data from ${apiUrl}`); + +let roadmapData: any; +try { + const response = await fetch(apiUrl); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + roadmapData = await response.json(); +} catch (error) { + console.error(`Failed to fetch roadmap data: ${error}`); + process.exit(1); +} + +// Check if dimensions exist in the API response +if (!roadmapData.dimensions) { + console.error('Invalid roadmap data: missing dimensions'); + process.exit(1); +} + +console.log(`Launching chromium`); +const browser = await playwright.chromium.launch(); +const context = await browser.newContext(); +const page = await context.newPage(); + +const pageUrl = `http://localhost:3000/${roadmapId}/svg`; +console.log(`Opening page ${pageUrl}`); +await page.goto(pageUrl); +await page.waitForSelector('#resource-svg-wrap'); +await page.waitForTimeout(5000); +console.log(`Generating PDF ${pageUrl}`); +await page.pdf({ + path: `./public/pdfs/roadmaps/${roadmapId}.pdf`, + margin: { top: 0, right: 0, bottom: 0, left: 0 }, + height: roadmapData.dimensions?.height || 2000, + width: roadmapData.dimensions?.width || 968, +}); + +// @todo generate png from the pdf +console.log(`Generating png ${pageUrl}`); +await page.locator('#resource-svg-wrap>svg').screenshot({ + path: `./public/roadmaps/${roadmapId}.png`, + type: 'png', + scale: 'device', +}); + +await browser.close(); diff --git a/scripts/editor-roadmap-content-json.ts b/scripts/editor-roadmap-content-json.ts new file mode 100644 index 000000000000..ccc16c0c0aea --- /dev/null +++ b/scripts/editor-roadmap-content-json.ts @@ -0,0 +1,205 @@ +import type { Node } from '@roadmapsh/editor'; +import matter from 'gray-matter'; +import { HTMLElement, parse } from 'node-html-parser'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { htmlToMarkdown } from '../src/lib/html'; +import { markdownToHtml } from '../src/lib/markdown'; +import type { RoadmapFrontmatter } from '../src/lib/roadmap'; +import { slugify } from '../src/lib/slugger'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export const allowedLinkTypes = [ + 'video', + 'article', + 'opensource', + 'course', + 'website', + 'podcast', +] as const; + +export async function fetchRoadmapJson(roadmapId: string) { + const response = await fetch( + `https://roadmap.sh/api/v1-official-roadmap/${roadmapId}`, + ); + + if (!response.ok) { + throw new Error(`Failed to fetch roadmap json: ${response.statusText}`); + } + + const data = await response.json(); + if (data.error) { + throw new Error(`Failed to fetch roadmap json: ${data.error}`); + } + + return data; +} + +// Directory containing the roadmaps +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const allRoadmaps = await fs.readdir(ROADMAP_CONTENT_DIR); + +const editorRoadmapIds = new Set(); +for (const roadmapId of allRoadmaps) { + const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, + ); + const roadmapFrontmatterRaw = await fs.readFile( + roadmapFrontmatterDir, + 'utf-8', + ); + const { data } = matter(roadmapFrontmatterRaw); + + const roadmapFrontmatter = data as RoadmapFrontmatter; + if (roadmapFrontmatter.renderer === 'editor') { + editorRoadmapIds.add(roadmapId); + } +} + +const publicRoadmapsContentDir = path.join('./public', 'roadmap-content'); +const stats = await fs.stat(publicRoadmapsContentDir).catch(() => null); +if (!stats || !stats.isDirectory()) { + await fs.mkdir(publicRoadmapsContentDir, { recursive: true }); +} + +for (const roadmapId of editorRoadmapIds) { + console.log(`🚀 Starting ${roadmapId}`); + + const data = await fetchRoadmapJson(roadmapId).catch((error) => { + console.error(error); + return null; + }); + + if (!data) { + console.error(`Failed to fetch roadmap json: ${roadmapId}`); + continue; + } + + let { nodes } = data as { + nodes: Node[]; + }; + nodes = nodes.filter( + (node) => + node?.type && + ['topic', 'subtopic', 'todo'].includes(node.type) && + node.data?.label, + ); + + const roadmapContentDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + 'content', + ); + const stats = await fs.stat(roadmapContentDir).catch(() => null); + if (!stats || !stats.isDirectory()) { + await fs.mkdir(roadmapContentDir, { recursive: true }); + } + + const roadmapContentFiles = await fs.readdir(roadmapContentDir, { + recursive: true, + }); + + const contentMap: Record< + string, + { + title: string; + description: string; + links: { + title: string; + url: string; + type: string; + }[]; + } + > = {}; + + for (const node of nodes) { + const nodeDirPatternWithoutExt = `${slugify(node?.data?.label as string)}@${node.id}`; + const nodeDirPattern = `${nodeDirPatternWithoutExt}.md`; + if (!roadmapContentFiles.includes(nodeDirPattern)) { + contentMap[nodeDirPattern] = { + title: node?.data?.label as string, + description: '', + links: [], + }; + + continue; + } + + const content = await fs.readFile( + path.join(roadmapContentDir, nodeDirPattern), + 'utf-8', + ); + const html = markdownToHtml(content, false); + const rootHtml = parse(html); + + let ulWithLinks: HTMLElement | undefined; + rootHtml.querySelectorAll('ul').forEach((ul) => { + const listWithJustLinks = Array.from(ul.querySelectorAll('li')).filter( + (li) => { + const link = li.querySelector('a'); + return link && link.textContent?.trim() === li.textContent?.trim(); + }, + ); + + if (listWithJustLinks.length > 0) { + ulWithLinks = ul; + } + }); + + const listLinks = + ulWithLinks !== undefined + ? Array.from(ulWithLinks.querySelectorAll('li > a')) + .map((link) => { + const typePattern = /@([a-z.]+)@/; + let linkText = link.textContent || ''; + const linkHref = link.getAttribute('href') || ''; + let linkType = linkText.match(typePattern)?.[1] || 'article'; + linkType = allowedLinkTypes.includes(linkType as any) + ? linkType + : 'article'; + + linkText = linkText.replace(typePattern, ''); + + return { + title: linkText, + url: linkHref, + type: linkType, + }; + }) + .sort((a, b) => { + const order = [ + 'official', + 'opensource', + 'article', + 'video', + 'feed', + ]; + return order.indexOf(a.type) - order.indexOf(b.type); + }) + : []; + + const title = rootHtml.querySelector('h1'); + ulWithLinks?.remove(); + title?.remove(); + const htmlStringWithoutLinks = rootHtml.toString(); + const description = htmlToMarkdown(htmlStringWithoutLinks); + + contentMap[node.id] = { + title: node.data.label as string, + description, + links: listLinks, + }; + } + + await fs.writeFile( + path.join(publicRoadmapsContentDir, `${roadmapId}.json`), + JSON.stringify(contentMap, null, 2), + ); + console.log(`✅ Finished ${roadmapId}`); + console.log('-'.repeat(20)); +} diff --git a/scripts/editor-roadmap-content.ts b/scripts/editor-roadmap-content.ts new file mode 100644 index 000000000000..4c16676fe8cc --- /dev/null +++ b/scripts/editor-roadmap-content.ts @@ -0,0 +1,189 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { Edge, Node } from '@roadmapsh/editor'; +import matter from 'gray-matter'; +import type { RoadmapFrontmatter } from '../src/lib/roadmap'; +import { slugify } from '../src/lib/slugger'; +import OpenAI from 'openai'; +import { runPromisesInBatchSequentially } from '../src/lib/promise'; +import { httpGet } from '../src/lib/http'; + +// ERROR: `__dirname` is not defined in ES module scope +// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Usage: tsx ./scripts/editor-roadmap-content.ts +const OPEN_AI_API_KEY = process.env.OPEN_AI_API_KEY; +console.log('OPEN_AI_API_KEY:', OPEN_AI_API_KEY); +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const roadmapId = process.argv[2]; + +const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR); +if (!roadmapId) { + console.error('Roadmap Id is required'); + process.exit(1); +} + +if (!allowedRoadmapIds.includes(roadmapId)) { + console.error(`Invalid roadmap key ${roadmapId}`); + console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`); + process.exit(1); +} + +const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, +); +const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8'); +const { data } = matter(roadmapFrontmatterRaw); + +const roadmapFrontmatter = data as RoadmapFrontmatter; +if (!roadmapFrontmatter) { + console.error('Invalid roadmap frontmatter'); + process.exit(1); +} + +if (roadmapFrontmatter.renderer !== 'editor') { + console.error('Only Editor Rendered Roadmaps are allowed'); + process.exit(1); +} + +const { response: roadmapContent, error } = await httpGet( + `${import.meta.env.PUBLIC_API_URL}/v1-official-roadmap/${roadmapId}`, +); + +if (error) { + console.error(error); + process.exit(1); +} + +let { nodes, edges } = roadmapContent as { + nodes: Node[]; + edges: Edge[]; +}; +const enrichedNodes = nodes + .filter( + (node) => + node?.type && + ['topic', 'subtopic'].includes(node.type) && + node.data?.label, + ) + .map((node) => { + // Because we only need the parent id and title for subtopics + if (node.type !== 'subtopic') { + return node; + } + + const parentNodeId = + edges.find((edge) => edge.target === node.id)?.source || ''; + const parentNode = nodes.find((n) => n.id === parentNodeId); + + return { + ...node, + parentId: parentNodeId, + parentTitle: parentNode?.data?.label || '', + }; + }) as (Node & { parentId?: string; parentTitle?: string })[]; + +const roadmapContentDir = path.join(ROADMAP_CONTENT_DIR, roadmapId, 'content'); +const stats = await fs.stat(roadmapContentDir).catch(() => null); +if (!stats || !stats.isDirectory()) { + await fs.mkdir(roadmapContentDir, { recursive: true }); +} + +let openai: OpenAI | undefined; +if (OPEN_AI_API_KEY) { + openai = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + }); +} + +function writeTopicContent( + roadmapTitle: string, + childTopic: string, + parentTopic?: string, +) { + let prompt = `I will give you a topic and you need to write a brief introduction for that with regards to "${roadmapTitle}". Your format should be as follows and be in strictly markdown format: + +# (Put a heading for the topic without adding parent "Subtopic in Topic" or "Topic in Roadmap" or "Subtopic under XYZ" etc.) + +(Briefly explain the topic in one paragraph using simple english with regards to "${roadmapTitle}". Don't start with explaining how important the topic is with regard to "${roadmapTitle}". Don't say something along the lines of "XYZ plays a crucial role in ${roadmapTitle}". Don't include anything saying "In the context of ${roadmapTitle}". Instead, start with a simple explanation of the topic itself. For example, if the topic is "React", you can start with "React is a JavaScript library for building user interfaces." and then you can explain how it is used in "${roadmapTitle}".) +`; + + if (!parentTopic) { + prompt += `First topic is: ${childTopic}`; + } else { + prompt += `First topic is: ${childTopic} under ${parentTopic}`; + } + + return new Promise((resolve, reject) => { + openai?.chat.completions + .create({ + model: 'gpt-4', + messages: [ + { + role: 'user', + content: prompt, + }, + ], + }) + .then((response) => { + const article = response.choices[0].message.content; + + resolve(article); + }) + .catch((err) => { + reject(err); + }); + }); +} + +async function writeNodeContent(node: Node & { parentTitle?: string }) { + const nodeDirPattern = `${slugify(node?.data?.label as string)}@${node.id}.md`; + if (!roadmapContentFiles.includes(nodeDirPattern)) { + console.log(`Missing file for: ${nodeDirPattern}`); + return; + } + + const nodeDir = path.join(roadmapContentDir, nodeDirPattern); + const nodeContent = await fs.readFile(nodeDir, 'utf-8'); + const isFileEmpty = !nodeContent.replace(`# ${node.data.label}`, '').trim(); + if (!isFileEmpty) { + console.log(`❌ Ignoring ${nodeDirPattern}. Not empty.`); + return; + } + + const topic = node.data.label as string; + const parentTopic = node.parentTitle; + + console.log(`⏳ Generating content for ${topic}...`); + let newContentFile = ''; + if (OPEN_AI_API_KEY) { + newContentFile = (await writeTopicContent( + roadmapFrontmatter.title, + topic, + parentTopic, + )) as string; + } else { + newContentFile = `# ${topic}`; + } + + await fs.writeFile(nodeDir, newContentFile, 'utf-8'); + console.log(`✅ Content generated for ${topic}`); +} + +let roadmapContentFiles = await fs.readdir(roadmapContentDir, { + recursive: true, +}); + +if (!OPEN_AI_API_KEY) { + console.log('----------------------------------------'); + console.log('OPEN_AI_API_KEY not found. Skipping openai api calls...'); + console.log('----------------------------------------'); +} +const promises = enrichedNodes.map((node) => () => writeNodeContent(node)); +await runPromisesInBatchSequentially(promises, 20); +console.log('✅ All content generated'); diff --git a/scripts/editor-roadmap-dirs.ts b/scripts/editor-roadmap-dirs.ts new file mode 100644 index 000000000000..26857b17150e --- /dev/null +++ b/scripts/editor-roadmap-dirs.ts @@ -0,0 +1,104 @@ +import type { Node } from '@roadmapsh/editor'; +import matter from 'gray-matter'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { RoadmapFrontmatter } from '../src/lib/roadmap'; +import { slugify } from '../src/lib/slugger'; + +// ERROR: `__dirname` is not defined in ES module scope +// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Usage: tsx ./scripts/editor-roadmap-dirs.ts + +// Directory containing the roadmaps +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const roadmapId = process.argv[2]; + +const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR); +if (!roadmapId) { + console.error('Roadmap Id is required'); + process.exit(1); +} + +if (!allowedRoadmapIds.includes(roadmapId)) { + console.error(`Invalid roadmap key ${roadmapId}`); + console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`); + process.exit(1); +} + +const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, +); +const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8'); +const { data } = matter(roadmapFrontmatterRaw); + +const roadmapFrontmatter = data as RoadmapFrontmatter; +if (!roadmapFrontmatter) { + console.error('Invalid roadmap frontmatter'); + process.exit(1); +} + +if (roadmapFrontmatter.renderer !== 'editor') { + console.error('Only Editor Rendered Roadmaps are allowed'); + process.exit(1); +} + +export async function fetchRoadmapJson(roadmapId: string) { + const response = await fetch( + `https://roadmap.sh/api/v1-official-roadmap/${roadmapId}`, + ); + + if (!response.ok) { + throw new Error(`Failed to fetch roadmap json: ${response.statusText}`); + } + + const data = await response.json(); + if (data.error) { + throw new Error(`Failed to fetch roadmap json: ${data.error}`); + } + + return data; +} + +const roadmapContent = await fetchRoadmapJson(roadmapId); + +if (!roadmapContent) { + console.error(`Failed to fetch roadmap json: ${roadmapId}`); + process.exit(1); +} + +let { nodes } = roadmapContent as { + nodes: Node[]; +}; +nodes = nodes.filter( + (node) => + node?.type && ['topic', 'subtopic'].includes(node.type) && node.data?.label, +); + +const roadmapContentDir = path.join(ROADMAP_CONTENT_DIR, roadmapId, 'content'); +const stats = await fs.stat(roadmapContentDir).catch(() => null); +if (!stats || !stats.isDirectory()) { + await fs.mkdir(roadmapContentDir, { recursive: true }); +} + +const roadmapContentFiles = await fs.readdir(roadmapContentDir, { + recursive: true, +}); + +nodes.forEach(async (node, index) => { + const nodeDirPattern = `${slugify(node.data.label as string)}@${node.id}.md`; + if (roadmapContentFiles.includes(nodeDirPattern)) { + console.log(`Skipping ${nodeDirPattern}`); + return; + } + + await fs.writeFile( + path.join(roadmapContentDir, nodeDirPattern), + `# ${node.data.label}`, + ); +}); diff --git a/scripts/extract-guide-images.cjs b/scripts/extract-guide-images.cjs new file mode 100644 index 000000000000..22e4117686d7 --- /dev/null +++ b/scripts/extract-guide-images.cjs @@ -0,0 +1,44 @@ +// get all the base64 encoded images and save them to a file from the given markdown file + +const fs = require('fs'); +const path = require('path'); +const matter = require('gray-matter'); + +const guidePath = path.join(process.cwd(), 'src/data/guides'); +const tempDir = path.join(process.cwd(), '.temp'); + +const guideId = process.argv[2]; +if (!guideId) { + console.error('Guide ID is required'); + process.exit(1); +} + +const guideContent = fs.readFileSync( + path.join(guidePath, `${guideId}.md`), + 'utf8', +); + +// Create temp directory if it doesn't exist +const guideTempDir = path.join(tempDir, guideId); +if (!fs.existsSync(guideTempDir)) { + fs.mkdirSync(guideTempDir, { recursive: true }); +} + +const { data, content } = matter(guideContent); + +// Find all base64 image references in the content +const images = content.match(/\[(.+?)\]:\s+? { + const imageName = image.match(/\[(.+?)\]/)[1]; + const imageExtension = image.match(/ +const GEMINI_API_KEY = process.env.GEMINI_API_KEY; +console.log('GEMINI_API_KEY:', GEMINI_API_KEY); +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const roadmapId = process.argv[2]; + +const google = createGoogleGenerativeAI({ + apiKey: process.env.GEMINI_API_KEY, +}); + +const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR); +if (!roadmapId) { + console.error('Roadmap Id is required'); + process.exit(1); +} + +if (!allowedRoadmapIds.includes(roadmapId)) { + console.error(`Invalid roadmap key ${roadmapId}`); + console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`); + process.exit(1); +} + +const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, +); +const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8'); +const { data } = matter(roadmapFrontmatterRaw); + +const roadmapFrontmatter = data as RoadmapFrontmatter; +if (!roadmapFrontmatter) { + console.error('Invalid roadmap frontmatter'); + process.exit(1); +} + +if (roadmapFrontmatter.renderer !== 'editor') { + console.error('Only Editor Rendered Roadmaps are allowed'); + process.exit(1); +} + +const roadmapDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.json`, +); +const roadmapContent = await fs.readFile(roadmapDir, 'utf-8'); +let { nodes, edges } = JSON.parse(roadmapContent) as { + nodes: Node[]; + edges: Edge[]; +}; +const enrichedNodes = nodes + .filter( + (node) => + node?.type && + ['topic', 'subtopic'].includes(node.type) && + node.data?.label, + ) + .map((node) => { + // Because we only need the parent id and title for subtopics + if (node.type !== 'subtopic') { + return node; + } + + const parentNodeId = + edges.find((edge) => edge.target === node.id)?.source || ''; + const parentNode = nodes.find((n) => n.id === parentNodeId); + + return { + ...node, + parentId: parentNodeId, + parentTitle: parentNode?.data?.label || '', + }; + }) as (Node & { parentId?: string; parentTitle?: string })[]; + +const roadmapContentDir = path.join(ROADMAP_CONTENT_DIR, roadmapId, 'content'); +const stats = await fs.stat(roadmapContentDir).catch(() => null); +if (!stats || !stats.isDirectory()) { + await fs.mkdir(roadmapContentDir, { recursive: true }); +} + +function writeTopicContent( + roadmapTitle: string, + childTopic: string, + parentTopic?: string, +) { + const updatedTitle = roadmapTitle.replace('Roadmap', '').trim().replace('Developer', ''); + let prompt = `I will give you a topic and you need to write a brief introduction for that in "${roadmapTitle}". Your format should be as follows and be in strictly markdown format: + +# (Put a heading for the topic without adding parent "Subtopic in Topic" or "Topic in Roadmap" or "Subtopic under XYZ" etc.) + +(Briefly explain the topic in one paragraph using simple english. Don't start with explaining how important the topic is with regard to "${roadmapTitle}". Don't say something along the lines of "XYZ plays a crucial role in ${roadmapTitle}". Don't include anything saying "In the context of ${roadmapTitle}". Instead, start with a simple explanation of the topic itself. For example, if the topic is "React", you can start with "React is a JavaScript library for building user interfaces."".) +`; + + if (!parentTopic) { + prompt += `First topic is: ${childTopic}`; + } else { + prompt += `First topic is: "${parentTopic} > ${childTopic}"`; + } + + return new Promise((resolve, reject) => { + generateText({ + model: google('gemini-2.0-flash'), + prompt: prompt, + providerOptions: { + } + }) + .then((response) => { + const article = response.text; + + resolve(article); + }) + .catch((err) => { + reject(err); + }); + }); +} + +async function writeNodeContent(node: Node & { parentTitle?: string }) { + const nodeDirPattern = `${slugify(node.data.label)}@${node.id}.md`; + if (!roadmapContentFiles.includes(nodeDirPattern)) { + console.log(`Missing file for: ${nodeDirPattern}`); + return; + } + + const nodeDir = path.join(roadmapContentDir, nodeDirPattern); + const nodeContent = await fs.readFile(nodeDir, 'utf-8'); + const isFileEmpty = !nodeContent.replace(`# ${node.data.label}`, '').trim(); + if (!isFileEmpty) { + console.log(`❌ Ignoring ${nodeDirPattern}. Not empty.`); + return; + } + + const topic = node.data.label; + const parentTopic = node.parentTitle; + + console.log(`⏳ Generating content for ${topic}...`); + let newContentFile = ''; + if (GEMINI_API_KEY) { + newContentFile = (await writeTopicContent( + roadmapFrontmatter.title, + topic, + parentTopic, + )) as string; + } else { + newContentFile = `# ${topic}`; + } + + await fs.writeFile(nodeDir, newContentFile, 'utf-8'); + console.log(`✅ Content generated for ${topic}`); +} + +let roadmapContentFiles = await fs.readdir(roadmapContentDir, { + recursive: true, +}); + +if (!GEMINI_API_KEY) { + console.log('----------------------------------------'); + console.log('GEMINI_API_KEY not found. Skipping gemini api calls...'); + console.log('----------------------------------------'); +} +const promises = enrichedNodes.map((node) => () => writeNodeContent(node)); +await runPromisesInBatchSequentially(promises, 20); +console.log('✅ All content generated'); diff --git a/scripts/generate-og-images.mjs b/scripts/generate-og-images.mjs new file mode 100644 index 000000000000..d6c49a347a78 --- /dev/null +++ b/scripts/generate-og-images.mjs @@ -0,0 +1,552 @@ +import path from 'node:path'; +import fs from 'node:fs/promises'; +import matter from 'gray-matter'; +import { html } from 'satori-html'; +import satori from 'satori'; +import sharp from 'sharp'; +import imageSize from 'image-size'; +import { Resvg } from '@resvg/resvg-js'; + +const ALL_ROADMAP_DIR = path.join(process.cwd(), '/src/data/roadmaps'); +const ALL_BEST_PRACTICE_DIR = path.join( + process.cwd(), + '/src/data/best-practices', +); +const ALL_GUIDE_DIR = path.join(process.cwd(), '/src/data/guides'); +const ALl_AUTHOR_DIR = path.join(process.cwd(), '/src/data/authors'); +const ALL_ROADMAP_IMAGE_DIR = path.join(process.cwd(), '/public/roadmaps'); +const ALL_BEST_PRACTICE_IMAGE_DIR = path.join( + process.cwd(), + '/public/best-practices', +); +const ALL_AUTHOR_IMAGE_DIR = path.join(process.cwd(), '/public'); + +const alreadyGeneratedImages = await fs.readdir( + path.join(process.cwd(), '/public/og-images'), + { + recursive: true, + }, +); + +async function getAllRoadmaps() { + const allRoadmapDirNames = await fs.readdir(ALL_ROADMAP_DIR); + + const allRoadmapFrontmatter = await Promise.all( + allRoadmapDirNames.map(async (roadmapDirName) => { + const roadmapDirPath = path.join( + ALL_ROADMAP_DIR, + roadmapDirName, + `${roadmapDirName}.md`, + ); + + const markdown = await fs.readFile(roadmapDirPath, 'utf8'); + const { data } = matter(markdown); + + return { + id: roadmapDirName, + title: data?.briefTitle, + description: data?.briefDescription, + }; + }), + ); + + return allRoadmapFrontmatter; +} + +async function getAllBestPractices() { + const allBestPracticeDirNames = await fs.readdir(ALL_BEST_PRACTICE_DIR); + + const allBestPracticeFrontmatter = await Promise.all( + allBestPracticeDirNames.map(async (bestPracticeDirName) => { + const bestPracticeDirPath = path.join( + ALL_BEST_PRACTICE_DIR, + bestPracticeDirName, + `${bestPracticeDirName}.md`, + ); + + const markdown = await fs.readFile(bestPracticeDirPath, 'utf8'); + const { data } = matter(markdown); + + return { + id: bestPracticeDirName, + title: data?.briefTitle, + description: data?.briefDescription, + }; + }), + ); + + return allBestPracticeFrontmatter; +} + +async function getAllGuides() { + const allGuideDirNames = await fs.readdir(ALL_GUIDE_DIR); + + const allGuideFrontmatter = await Promise.all( + allGuideDirNames.map(async (guideDirName) => { + const guideDirPath = path.join(ALL_GUIDE_DIR, guideDirName); + + const markdown = await fs.readFile(guideDirPath, 'utf8'); + const { data } = matter(markdown); + + return { + id: guideDirName?.replace('.md', ''), + title: data?.title, + description: data?.description, + authorId: data?.authorId, + }; + }), + ); + + return allGuideFrontmatter; +} + +async function getAllAuthors() { + const allAuthorDirNames = await fs.readdir(ALl_AUTHOR_DIR); + + const allAuthorFrontmatter = await Promise.all( + allAuthorDirNames.map(async (authorDirName) => { + const authorDirPath = path.join(ALl_AUTHOR_DIR, authorDirName); + + const markdown = await fs.readFile(authorDirPath, 'utf8'); + const { data } = matter(markdown); + + return { + id: authorDirName?.replace('.md', ''), + name: data?.name, + imageUrl: data?.imageUrl, + }; + }), + ); + + return allAuthorFrontmatter; +} + +async function getAllRoadmapImageIds() { + const allRoadmapImageDirNames = await fs.readdir(ALL_ROADMAP_IMAGE_DIR); + + return allRoadmapImageDirNames?.reduce((acc, image) => { + acc[image.replace(/(\.[^.]*)$/, '')] = image; + return acc; + }, {}); +} + +async function getAllBestPracticeImageIds() { + const allBestPracticeImageDirNames = await fs.readdir( + ALL_BEST_PRACTICE_IMAGE_DIR, + ); + + return allBestPracticeImageDirNames?.reduce((acc, image) => { + acc[image.replace(/(\.[^.]*)$/, '')] = image; + return acc; + }, {}); +} + +async function generateResourceOpenGraph() { + const allRoadmaps = (await getAllRoadmaps()).filter( + (roadmap) => !alreadyGeneratedImages.includes(`roadmaps/${roadmap.id}.png`), + ); + const allBestPractices = (await getAllBestPractices()).filter( + (bestPractice) => + !alreadyGeneratedImages.includes(`best-practices/${bestPractice.id}.png`), + ); + const allRoadmapImageIds = await getAllRoadmapImageIds(); + const allBestPracticeImageIds = await getAllBestPracticeImageIds(); + + const resources = []; + allRoadmaps.forEach((roadmap) => { + const hasImage = allRoadmapImageIds?.[roadmap.id]; + resources.push({ + type: 'roadmaps', + id: roadmap.id, + title: roadmap.title, + description: roadmap.description, + image: hasImage + ? path.join(ALL_ROADMAP_IMAGE_DIR, allRoadmapImageIds[roadmap.id]) + : null, + }); + }); + + allBestPractices.forEach((bestPractice) => { + const hasImage = allBestPracticeImageIds?.[bestPractice.id]; + resources.push({ + type: 'best-practices', + id: bestPractice.id, + title: bestPractice.title, + description: bestPractice.description, + image: hasImage + ? path.join( + ALL_BEST_PRACTICE_IMAGE_DIR, + allBestPracticeImageIds[bestPractice.id], + ) + : null, + }); + }); + + for (const resource of resources) { + if (!resource.image) { + let template = getRoadmapDefaultTemplate(resource); + if ( + hasSpecialCharacters(resource.title) || + hasSpecialCharacters(resource.description) + ) { + // For some reason special characters are not being rendered properly + // https://github.com/natemoo-re/satori-html/issues/20 + // So we need to unescape the html + template = JSON.parse(unescapeHtml(JSON.stringify(template))); + } + await generateOpenGraph( + template, + resource.type, + resource.id + '.png', + 'resvg', + ); + } else { + const image = await fs.readFile(resource.image); + const dimensions = imageSize(image); + + const widthRatio = 1200 / dimensions.width; + let width = dimensions.width * widthRatio * 0.85; + let height = dimensions.height * widthRatio * 0.85; + + let template = getRoadmapImageTemplate({ + ...resource, + image: `data:image/${dimensions.type};base64,${image.toString('base64')}`, + width, + height, + }); + + if ( + hasSpecialCharacters(resource.title) || + hasSpecialCharacters(resource.description) + ) { + // For some reason special characters are not being rendered properly + // https://github.com/natemoo-re/satori-html/issues/20 + // So we need to unescape the html + template = JSON.parse(unescapeHtml(JSON.stringify(template))); + } + + await generateOpenGraph(template, resource.type, resource.id + '.png'); + } + } +} + +async function generateGuideOpenGraph() { + const allGuides = (await getAllGuides()).filter( + (guide) => !alreadyGeneratedImages.includes(`guides/${guide.id}.png`), + ); + const allAuthors = await getAllAuthors(); + + for (const guide of allGuides) { + const author = allAuthors.find((author) => author.id === guide.authorId); + const image = + author?.imageUrl || 'https://roadmap.sh/img/default-avatar.png'; + const isExternalImage = image?.startsWith('http'); + let authorImageExtension = ''; + let authorAvatar; + if (!isExternalImage) { + authorAvatar = await fs.readFile(path.join(ALL_AUTHOR_IMAGE_DIR, image)); + authorImageExtension = image?.split('.')[1]; + } + + let template = getGuideTemplate({ + ...guide, + authorName: author.name, + authorAvatar: isExternalImage + ? image + : `data:image/${authorImageExtension};base64,${authorAvatar.toString('base64')}`, + }); + if ( + hasSpecialCharacters(guide.title) || + hasSpecialCharacters(guide.description) + ) { + // For some reason special characters are not being rendered properly + // https://github.com/natemoo-re/satori-html/issues/20 + // So we need to unescape the html + template = JSON.parse(unescapeHtml(JSON.stringify(template))); + } + await generateOpenGraph(template, 'guides', guide.id + '.png'); + } +} + +async function generateOpenGraph( + htmlString, + type, + fileName, + renderer = 'sharp', +) { + console.log('Started 🚀', `${type}/${fileName}`); + const svg = await satori(htmlString, { + width: 1200, + height: 630, + fonts: [ + { + name: 'balsamiq', + data: await fs.readFile( + path.join(process.cwd(), '/public/fonts/BalsamiqSans-Regular.ttf'), + ), + weight: 400, + style: 'normal', + }, + ], + }); + + await fs.mkdir(path.join(process.cwd(), '/public/og-images/' + type), { + recursive: true, + }); + // It will be used to generate the default image + // for some reasone sharp is not working with this + // FIXME: Investigate why sharp is not working with this + if (renderer === 'resvg') { + const resvg = new Resvg(svg, { + fitTo: { + mode: 'width', + value: 2500, + }, + }); + const pngData = resvg.render(); + const pngBuffer = pngData.asPng(); + await fs.writeFile( + path.join(process.cwd(), '/public/og-images/' + `${type}/${fileName}`), + pngBuffer, + ); + } else { + await sharp(Buffer.from(svg), { density: 150 }) + .png() + .toFile( + path.join(process.cwd(), '/public/og-images/' + `${type}/${fileName}`), + ); + } + + console.log('Completed ✅', `${type}/${fileName}`); +} + +await generateResourceOpenGraph(); +await generateGuideOpenGraph(); + +function getRoadmapDefaultTemplate({ title, description }) { + return html`
+
+
+
+
+
+
+ +
+
+
+
${title}
+
+ ${description} +
+
+ +
+
+
+ + + +
+
+ 7th most starred GitHub project +
+
+
+
+ + + + + + + + + +
+
+ Created and maintained by community +
+
+
+
+ + + + +
+
Up-to-date roadmap
+
+
+
+
+
`; +} + +function getRoadmapImageTemplate({ title, description, image, height, width }) { + return html`
+
+
+
+ ${title?.replace('&', `{"&"}`)} +
+
+ ${description} +
+
+
+ + +
`; +} + +function getGuideTemplate({ title, description, authorName, authorAvatar }) { + return html`
+
+
+
+
+
+
+ +
+
+
+
+ +
+ ${authorName} +
+
+
${title}
+
+ ${description} +
+
+
+
+
`; +} + +function unescapeHtml(html) { + return html + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/'/g, "'"); +} + +function hasSpecialCharacters(str) { + return /[&<>"]/.test(str); +} diff --git a/scripts/generate-renderer.sh b/scripts/generate-renderer.sh new file mode 100644 index 000000000000..11db6d24b310 --- /dev/null +++ b/scripts/generate-renderer.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -e + +# Remove old editor +rm -rf editor + +if [ ! -d ".temp/web-draw" ]; then + git clone ssh://git@github.com/roadmapsh/web-draw.git .temp/web-draw --depth 1 +fi + +# Make dir +mkdir -p packages/editor +mkdir -p packages/editor/dist + +# Copy the editor dist, package.json +cp -rf .temp/web-draw/packages/editor/dist packages/editor +cp -rf .temp/web-draw/packages/editor/package.json packages/editor + +# Remove temp directory +rm -rf .temp + +# Reinstall so that the editor which was setup gets used +rm -rf node_modules +pnpm install diff --git a/scripts/label-issues.sh b/scripts/label-issues.sh new file mode 100755 index 000000000000..3e4faa704b86 --- /dev/null +++ b/scripts/label-issues.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# Fetch issues JSON data and parse it properly +issues=$(gh issue list --repo kamranahmedse/developer-roadmap --search "sort:created-asc" --state open --limit 500 --json number,title,createdAt,updatedAt,state,url,comments,reactionGroups,body | jq -c '.[]') + +# checks the body of issue, identifies the slug from the roadmap URLs +# and labels the issue with the corresponding slug +while IFS= read -r issue; do + created_at=$(echo "$issue" | jq -r '.createdAt') + updated_at=$(echo "$issue" | jq -r '.updatedAt') + issue_number=$(echo "$issue" | jq -r '.number') + issue_title=$(echo "$issue" | jq -r '.title') + reaction_groups=$(echo "$issue" | jq -r '.reactionGroups') + has_reactions=$(echo "$issue" | jq -r '.reactionGroups | length') + comment_count=$(echo "$issue" | jq -r '.comments | length') + body_characters=$(echo "$issue" | jq -r '.body | length') + + # If the issue has no body, then skip it + if [ "$body_characters" -eq 0 ]; then + continue + fi + + # Extract the roadmap URLs from the issue body + roadmap_urls=$(echo "$issue" | jq -r '.body' | grep -o 'https://roadmap\.sh/[^ ]*') + + # If no roadmap URLs found, then skip it + if [ -z "$roadmap_urls" ]; then + continue + fi + + # URL is like https://roadmap.sh/frontend + # Extract the slug from the URL + slug_of_first_url=$(echo "$roadmap_urls" | head -n 1 | sed 's/https:\/\/roadmap\.sh\///') + + if [ -z "$slug_of_first_url" ]; then + continue + fi + + # Label the issue with the slug + gh issue edit "$issue_number" --add-label "$slug_of_first_url" +done <<< "$issues" diff --git a/scripts/migrate-content-repo-to-database.ts b/scripts/migrate-content-repo-to-database.ts new file mode 100644 index 000000000000..508e61bff37f --- /dev/null +++ b/scripts/migrate-content-repo-to-database.ts @@ -0,0 +1,255 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { OfficialRoadmapDocument } from '../src/queries/official-roadmap'; +import { parse } from 'node-html-parser'; +import { markdownToHtml } from '../src/lib/markdown'; +import { htmlToMarkdown } from '../src/lib/html'; +import matter from 'gray-matter'; +import type { RoadmapFrontmatter } from '../src/lib/roadmap'; +import { + allowedOfficialRoadmapTopicResourceType, + type AllowedOfficialRoadmapTopicResourceType, + type SyncToDatabaseTopicContent, +} from '../src/queries/official-roadmap-topic'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const args = process.argv.slice(2); +const secret = args + .find((arg) => arg.startsWith('--secret=')) + ?.replace('--secret=', ''); +if (!secret) { + throw new Error('Secret is required'); +} + +let roadmapJsonCache: Map = new Map(); +export async function fetchRoadmapJson( + roadmapId: string, +): Promise { + if (roadmapJsonCache.has(roadmapId)) { + return roadmapJsonCache.get(roadmapId)!; + } + + const response = await fetch( + `https://roadmap.sh/api/v1-official-roadmap/${roadmapId}`, + ); + + if (!response.ok) { + throw new Error( + `Failed to fetch roadmap json: ${response.statusText} for ${roadmapId}`, + ); + } + + const data = await response.json(); + if (data.error) { + throw new Error( + `Failed to fetch roadmap json: ${data.error} for ${roadmapId}`, + ); + } + + roadmapJsonCache.set(roadmapId, data); + return data; +} + +export async function syncContentToDatabase( + topics: SyncToDatabaseTopicContent[], +) { + const response = await fetch( + `https://roadmap.sh/api/v1-sync-official-roadmap-topics`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + topics, + secret, + }), + }, + ); + + if (!response.ok) { + const error = await response.json(); + throw new Error( + `Failed to sync content to database: ${response.statusText} ${JSON.stringify(error, null, 2)}`, + ); + } + + return response.json(); +} + +// Directory containing the roadmaps +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const allRoadmaps = await fs.readdir(ROADMAP_CONTENT_DIR); + +const editorRoadmapIds = new Set(); +for (const roadmapId of allRoadmaps) { + const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, + ); + const roadmapFrontmatterRaw = await fs.readFile( + roadmapFrontmatterDir, + 'utf-8', + ); + const { data } = matter(roadmapFrontmatterRaw); + + const roadmapFrontmatter = data as RoadmapFrontmatter; + if (roadmapFrontmatter.renderer === 'editor') { + editorRoadmapIds.add(roadmapId); + } +} + +for (const roadmapId of editorRoadmapIds) { + try { + const roadmap = await fetchRoadmapJson(roadmapId); + + const files = await fs.readdir( + path.join(ROADMAP_CONTENT_DIR, roadmapId, 'content'), + ); + + console.log(`🚀 Starting ${files.length} files for ${roadmapId}`); + const topics: SyncToDatabaseTopicContent[] = []; + + for (const file of files) { + const isContentFile = file.endsWith('.md'); + if (!isContentFile) { + console.log(`🚨 Skipping ${file} because it is not a content file`); + continue; + } + + const nodeSlug = file.replace('.md', ''); + if (!nodeSlug) { + console.error(`🚨 Node id is required: ${file}`); + continue; + } + + const nodeId = nodeSlug.split('@')?.[1]; + if (!nodeId) { + console.error(`🚨 Node id is required: ${file}`); + continue; + } + + const node = roadmap.nodes.find((node) => node.id === nodeId); + if (!node) { + console.error(`🚨 Node not found: ${file}`); + continue; + } + + const filePath = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + 'content', + `${nodeSlug}.md`, + ); + + const fileExists = await fs + .stat(filePath) + .then(() => true) + .catch(() => false); + if (!fileExists) { + console.log(`🚨 File not found: ${filePath}`); + continue; + } + + const content = await fs.readFile(filePath, 'utf8'); + const html = markdownToHtml(content, false); + const rootHtml = parse(html); + + let ulWithLinks: HTMLElement | undefined; + rootHtml.querySelectorAll('ul').forEach((ul) => { + const listWithJustLinks = Array.from(ul.querySelectorAll('li')).filter( + (li) => { + const link = li.querySelector('a'); + return link && link.textContent?.trim() === li.textContent?.trim(); + }, + ); + + if (listWithJustLinks.length > 0) { + // @ts-expect-error - TODO: fix this + ulWithLinks = ul; + } + }); + + const listLinks: SyncToDatabaseTopicContent['resources'] = + ulWithLinks !== undefined + ? Array.from(ulWithLinks.querySelectorAll('li > a')) + .map((link) => { + const typePattern = /@([a-z.]+)@/; + let linkText = link.textContent || ''; + const linkHref = link.getAttribute('href') || ''; + let linkType = linkText.match(typePattern)?.[1] || 'article'; + linkType = allowedOfficialRoadmapTopicResourceType.includes( + linkType as any, + ) + ? linkType + : 'article'; + + linkText = linkText.replace(typePattern, ''); + + if (!linkText || !linkHref) { + return null; + } + + return { + title: linkText, + url: linkHref, + type: linkType as AllowedOfficialRoadmapTopicResourceType, + }; + }) + .filter((link) => link !== null) + .sort((a, b) => { + const order = [ + 'official', + 'opensource', + 'article', + 'video', + 'feed', + ]; + return order.indexOf(a!.type) - order.indexOf(b!.type); + }) + : []; + + const title = rootHtml.querySelector('h1'); + ulWithLinks?.remove(); + title?.remove(); + + const allParagraphs = rootHtml.querySelectorAll('p'); + if (listLinks.length > 0 && allParagraphs.length > 0) { + // to remove the view more see more from the description + const lastParagraph = allParagraphs[allParagraphs.length - 1]; + lastParagraph?.remove(); + } + + const htmlStringWithoutLinks = rootHtml.toString(); + const description = htmlToMarkdown(htmlStringWithoutLinks); + + const updatedDescription = + `# ${title?.textContent}\n\n${description}`.trim(); + + const label = node?.data?.label as string; + if (!label) { + console.error(`🚨 Label is required: ${file}`); + continue; + } + + topics.push({ + roadmapSlug: roadmapId, + nodeId, + description: updatedDescription, + resources: listLinks, + }); + } + + await syncContentToDatabase(topics); + console.log( + `✅ Synced ${topics.length} topics to database for ${roadmapId}`, + ); + } catch (error) { + console.error(error); + process.exit(1); + } +} diff --git a/scripts/migrate-editor-roadmap.ts b/scripts/migrate-editor-roadmap.ts new file mode 100644 index 000000000000..96c504b905af --- /dev/null +++ b/scripts/migrate-editor-roadmap.ts @@ -0,0 +1,76 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { Node } from '@roadmapsh/editor'; +import matter from 'gray-matter'; +import type { RoadmapFrontmatter } from '../src/lib/roadmap'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Directory containing the roadmaps +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const allRoadmaps = await fs.readdir(ROADMAP_CONTENT_DIR); + +const editorRoadmapIds = new Set(); +for (const roadmapId of allRoadmaps) { + const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, + ); + const roadmapFrontmatterRaw = await fs.readFile( + roadmapFrontmatterDir, + 'utf-8', + ); + const { data } = matter(roadmapFrontmatterRaw); + + const roadmapFrontmatter = data as RoadmapFrontmatter; + if (roadmapFrontmatter.renderer === 'editor') { + editorRoadmapIds.add(roadmapId); + } +} + +for (const roadmapId of editorRoadmapIds) { + const roadmapJSONDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.json`, + ); + + const roadmapJSONRaw = await fs.readFile(roadmapJSONDir, 'utf-8'); + const roadmapJSON = JSON.parse(roadmapJSONRaw); + + const roadmapNodes = roadmapJSON.nodes as Node[]; + const updatedNodes = roadmapNodes.map((node) => { + const width = +(node?.width || node?.style?.width || 0); + const height = +(node?.height || node?.style?.height || 0); + + const ADDITIONAL_WIDTH = 1; + // adding one `1px` in width to avoid the node to be cut in half + // this is a quick fix to avoid the issue + if (node?.style?.width) { + node.style.width = width + ADDITIONAL_WIDTH; + } + + if (node?.width) { + node.width = width + ADDITIONAL_WIDTH; + } + + return { + ...node, + measured: { + width: width + ADDITIONAL_WIDTH, + height, + }, + }; + }); + + const updatedRoadmapJSON = { + ...roadmapJSON, + nodes: updatedNodes, + }; + + const updatedRoadmapJSONString = JSON.stringify(updatedRoadmapJSON, null, 2); + await fs.writeFile(roadmapJSONDir, updatedRoadmapJSONString, 'utf-8'); +} diff --git a/scripts/official-roadmap-assets.ts b/scripts/official-roadmap-assets.ts new file mode 100644 index 000000000000..7affddd4f0c4 --- /dev/null +++ b/scripts/official-roadmap-assets.ts @@ -0,0 +1,62 @@ +import playwright from 'playwright'; +import type { OfficialRoadmapDocument } from '../src/queries/official-roadmap'; + +async function listAllRoadmaps(): Promise { + const response = await fetch( + 'https://roadmap.sh/api/v1-list-official-roadmaps', + ); + const mainRoadmaps = await response.json(); + const beginnerResponse = await fetch( + 'https://roadmap.sh/api/v1-list-official-beginner-roadmaps', + ); + const beginnerRoadmaps = await beginnerResponse.json(); + const data = [...mainRoadmaps, ...beginnerRoadmaps]; + return data; +} + +// Usage: tsx ./scripts/official-roadmap-assets.ts + +const roadmapSlug = process.argv?.[2]; + +const allRoadmaps = await listAllRoadmaps(); +const allowedRoadmapSlugs = allRoadmaps.map((roadmap) => roadmap.slug); + +const roadmapSlugs = roadmapSlug ? [roadmapSlug] : allowedRoadmapSlugs; + +console.log(`Launching chromium`); +const browser = await playwright.chromium.launch(); + +for (const roadmapSlug of roadmapSlugs) { + const roadmap = allRoadmaps.find((roadmap) => roadmap.slug === roadmapSlug); + if (!roadmap) { + console.error(`Roadmap ${roadmapSlug} not found`); + continue; + } + + const context = await browser.newContext(); + const page = await context.newPage(); + + const pageUrl = `http://roadmap.sh/${roadmapSlug}/svg`; + console.log(`Opening page ${pageUrl}`); + await page.goto(pageUrl); + await page.waitForSelector('#resource-svg-wrap'); + await page.waitForTimeout(5000); + + console.log(`Generating PDF ${pageUrl}`); + await page.pdf({ + path: `./public/pdfs/roadmaps/${roadmapSlug}.pdf`, + margin: { top: 0, right: 0, bottom: 0, left: 0 }, + height: roadmap?.dimensions?.height || 2000, + width: roadmap?.dimensions?.width || 968, + }); + + console.log(`Generating png ${pageUrl}`); + await page.locator('#resource-svg-wrap>svg').screenshot({ + path: `./public/roadmaps/${roadmapSlug}.png`, + type: 'png', + scale: 'device', + }); +} + +console.log(`Closing browser`); +await browser.close(); diff --git a/scripts/page-data-agg.cjs b/scripts/page-data-agg.cjs new file mode 100644 index 000000000000..e449e64c1c8a --- /dev/null +++ b/scripts/page-data-agg.cjs @@ -0,0 +1,129 @@ +const csv = require('csv-parser'); +const fs = require('fs'); +const path = require('path'); + +const csvFilePath = path.join(__dirname, '../data.csv'); + +const results = {}; +const pageSummary = {}; + +fs.createReadStream(csvFilePath) + .pipe( + csv({ + separator: ',', + mapHeaders: ({ header, index }) => + header.toLowerCase().replace(/ /g, '_'), + mapValues: ({ header, index, value }) => { + if (header === 'page') { + return ( + value + .replace(/"/g, '') + .replace(/'/g, '') + .replace(/`/g, '') + .replace(/\?r=/g, '#r#') + .replace(/\?.+?$/g, '') + .replace(/#r#/g, '?r=') + .replace(/\/$/g, '') || '/' + ); + } + + if (header !== 'month_of_year') { + return parseInt(value, 10); + } + + return value; + }, + }) + ) + .on('data', (data) => { + const { page, month_of_year, unique_pageviews, users } = data; + const pageData = results[page] || {}; + const existingPageMonthData = pageData[month_of_year] || {}; + + const existingViews = existingPageMonthData.views || 0; + const existingUsers = existingPageMonthData.users || 0; + + const newViews = existingViews + unique_pageviews; + const newUsers = existingUsers + users; + + pageData[month_of_year] = { + views: newViews, + users: newUsers, + }; + + results[page] = pageData; + + pageSummary[page] = pageSummary[page] || { views: 0, users: 0 }; + pageSummary[page].views += unique_pageviews; + pageSummary[page].users += users; + }) + .on('end', () => { + const csvHeader = [ + 'Page', + 'Jan 2022', + 'Feb 2022', + 'Mar 2022', + 'Apr 2022', + 'May 2022', + 'Jun 2022', + 'Jul 2022', + 'Aug 2022', + 'Sep 2022', + 'Oct 2022', + 'Nov 2022', + 'Dec 2022', + 'Jan 2023', + 'Feb 2023', + 'Mar 2023', + 'Apr 2023', + 'May 2023', + 'Jun 2023', + 'Jul 2023', + 'Aug 2023', + 'Sep 2023', + 'Oct 2023', + 'Nov 2023', + 'Dec 2023', + ]; + + const csvRows = Object.keys(pageSummary) + .filter(pageUrl => pageSummary[pageUrl].views > 10) + .filter(pageUrl => !['/upcoming', '/pdfs', '/signup', '/login', '/@'].includes(pageUrl)) + .sort((pageA, pageB) => { + const aViews = pageSummary[pageA].views; + const bViews = pageSummary[pageB].views; + + return bViews - aViews; + }) + .map((pageUrl) => { + const rawPageResult = results[pageUrl]; + const pageResultCsvRow = []; + + csvHeader.forEach((csvHeaderItem) => { + if (csvHeaderItem === 'Page') { + pageResultCsvRow.push(pageUrl); + return; + } + + const csvHeaderItemAlt = csvHeaderItem + .replace(/ /g, '_') + .toLowerCase(); + + const result = rawPageResult[csvHeaderItem || csvHeaderItemAlt] || {}; + const views = result.views || 0; + const users = result.users || 0; + + pageResultCsvRow.push(users); + }); + + return pageResultCsvRow; + }); + + const finalCsvRows = [csvHeader, ...csvRows]; + const csvRowStrings = finalCsvRows.map((row) => { + return row.join(','); + }); + + const csvString = csvRowStrings.join('\n'); + fs.writeFileSync(path.join(__dirname, '../data-agg.csv'), csvString); + }); diff --git a/scripts/readme.md b/scripts/readme.md new file mode 100644 index 000000000000..86cb552bbd06 --- /dev/null +++ b/scripts/readme.md @@ -0,0 +1,37 @@ +## CLI Tools + +> A bunch of CLI scripts to make the development easier + +## `roadmap-links.cjs` + +Generates a list of all the resources links in any roadmap file. + +## `compress-jsons.cjs` + +Compresses all the JSON files in the `public/jsons` folder + +## `update-sponsors.cjs` + +Updates the sponsor ads on each roadmap page with the latest sponsor information in the Excel sheet. + +## `roadmap-content.cjs` + +Currently, for any new roadmaps that we add, we do create the interactive roadmap but we end up leaving the content empty in the roadmap till we get time to fill it up manually. + +This script populates all the content files with some minimal content from OpenAI so that the users visiting the website have something to read in the interactive roadmap till we get time to fill it up manually. + +## `roadmap-dirs.cjs` + +This command is used to create the content folders and files for the interactivity of the roadmap. You can use the below command to generate the roadmap skeletons inside a roadmap directory: + +```bash +npm run roadmap-dirs [frontend|backend|devops|...] +``` + +For the content skeleton to be generated, we should have proper grouping, and the group names in the project files. You can follow the steps listed below in order to add the meta information to the roadmap. + +- Remove all the groups from the roadmaps through the project editor. Select all and press `cmd+shift+g` +- Identify the boxes that should be clickable and group them together with `cmd+shift+g` +- Assign the name to the groups. + - Group names have the format of `[sort]-[slug]` e.g. `100-internet`. Each group name should start with a number starting from 100 which helps with sorting of the directories and the files. Groups at the same level have the sequential sorting information. + - Each groups children have a separate group and have the name similar to `[sort]-[parent-slug]:[child-slug]` where sort refers to the sorting of the `child-slug` and not the parent. Also parent-slug does not need to have the sorting information as a part of slug e.g. if parent was `100-internet` the children would be `100-internet:how-does-the-internet-work`, `101-internet:what-is-http`, `102-internet:browsers`. diff --git a/scripts/refresh-assets.ts b/scripts/refresh-assets.ts new file mode 100644 index 000000000000..069f21a29d83 --- /dev/null +++ b/scripts/refresh-assets.ts @@ -0,0 +1,44 @@ +#!/usr/bin/env tsx + +import { execSync } from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; + +const roadmapsDir = path.join(process.cwd(), 'src/data/roadmaps'); + +const roadmapIds = fs.readdirSync(roadmapsDir) + .filter(item => { + const fullPath = path.join(roadmapsDir, item); + return fs.statSync(fullPath).isDirectory(); + }); + +console.log(`Found ${roadmapIds.length} roadmaps to process...`); + +const promises = roadmapIds.map(roadmapId => { + return new Promise((resolve, reject) => { + console.log(`Processing: ${roadmapId}`); + + try { + execSync(`npm run roadmap-assets ${roadmapId}`, { + stdio: 'inherit', + cwd: process.cwd() + }); + console.log(`✓ Completed: ${roadmapId}`); + resolve(roadmapId); + } catch (error) { + console.error(`✗ Failed: ${roadmapId}`, error); + reject(error); + } + }); +}); + +Promise.allSettled(promises).then(results => { + const successful = results.filter(r => r.status === 'fulfilled').length; + const failed = results.filter(r => r.status === 'rejected').length; + + console.log(`\n=== Summary ===`); + console.log(`✓ Successful: ${successful}/${roadmapIds.length}`); + if (failed > 0) { + console.log(`✗ Failed: ${failed}/${roadmapIds.length}`); + } +}); \ No newline at end of file diff --git a/scripts/rename-content.ts b/scripts/rename-content.ts new file mode 100644 index 000000000000..777762feacfc --- /dev/null +++ b/scripts/rename-content.ts @@ -0,0 +1,58 @@ +import fs from 'fs'; +import path from 'path'; + +const roadmapDirs = fs.readdirSync( + path.join(__dirname, '..', 'src', 'data', 'roadmaps'), +); + +roadmapDirs.forEach((roadmapDir) => { + const roadmapDirPath = path.join( + __dirname, + '..', + 'src', + 'data', + 'roadmaps', + roadmapDir, + 'content', + ); + + const roadmapDirContent = fs.readdirSync(roadmapDirPath); + + roadmapDirContent.forEach((content) => { + const contentPath = path.join(roadmapDirPath, content); + const contentStats = fs.statSync(contentPath); + + const oldName = path.basename(contentPath); + const newName = oldName.replace(/^(\d+)-/, ''); + + fs.renameSync(contentPath, path.join(roadmapDirPath, newName)); + + if (contentStats.isDirectory()) { + const contentDirContent = fs.readdirSync(contentPath); + + contentDirContent.forEach((contentDir) => { + const contentDirPath = path.join(contentPath, contentDir); + const contentDirStats = fs.statSync(contentDirPath); + + const oldName = path.basename(contentDirPath); + const newName = oldName.replace(/^(\d+)-/, ''); + + fs.renameSync(contentDirPath, path.join(contentPath, newName)); + + if (contentDirStats.isDirectory()) { + const contentDirContent = fs.readdirSync(contentDirPath); + + contentDirContent.forEach((contentDir) => { + const contentDirPath2 = path.join(contentDirPath, contentDir); + const contentDirStats2 = fs.statSync(contentDirPath2); + + const oldName2 = path.basename(contentDirPath2); + const newName2 = oldName2.replace(/^(\d+)-/, ''); + + fs.renameSync(contentDirPath2, path.join(contentDirPath, newName2)); + }); + } + }); + } + }); +}); diff --git a/scripts/roadmap-content.cjs b/scripts/roadmap-content.cjs new file mode 100644 index 000000000000..becfb68ed878 --- /dev/null +++ b/scripts/roadmap-content.cjs @@ -0,0 +1,187 @@ +const fs = require('fs'); +const path = require('path'); + +const OPEN_AI_API_KEY = process.env.OPEN_AI_API_KEY; +const ALL_ROADMAPS_DIR = path.join(__dirname, '../src/data/roadmaps'); + +const roadmapId = process.argv[2]; + +const allowedRoadmapIds = fs.readdirSync(ALL_ROADMAPS_DIR); +if (!roadmapId) { + console.error('roadmapId is required'); + process.exit(1); +} + +if (!allowedRoadmapIds.includes(roadmapId)) { + console.error(`Invalid roadmap key ${roadmapId}`); + console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`); + process.exit(1); +} + +const ROADMAP_CONTENT_DIR = path.join(ALL_ROADMAPS_DIR, roadmapId, 'content'); +const OpenAI = require('openai'); + +const openai = new OpenAI({ + apiKey: OPEN_AI_API_KEY, +}); + +function getFilesInFolder(folderPath, fileList = {}) { + const files = fs.readdirSync(folderPath); + + files.forEach((file) => { + const filePath = path.join(folderPath, file); + const stats = fs.statSync(filePath); + + if (stats.isDirectory()) { + getFilesInFolder(filePath, fileList); + } else if (stats.isFile()) { + const fileUrl = filePath + .replace(ROADMAP_CONTENT_DIR, '') // Remove the content folder + .replace(/\/\d+-/g, '/') // Remove ordering info `/101-ecosystem` + .replace(/\/index\.md$/, '') // Make the `/index.md` to become the parent folder only + .replace(/\.md$/, ''); // Remove `.md` from the end of file + + fileList[fileUrl] = filePath; + } + }); + + return fileList; +} + +/** + * Write the topic content for the given topic + * @param currTopicUrl + * @returns {Promise} + */ +function writeTopicContent(currTopicUrl) { + const [parentTopic, childTopic] = currTopicUrl + .replace(/^\d+-/g, '/') + .replace(/:/g, '/') + .replace(/^\//, '') + .split('/') + .slice(-2) + .map((topic) => topic.replace(/-/g, ' ')); + + const roadmapTitle = roadmapId.replace(/-/g, ' '); + + let prompt = `I will give you a topic and you need to write a brief introduction for that with regards to "${roadmapTitle}". Your format should be as follows and be in strictly markdown format: + +# (Put a heading for the topic without adding parent "Subtopic in Topic" or "Topic in Roadmap" etc.) + +(Write me a brief introduction for the topic with regards to "${roadmapTitle}") + +(add any code snippets ONLY if necessary and makes sense) + +`; + + if (!childTopic) { + prompt += `First topic is: ${parentTopic}`; + } else { + prompt += `First topic is: ${childTopic} under ${parentTopic}`; + } + + console.log(`Generating '${childTopic || parentTopic}'...`); + + return new Promise((resolve, reject) => { + openai.chat.completions + .create({ + model: 'gpt-4', + messages: [ + { + role: 'user', + content: prompt, + }, + ], + }) + .then((response) => { + const article = response.choices[0].message.content; + + resolve(article); + }) + .catch((err) => { + reject(err); + }); + }); +} + +async function writeFileForGroup(group, topicUrlToPathMapping) { + const topicId = group?.properties?.controlName; + const topicTitle = group?.children?.controls?.control?.find( + (control) => control?.typeID === 'Label', + )?.properties?.text; + const currTopicUrl = topicId?.replace(/^\d+-/g, '/')?.replace(/:/g, '/'); + if (!currTopicUrl) { + return; + } + + const contentFilePath = topicUrlToPathMapping[currTopicUrl]; + + if (!contentFilePath) { + console.log(`Missing file for: ${currTopicUrl}`); + return; + } + + const currentFileContent = fs.readFileSync(contentFilePath, 'utf8'); + const isFileEmpty = currentFileContent.replace(/^#.+/, ``).trim() === ''; + + if (!isFileEmpty) { + console.log(`Ignoring ${topicId}. Not empty.`); + return; + } + + let newFileContent = `# ${topicTitle}`; + + if (!OPEN_AI_API_KEY) { + console.log(`Writing ${topicId}..`); + + fs.writeFileSync(contentFilePath, newFileContent, 'utf8'); + return; + } + + const topicContent = await writeTopicContent(currTopicUrl); + + console.log(`Writing ${topicId}..`); + fs.writeFileSync(contentFilePath, topicContent, 'utf8'); + + // console.log(currentFileContent); + // console.log(currTopicUrl); + // console.log(topicTitle); + // console.log(topicUrlToPathMapping[currTopicUrl]); +} + +async function run() { + const topicUrlToPathMapping = getFilesInFolder(ROADMAP_CONTENT_DIR); + + const roadmapJson = require( + path.join(ALL_ROADMAPS_DIR, `${roadmapId}/${roadmapId}`), + ); + + const groups = roadmapJson?.mockup?.controls?.control?.filter( + (control) => + control.typeID === '__group__' && + !control.properties?.controlName?.startsWith('ext_link'), + ); + + if (!OPEN_AI_API_KEY) { + console.log('----------------------------------------'); + console.log('OPEN_AI_API_KEY not found. Skipping openai api calls...'); + console.log('----------------------------------------'); + } + + const writePromises = []; + for (let group of groups) { + writePromises.push(writeFileForGroup(group, topicUrlToPathMapping)); + } + + console.log('Waiting for all files to be written...'); + await Promise.all(writePromises); +} + +run() + .then(() => { + console.log('Done'); + }) + .catch((err) => { + console.error(err); + process.exit(1); + }); diff --git a/scripts/roadmap-dirs.cjs b/scripts/roadmap-dirs.cjs new file mode 100644 index 000000000000..f90c892c723a --- /dev/null +++ b/scripts/roadmap-dirs.cjs @@ -0,0 +1,167 @@ +const fs = require('fs'); +const path = require('path'); + +const CONTENT_DIR = path.join(__dirname, '../content'); +// Directory containing the roadmaps +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const roadmapId = process.argv[2]; + +const allowedRoadmapIds = fs.readdirSync(ROADMAP_CONTENT_DIR); +if (!roadmapId) { + console.error('roadmapId is required'); + process.exit(1); +} + +if (!allowedRoadmapIds.includes(roadmapId)) { + console.error(`Invalid roadmap key ${roadmapId}`); + console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`); + process.exit(1); +} + +// Directory holding the roadmap content files +const roadmapDirName = fs + .readdirSync(ROADMAP_CONTENT_DIR) + .find((dirName) => dirName.replace(/\d+-/, '') === roadmapId); + +if (!roadmapDirName) { + console.error('Roadmap directory not found'); + process.exit(1); +} + +const roadmapDirPath = path.join(ROADMAP_CONTENT_DIR, roadmapDirName); +const roadmapContentDirPath = path.join( + ROADMAP_CONTENT_DIR, + roadmapDirName, + 'content' +); + +// If roadmap content already exists do not proceed as it would override the files +if (fs.existsSync(roadmapContentDirPath)) { + console.error(`Roadmap content already exists @ ${roadmapContentDirPath}`); + process.exit(1); +} + +function prepareDirTree(control, dirTree, dirSortOrders) { + // Directories are only created for groups + if (control.typeID !== '__group__') { + return; + } + + // e.g. 104-testing-your-apps:other-options + const controlName = control?.properties?.controlName || ''; + // e.g. 104 + const sortOrder = controlName.match(/^\d+/)?.[0]; + + // No directory for a group without control name + if (!controlName || (!sortOrder && !controlName.startsWith('check:'))) { + return; + } + + // e.g. testing-your-apps:other-options + const controlNameWithoutSortOrder = controlName.replace(/^\d+-/, '').replace(/^check:/, ''); + // e.g. ['testing-your-apps', 'other-options'] + const dirParts = controlNameWithoutSortOrder.split(':'); + + // Nest the dir path in the dirTree + let currDirTree = dirTree; + dirParts.forEach((dirPart) => { + currDirTree[dirPart] = currDirTree[dirPart] || {}; + currDirTree = currDirTree[dirPart]; + }); + + dirSortOrders[controlNameWithoutSortOrder] = Number(sortOrder); + + const childrenControls = control.children.controls.control; + // No more children + if (childrenControls.length) { + childrenControls.forEach((childControl) => { + prepareDirTree(childControl, dirTree, dirSortOrders); + }); + } + + return { dirTree, dirSortOrders }; +} + +const roadmap = require(path.join( + __dirname, + `../src/data/roadmaps/${roadmapId}/${roadmapId}` +)); + +const controls = roadmap.mockup.controls.control; + +// Prepare the dir tree that we will be creating and also calculate the sort orders +const dirTree = {}; +const dirSortOrders = {}; + +controls.forEach((control) => { + prepareDirTree(control, dirTree, dirSortOrders); +}); + +/** + * @param parentDir Parent directory in which directory is to be created + * @param dirTree Nested dir tree to be created + * @param sortOrders Mapping from groupName to sort order + * @param filePaths The mapping from groupName to file path + */ +function createDirTree(parentDir, dirTree, sortOrders, filePaths = {}) { + const childrenDirNames = Object.keys(dirTree); + const hasChildren = childrenDirNames.length !== 0; + + // @todo write test for this, yolo for now + const groupName = parentDir + .replace(roadmapContentDirPath, '') // Remove base dir path + .replace(/(^\/)|(\/$)/g, '') // Remove trailing slashes + .replace(/(^\d+?-)/g, '') // Remove sorting information + .replaceAll('/', ':') // Replace slashes with `:` + .replace(/:\d+-/, ':'); + + const humanizedGroupName = groupName + .split(':') + .pop() + ?.replaceAll('-', ' ') + .replace(/^\w/, ($0) => $0.toUpperCase()); + + const sortOrder = sortOrders[groupName] || ''; + + // Attach sorting information to dirname + // e.g. /roadmaps/100-frontend/content/internet + // ———> /roadmaps/100-frontend/content/103-internet + if (sortOrder) { + parentDir = parentDir.replace(/(.+?)([^\/]+)?$/, `$1${sortOrder}-$2`); + } + + // If no children, create a file for this under the parent directory + if (!hasChildren) { + let fileName = `${parentDir}.md`; + fs.writeFileSync(fileName, `# ${humanizedGroupName}`); + + filePaths[groupName || 'home'] = fileName.replace(CONTENT_DIR, ''); + return filePaths; + } + + // There *are* children, so create the parent as a directory + // and create `index.md` as the content file for this + fs.mkdirSync(parentDir); + + let readmeFilePath = path.join(parentDir, 'index.md'); + fs.writeFileSync(readmeFilePath, `# ${humanizedGroupName}`); + + filePaths[groupName || 'home'] = readmeFilePath.replace(CONTENT_DIR, ''); + + // For each of the directory names, create a + // directory inside the given directory + childrenDirNames.forEach((dirName) => { + createDirTree( + path.join(parentDir, dirName), + dirTree[dirName], + dirSortOrders, + filePaths + ); + }); + + return filePaths; +} + +// Create directories and get back the paths for created directories +createDirTree(roadmapContentDirPath, dirTree, dirSortOrders); +console.log('Created roadmap content directory structure'); diff --git a/scripts/roadmap-links.cjs b/scripts/roadmap-links.cjs new file mode 100644 index 000000000000..256d89667dd0 --- /dev/null +++ b/scripts/roadmap-links.cjs @@ -0,0 +1,44 @@ +const fs = require('fs'); +const path = require('path'); + +const roadmapId = process.argv[2]; +if (!roadmapId) { + console.error('Error: roadmapId is required'); +} + +const fullPath = path.join(__dirname, `../src/data/roadmaps/${roadmapId}`); +if (!fs.existsSync(fullPath)) { + console.error(`Error: path not found: ${fullPath}!`); + process.exit(1); +} + +function readFiles(folderPath) { + const stats = fs.lstatSync(folderPath); + + if (stats.isFile()) { + return [folderPath]; + } + + const folderContent = fs.readdirSync(folderPath); + let files = []; + + for (const file of folderContent) { + const filePath = path.join(folderPath, file); + + files = [...files, ...readFiles(filePath)]; + } + + return files; +} + +const files = readFiles(fullPath); +let allLinks = []; + +files.forEach((file) => { + const fileContent = fs.readFileSync(file, 'utf-8'); + const matches = [...fileContent.matchAll(/\[[^\]]+]\((https?:\/\/[^)]+)\)/g)]; + + allLinks = [...allLinks, ...matches.map((match) => match[1])]; +}); + +allLinks.map((link) => console.log(link)); diff --git a/scripts/roadmap-tree-content.js b/scripts/roadmap-tree-content.js new file mode 100644 index 000000000000..087210257236 --- /dev/null +++ b/scripts/roadmap-tree-content.js @@ -0,0 +1,537 @@ +import OpenAI from 'openai'; +import path from 'path'; +import fs from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** + * @typedef {Object} Node + * @property {string} id - The unique identifier for the node + * @property {string} text - The text content of the node + */ + +const roadmapId = 'ai-agents'; + +/** @type {Node[]} */ +const nodes = [ + { + id: 'ZF5_5Y5zqa75Ov22JACX6', + text: 'AI Agents > Transformer Models and LLMs', + }, + { + id: 'GAjuWyJl9CI1nqXBp6XCf', + text: 'AI Agents > LLM Fundamentals > Model Mechanis > Tokenization', + }, + { + id: 'dyn1LSioema-Bf9lLTgUZ', + text: 'AI Agents > LLM Fundamentals > Model Mechanis > Context Windows', + }, + { + id: '1fiWPBV99E2YncqdCgUw2', + text: 'AI Agents > LLM Fundamentals > Model Mechanis > Token Based Pricing', + }, + { + id: 'L1zL1GzqjSAjF06pIIXhy', + text: 'AI Agents > LLM Fundamentals > Generation Controls > Temperature', + }, + { + id: 'icbp1NjurQfdM0dHnz6v2', + text: 'AI Agents > LLM Fundamentals > Generation Controls > Top-p', + }, + { + id: 'z_N-Y0zGkv8_qHPuVtimL', + text: 'AI Agents > LLM Fundamentals > Generation Controls > Frequency Penalty', + }, + { + id: 'Vd8ycw8pW-ZKvg5WYFtoh', + text: 'AI Agents > LLM Fundamentals > Generation Controls > Presence Penalty', + }, + { + id: 'K0G-Lw069jXUJwZqHtybd', + text: 'AI Agents > LLM Fundamentals > Generation Controls > Stopping Criteria', + }, + { + id: 'Bn_BkthrVX_vOuwQzvPZa', + text: 'AI Agents > LLM Fundamentals > Generation Controls > Max Length', + }, + { + id: 'DSJAhQhc1dQmBHQ8ZkTau', + text: 'AI Agents > Model Families and Licences > Open Weight Models', + }, + { + id: 'tJYmEDDwK0LtEux-kwp9B', + text: 'AI Agents > Model Families and Licences > Closed Weight Models', + }, + { + id: 'i2NE6haX9-7mdoV5LQ3Ah', + text: 'AI Agents > Understand the Basics > Streamed vs Unstreamed Responses', + }, + { + id: 'N3yZfUxphxjiupqGpyaS9', + text: 'AI Agents > Understand the Basics > Reasoning vs Standard Models', + }, + { + id: '5OW_6o286mj470ElFyJ_5', + text: 'AI Agents > Understand the Basics > Fine-tuning vs Prompt Engineering', + }, + { + id: 'UIm54UmICKgep6s8Itcyv', + text: 'AI Agents > Understand the Basics > Embeddings and Vector Search', + }, + { + id: 'qwVQOwBTLA2yUgRISzC8k', + text: 'AI Agents > Understand the Basics > Understand the Basics of RAG', + }, + { + id: 'B8dzg61TGaknuruBgkEJd', + text: 'AI Agents > Understand the Basics > Pricing of Common Models', + }, + { + id: 'aFZAm44nP5NefX_9TpT0A', + text: 'AI Agents > AI Agents 101 > What are AI Agents?', + }, + { + id: '2zsOUWJQ8e7wnoHmq1icG', + text: 'AI Agents > AI Agents 101 > What are Tools?', + }, + { + id: 'Eih4eybuYB3C2So8K0AT3', + text: 'AI Agents > AI Agents 101 > Agent Loop', + }, + { + id: 'LU76AhCYDjxdBhpMQ4eMU', + text: 'AI Agents > AI Agents 101 > Agent Loop > Perception / User Input', + }, + { + id: 'ycPRgRYR4lEBQr_xxHKnM', + text: 'AI Agents > AI Agents 101 > Agent Loop > Reason and Plan', + }, + { + id: 'sHYd4KsKlmw5Im3nQ19W8', + text: 'AI Agents > AI Agents 101 > Agent Loop > Acting / Tool Invocation', + }, + { + id: 'ZJTrun3jK3zBGOTm1jdMI', + text: 'AI Agents > AI Agents 101 > Agent Loop > Observation & Reflection', + }, + { + id: 'PPdAutqJF5G60Eg9lYBND', + text: 'AI Agents > AI Agents 101 > Example Usecases > Personal assistant', + }, + { + id: 'PK8w31GlvtmAuU92sHaqr', + text: 'AI Agents > AI Agents 101 > Example Usecases > Code generation', + }, + { + id: 'wKYEaPWNsR30TIpHaxSsq', + text: 'AI Agents > AI Agents 101 > Example Usecases > Data analysis', + }, + { + id: '5oLc-235bvKhApxzYFkEc', + text: 'AI Agents > AI Agents 101 > Example Usecases > Web Scraping / Crawling', + }, + { + id: 'ok8vN7VtCgyef5x6aoQaL', + text: 'AI Agents > AI Agents 101 > Example Usecases > NPC / Game AI', + }, + { + id: 'Y8EqzFx3qxtrSh7bWbbV8', + text: 'AI Agents > Prompt Engineering > What is Prompt Engineering', + }, + { + id: 'qFKFM2qNPEN7EoD0V-1SM', + text: 'AI Agents > Prompt Engineering > Writing Good Prompts > Be specific in what you want', + }, + { + id: '6I42CoeWX-kkFXTKAY7rw', + text: 'AI Agents > Prompt Engineering > Writing Good Prompts > Provide additional context', + }, + { + id: 'sUwdtOX550tSdceaeFPmF', + text: 'AI Agents > Prompt Engineering > Writing Good Prompts > Use relevant technical terms', + }, + { + id: 'yulzE4ZNLhXOgHhG7BtZQ', + text: 'AI Agents > Prompt Engineering > Writing Good Prompts > Use Examples in your Prompt', + }, + { + id: 'noTuUFnHSBzn7GKG9UZEi', + text: 'AI Agents > Prompt Engineering > Writing Good Prompts > Iterate and Test your Prompts', + }, + { + id: 'wwHHlEoPAx0TLxbtY6nMA', + text: 'AI Agents > Prompt Engineering > Writing Good Prompts > Specify Length, format etc', + }, + { + id: 'qakbxB8xe7Y8gejC5cZnK', + text: 'AI Agents > AI Agents 101 > Tools / Actions > Tool Definition', + }, + { + id: 'kBtqT8AduLoYDWopj-V9_', + text: 'AI Agents > Tools / Actions > Examples of Tools > Web Search', + }, + { + id: 'mS0EVCkWuPN_GkVPng4A2', + text: 'AI Agents > Tools / Actions > Examples of Tools > Code Execution / REPL', + }, + { + id: 'sV1BnA2-qBnXoKpUn-8Ub', + text: 'AI Agents > Tools / Actions > Examples of Tools > Database Queries', + }, + { + id: '52qxjZILV-X1isup6dazC', + text: 'AI Agents > Tools / Actions > Examples of Tools > API Requests > Tools / Actions > Examples of Tools > API Requests', + }, + { + id: 'qaNr5I-NQPnfrRH7ynGTl', + text: 'AI Agents > Tools / Actions > Examples of Tools > Email / Slack / SMS', + }, + { + id: 'BoJqZvdGam4cd6G6yK2IV', + text: 'AI Agents > Tools / Actions > Examples of Tools > File System Access', + }, + { + id: '1B0IqRNYdtbHDi1jHSXuI', + text: 'AI Agents > Model Context Protocol (MCP)', + }, + { + id: '9FryAIrWRHh8YlzKX3et5', + text: 'AI Agents > Model Context Protocol (MCP) > Core Components > MCP Hosts', + }, + { + id: 'CGVstUxVXLJcYZrwk3iNQ', + text: 'AI Agents > Model Context Protocol (MCP) > Core Components > MCP Client', + }, + { + id: 'yv_-87FVM7WKn5iv6LW9q', + text: 'AI Agents > Model Context Protocol (MCP) > Core Components > MCP Servers', + }, + { + id: '1NXIN-Hbjl5rPy_mqxQYW', + text: 'AI Agents > Model Context Protocol (MCP) > Creating MCP Servers', + }, + { + id: 'iBtJp24F_kJE3YlBsW60s', + text: 'AI Agents > Model Context Protocol (MCP) > Creating MCP Servers > Deployment Modes > Local Desktop', + }, + { + id: 'dHNMX3_t1KSDdAWqgdJXv', + text: 'AI Agents > Model Context Protocol (MCP) > Creating MCP Servers > Deployment Modes > Remote / Cloud', + }, + { + id: 'TBH_DZTAfR8Daoh-njNFC', + text: 'AI Agents > Agent Memory > What is Agent Memory?', + }, + { + id: 'M3U6RfIqaiut2nuOibY8W', + text: 'AI Agents > Agent Memory > Short Term Memory', + }, + { + id: 'Ue633fz6Xu2wa2-KOAtdP', + text: 'AI Agents > Agent Memory > What is Agent Memory? > Long Term Memory', + }, + { + id: 'EfCCNqLMJpWKKtamUa5gK', + text: 'AI Agents > Agent Memory > What is Agent Memory? > Episodic vs Semantic Memory', + }, + { + id: 'wkS4yOJ3JdZQE_yBID8K7', + text: 'AI Agents > Agent Memory > What is Agent Memory? > Maintaining Memory > RAG and Vector Databases', + }, + { + id: 'QJqXHV8VHPTnfYfmKPzW7', + text: 'AI Agents > Agent Memory > What is Agent Memory? > Maintaining Memory > User Profile Storage', + }, + { + id: 'jTDC19BTWCqxqMizrIJHr', + text: 'AI Agents > Agent Memory > Maintaining Memory > Summarization / Compression', + }, + { + id: 'm-97m7SI0XpBnhEE8-_1S', + text: 'AI Agents > Agent Memory > Maintaining Memory > Forgetting / Aging Strategies', + }, + { + id: 'cW8O4vLLKEG-Q0dE8E5Zp', + text: 'AI Agents > Agent Architectures > Common Architectures > RAG Agent', + }, + { + id: '53xDks6JQ33fHMa3XcuCd', + text: 'AI Agents > Agent Architectures > Common Architectures > ReAct (Reason + Act)', + }, + { + id: 'qwdh5pkBbrF8LKPxbZp4F', + text: 'AI Agents > Agent Architectures > Common Architectures > Chain of Thought (CoT)', + }, + { + id: '6YLCMWzystao6byCYCTPO', + text: 'AI Agents > Agent Architectures > Common Architectures > Planner Executor', + }, + { + id: 'Ep8RoZSy_Iq_zWXlGQLZo', + text: 'AI Agents > Agent Architectures > Common Architectures > DAG Agents', + }, + { + id: 'Nmy1PoB32DcWZnPM8l8jT', + text: 'AI Agents > Agent Architectures > Common Architectures > Tree-of-Thought', + }, + { + id: 'hj1adjkG9nalXKZ-Youn0', + text: 'AI Agents > Agent Architectures > Common Architectures > Tree-of-Thought', + }, + { + id: 'US6T5dXM8IY9V2qZnTOFW', + text: 'AI Agents > Building Agents > Manual (from scratch)', + }, + { + id: 'aafZxtjxiwzJH1lwHBODi', + text: 'AI Agents > Building Agents > LLM Native "Function Calling"', + }, + { + id: 'AQtxTTxmBpfl8BMgJbGzc', + text: 'AI Agents > Building Agents > LLM Native "Function Calling" > OpenAI Functions Calling', + }, + { + id: '37GBFVZ2J2d5r8bd1ViHq', + text: 'AI Agents > Building Agents > LLM Native "Function Calling" > OpenAI Assistant API', + }, + { + id: '_iIsBJTVS6OBf_dsdmbVO', + text: 'AI Agents > Building Agents > LLM Native "Function Calling" > Gemini Function Calling', + }, + { + id: '1EZFbDHA5J5_5BPMLMxXb', + text: 'AI Agents > Building Agents > LLM Native "Function Calling" > Anthropic Tool Use', + }, + { + id: 'Ka6VpCEnqABvwiF9vba7t', + text: 'AI Agents > Building Agents > Building Using Frameworks > Langchain', + }, + { + id: 'iEHF-Jm3ck-Iu85EbCoDi', + text: 'AI Agents > Building Agents > Building Using Frameworks > LlamaIndex', + }, + { + id: 'XS-FsvtrXGZ8DPrwOsnlI', + text: 'AI Agents > Building Agents > Building Using Frameworks > Haystack', + }, + { + id: '7YtnQ9-KIvGPSpDzEDexl', + text: 'AI Agents > Building Agents > Building Using Frameworks > AutoGen', + }, + { + id: 'uFPJqgU4qGvZyxTv-osZA', + text: 'AI Agents > Building Agents > Building Using Frameworks > CrewAI', + }, + { + id: 'eWxQiBrxIUG2JNcrdfIHS', + text: 'AI Agents > Building Agents > Building Using Frameworks > Smol Depot', + }, + { + id: 'v8qLnyFRnEumodBYxQSXQ', + text: 'AI Agents > Building Agents > Evaluation and Testing > Metrics to Track', + }, + { + id: 'qo_O4YAe4-MTP_ZJoXJHR', + text: 'AI Agents > Evaluation and Testing > Unit Testing for Individual Tools', + }, + { + id: 'P9-SiIda3TSjHsfkI5OUV', + text: 'AI Agents > Evaluation and Testing > Integration Testing for Flows', + }, + { + id: 'rHxdxN97ZcU7MPl8L1jzN', + text: 'AI Agents > Evaluation and Testing > Human in the Loop Evaluation', + }, + { + id: 'xp7TCTRE9HP60_rGzTUF6', + text: 'AI Agents > Evaluation and Testing > Frameworks > LangSmith', + }, + { + id: '0924QUH1wV7Mp-Xu0FAhF', + text: 'AI Agents > Evaluation and Testing > Frameworks > DeepEval', + }, + { + id: 'YzEDtGEaMaMWVt0W03HRt', + text: 'AI Agents > Evaluation and Testing > Frameworks > Ragas', + }, + { + id: 'zs6LM8WEnb0ERWpiaQCgc', + text: 'AI Agents > Debugging and Monitoring > Structured logging & tracing', + }, + { + id: 'zs6LM8WEnb0ERWpiaQCgc', + text: 'AI Agents > Debugging and Monitoring > Structured logging & tracing', + }, + { + id: 'SS8mGqf9wfrNqenIWvN8Z', + text: 'AI Agents > Observability Tools > LangSmith', + }, + { + id: 'MLxP5N0Vrmwh-kyvNeGXn', + text: 'AI Agents > Observability Tools > Helicone', + }, + { + id: 'UoIheaJlShiceafrWALEH', + text: 'AI Agents > Observability Tools > LangFuse', + }, + { + id: '7UqPXUzqKYXklnB3x-tsv', + text: 'AI Agents > Observability Tools > openllmetry', + }, + { + id: 'SU2RuicMUo8tiAsQtDI1k', + text: 'AI Agents > Security & Ethics > Prompt Injection / Jailbreaks', + }, + { + id: 'UVzLGXG6K7HQVHmw8ZAv2', + text: 'AI Agents > Security & Ethics > Tool sandboxing / Permissioning', + }, + { + id: 'rdlYBJNNyZUshzsJawME4', + text: 'AI Agents > Security & Ethics > Data Privacy + PII Redaction', + }, + { + id: 'EyLo2j8IQsIK91SKaXkmK', + text: 'AI Agents > Security & Ethics > Bias & Toxicity Guardrails', + }, + { + id: '63nsfJFO1BwjLX_ZVaPFC', + text: 'AI Agents > Security & Ethics > Safety + Red Team Testing', + }, +]; + +const OPENAI_API_KEY = process.env.OPENAI_API_KEY; + +if (!OPENAI_API_KEY) { + console.error('OPENAI_API_KEY is not set'); + process.exit(1); +} + +const openai = new OpenAI({ + apiKey: OPENAI_API_KEY, +}); + +const prompt = ` + You are a helpful assistant that can help me generate content for a roadmap tree. + You will be given a roadmap topic in the form of "Parent > Child > Leaf". You need + to generate a single paragraph explaining the topic. + Also, I hate it when you say "In the realm of..." + or "In the context of..." or "..in the context of..." or "when we talk about..." or something + similar. + IMPORTANT: Use simple and clear English. Avoid complex words and jargon when possible. + Write in a way that is easy to understand. Use short sentences and common words. +`; + +/** + * Generates content for a given node using OpenAI's GPT model + * @param {Node} node - The node to generate content for + * @returns {Promise} The generated content + */ +const generateContent = async (node) => { + try { + const content = await openai.chat.completions.create({ + model: 'o3', + messages: [ + { role: 'system', content: prompt }, + { + role: 'user', + content: `Node: ${node.text}`, + }, + ], + }); + + return content.choices[0].message.content; + } catch (error) { + console.error( + `Error generating content for node ${node.id}:`, + error.message, + ); + throw error; + } +}; + +const roadmapContentDir = path.join( + __dirname, + `../src/data/roadmaps/${roadmapId}/content`, +); +const contentFiles = fs.readdirSync(roadmapContentDir); + +/** + * Processes a single node by generating content and writing to file + * @param {Node} node - The node to process + * @param {string} roadmapContentDir - Directory path for content files + * @param {string[]} contentFiles - List of existing content files + * @returns {Promise} + */ +const processNode = async (node, roadmapContentDir, contentFiles) => { + try { + const nodeId = node.id; + const relevantFileName = contentFiles.find((file) => + file.endsWith(`${nodeId}.md`), + ); + + if (!relevantFileName) { + console.warn(`No matching file found for node ${nodeId}`); + return; + } + + const fileTitle = node.text + .replace(/\s+>\s+/g, '>') + .split('>') + .pop(); + + const content = await generateContent(node); + const filePath = path.join(roadmapContentDir, relevantFileName); + + await fs.promises.writeFile(filePath, `# ${fileTitle}\n\n${content}`); + console.log(`Successfully processed node ${nodeId}`); + } catch (error) { + console.error(`Failed to process node ${node.id}:`, error.message); + } +}; + +/** + * Main function to run the content generation + * @returns {Promise} + */ +const main = async () => { + try { + // Process nodes in parallel with concurrency limit + const BATCH_SIZE = 20; // Adjust based on API rate limits + + for (let i = 0; i < nodes.length; i += BATCH_SIZE) { + const batch = nodes.slice(i, i + BATCH_SIZE); + const promises = batch.map((node) => + processNode(node, roadmapContentDir, contentFiles), + ); + + await Promise.allSettled(promises); + + // Add a small delay between batches to avoid rate limiting + if (i + BATCH_SIZE < nodes.length) { + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + } + + console.log('Content generation completed'); + } catch (error) { + console.error('Fatal error in main process:', error); + process.exit(1); + } +}; + +// Add error handling for uncaught exceptions +process.on('uncaughtException', (error) => { + console.error('Uncaught Exception:', error); + process.exit(1); +}); + +process.on('unhandledRejection', (error) => { + console.error('Unhandled Rejection:', error); + process.exit(1); +}); + +main(); diff --git a/scripts/sync-content-to-repo.ts b/scripts/sync-content-to-repo.ts new file mode 100644 index 000000000000..b8fa571a6ae4 --- /dev/null +++ b/scripts/sync-content-to-repo.ts @@ -0,0 +1,113 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { slugify } from '../src/lib/slugger'; +import type { OfficialRoadmapDocument } from '../src/queries/official-roadmap'; +import type { OfficialRoadmapTopicContentDocument } from '../src/queries/official-roadmap-topic'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const args = process.argv.slice(2); +const roadmapSlug = args?.[0]?.replace('--roadmap-slug=', ''); +const secret = args?.[1]?.replace('--secret=', ''); +if (!secret) { + throw new Error('Secret is required'); +} + +if (!roadmapSlug || roadmapSlug === '__default__') { + throw new Error('Roadmap slug is required'); +} + +console.log(`🚀 Starting ${roadmapSlug}`); + +export async function roadmapTopics( + roadmapId: string, + secret: string, +): Promise { + const path = `https://roadmap.sh/api/v1-list-official-roadmap-topics/${roadmapId}?secret=${secret}`; + const response = await fetch(path); + if (!response.ok) { + throw new Error(`Failed to fetch roadmap topics: ${response.statusText}`); + } + + const data = await response.json(); + if (data.error) { + throw new Error(`Failed to fetch roadmap topics: ${data.error}`); + } + + return data; +} + +export async function fetchRoadmapJson( + roadmapId: string, +): Promise { + const response = await fetch( + `https://roadmap.sh/api/v1-official-roadmap/${roadmapId}`, + ); + + if (!response.ok) { + throw new Error(`Failed to fetch roadmap json: ${response.statusText}`); + } + + const data = await response.json(); + if (data.error) { + throw new Error(`Failed to fetch roadmap json: ${data.error}`); + } + + return data; +} + +// Directory containing the roadmaps +const ROADMAP_CONTENT_DIR = path.join( + __dirname, + '../src/data/roadmaps', + roadmapSlug, +); + +const allTopics = await roadmapTopics(roadmapSlug, secret); +const roadmap = await fetchRoadmapJson(roadmapSlug); +const { nodes } = roadmap; + +for (const topic of allTopics) { + const { nodeId } = topic; + + const node = nodes.find((node) => node.id === nodeId); + if (!node) { + console.error(`Node not found: ${nodeId}`); + continue; + } + + const label = node?.data?.label as string; + if (!label) { + console.error(`Label not found: ${nodeId}`); + continue; + } + + const topicSlug = `${slugify(label)}@${nodeId}.md`; + + const topicPath = path.join(ROADMAP_CONTENT_DIR, 'content', topicSlug); + const topicDir = path.dirname(topicPath); + const topicDirExists = await fs + .stat(topicDir) + .then(() => true) + .catch(() => false); + if (!topicDirExists) { + await fs.mkdir(topicDir, { recursive: true }); + } + + const topicContent = prepareTopicContent(topic); + await fs.writeFile(topicPath, topicContent); + console.log(`✅ Synced ${topicSlug}`); +} + +function prepareTopicContent(topic: OfficialRoadmapTopicContentDocument) { + const { description, resources = [] } = topic; + + let content = description; + if (resources.length > 0) { + content += `\n\nVisit the following resources to learn more:\n\n${resources.map((resource) => `- [@${resource.type}@${resource.title}](${resource.url})`).join('\n')}`; + } + + return content; +} diff --git a/scripts/sync-repo-to-database.ts b/scripts/sync-repo-to-database.ts new file mode 100644 index 000000000000..cdfc1c85ece9 --- /dev/null +++ b/scripts/sync-repo-to-database.ts @@ -0,0 +1,258 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { OfficialRoadmapDocument } from '../src/queries/official-roadmap'; +import { parse } from 'node-html-parser'; +import { markdownToHtml } from '../src/lib/markdown'; +import { htmlToMarkdown } from '../src/lib/html'; +import { + allowedOfficialRoadmapTopicResourceType, + type AllowedOfficialRoadmapTopicResourceType, + type SyncToDatabaseTopicContent, +} from '../src/queries/official-roadmap-topic'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const args = process.argv.slice(2); +const allFiles = args + .find((arg) => arg.startsWith('--files=')) + ?.replace('--files=', ''); +const secret = args + .find((arg) => arg.startsWith('--secret=')) + ?.replace('--secret=', ''); + +if (!secret) { + throw new Error('Secret is required'); +} + +let roadmapJsonCache: Map = new Map(); +export async function fetchRoadmapJson( + roadmapId: string, +): Promise { + if (roadmapJsonCache.has(roadmapId)) { + return roadmapJsonCache.get(roadmapId)!; + } + + const response = await fetch( + `https://roadmap.sh/api/v1-official-roadmap/${roadmapId}`, + { + headers: { + 'User-Agent': 'Mozilla/5.0 (compatible; roadmap-sync/1.0)', + }, + }, + ); + + if (!response.ok) { + throw new Error( + `Failed to fetch roadmap json: ${response.statusText} for ${roadmapId}`, + ); + } + + const data = await response.json(); + if (data.error) { + throw new Error( + `Failed to fetch roadmap json: ${data.error} for ${roadmapId}`, + ); + } + + roadmapJsonCache.set(roadmapId, data); + return data; +} + +export async function syncContentToDatabase( + topics: SyncToDatabaseTopicContent[], +) { + const response = await fetch( + `https://roadmap.sh/api/v1-sync-official-roadmap-topics`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'User-Agent': 'Mozilla/5.0 (compatible; roadmap-sync/1.0)', + }, + body: JSON.stringify({ + topics, + secret, + }), + }, + ); + + const responseText = await response.text(); + + if (!response.ok) { + throw new Error( + `Failed to sync content to database: ${response.status} ${response.statusText}\n${responseText}`, + ); + } + + try { + return JSON.parse(responseText); + } catch { + throw new Error( + `Failed to parse response as JSON: ${responseText.substring(0, 500)}`, + ); + } +} + +const files = + allFiles + ?.split(',') + .map((file) => file.trim()) + .filter(Boolean) || []; +if (files.length === 0) { + console.log('No files to sync'); + process.exit(0); +} + +console.log(`🚀 Starting ${files.length} files`); +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); + +try { + const topics: SyncToDatabaseTopicContent[] = []; + + for (const file of files) { + const isContentFile = file.endsWith('.md') && file.includes('content/'); + if (!isContentFile) { + console.log(`🚨 Skipping ${file} because it is not a content file`); + continue; + } + + const pathParts = file.replace('src/data/roadmaps/', '').split('/'); + const roadmapSlug = pathParts?.[0]; + if (!roadmapSlug) { + console.error(`🚨 Roadmap slug is required: ${file}`); + continue; + } + + const nodeSlug = pathParts?.[2]?.replace('.md', ''); + if (!nodeSlug) { + console.error(`🚨 Node id is required: ${file}`); + continue; + } + + const nodeId = nodeSlug.split('@')?.[1]; + if (!nodeId) { + console.error(`🚨 Node id is required: ${file}`); + continue; + } + + const roadmap = await fetchRoadmapJson(roadmapSlug); + const node = roadmap.nodes.find((node) => node.id === nodeId); + if (!node) { + console.error(`🚨 Node not found: ${file}`); + continue; + } + + const filePath = path.join( + ROADMAP_CONTENT_DIR, + roadmapSlug, + 'content', + `${nodeSlug}.md`, + ); + + const fileExists = await fs + .stat(filePath) + .then(() => true) + .catch(() => false); + if (!fileExists) { + console.log(`🚨 File not found: ${filePath}`); + continue; + } + + const content = await fs.readFile(filePath, 'utf8'); + const html = markdownToHtml(content, false); + const rootHtml = parse(html); + + let ulWithLinks: HTMLElement | undefined; + rootHtml.querySelectorAll('ul').forEach((ul) => { + const listWithJustLinks = Array.from(ul.querySelectorAll('li')).filter( + (li) => { + const link = li.querySelector('a'); + return link && link.textContent?.trim() === li.textContent?.trim(); + }, + ); + + if (listWithJustLinks.length > 0) { + // @ts-expect-error - TODO: fix this + ulWithLinks = ul; + } + }); + + const listLinks: SyncToDatabaseTopicContent['resources'] = + ulWithLinks !== undefined + ? Array.from(ulWithLinks.querySelectorAll('li > a')) + .map((link) => { + const typePattern = /@([a-z.]+)@/; + let linkText = link.textContent || ''; + const linkHref = link.getAttribute('href') || ''; + let linkType = linkText.match(typePattern)?.[1] || 'article'; + linkType = allowedOfficialRoadmapTopicResourceType.includes( + linkType as any, + ) + ? linkType + : 'article'; + + linkText = linkText.replace(typePattern, ''); + + return { + title: linkText, + url: linkHref, + type: linkType as AllowedOfficialRoadmapTopicResourceType, + }; + }) + .sort((a, b) => { + const order = [ + 'official', + 'opensource', + 'article', + 'video', + 'feed', + ]; + return order.indexOf(a.type) - order.indexOf(b.type); + }) + : []; + + const title = rootHtml.querySelector('h1'); + ulWithLinks?.remove(); + title?.remove(); + + const allParagraphs = rootHtml.querySelectorAll('p'); + if (listLinks.length > 0 && allParagraphs.length > 0) { + // to remove the view more see more from the description + const lastParagraph = allParagraphs[allParagraphs.length - 1]; + lastParagraph?.remove(); + } + + const htmlStringWithoutLinks = rootHtml.toString(); + const description = htmlToMarkdown(htmlStringWithoutLinks); + + const updatedDescription = + `# ${title?.textContent}\n\n${description}`.trim(); + + const label = node?.data?.label as string; + if (!label) { + console.error(`🚨 Label is required: ${file}`); + continue; + } + + topics.push({ + roadmapSlug, + nodeId, + description: updatedDescription, + resources: listLinks, + }); + } + + console.log(`📤 Syncing ${topics.length} topics to database...`); + await syncContentToDatabase(topics); + console.log(`✅ Successfully synced ${topics.length} topics`); +} catch (error) { + console.error('❌ Sync failed with error:'); + console.error(error); + if (error instanceof Error) { + console.error('\nError message:', error.message); + console.error('\nStack trace:', error.stack); + } + process.exit(1); +} diff --git a/scripts/sync-roadmap-to-database.ts b/scripts/sync-roadmap-to-database.ts new file mode 100644 index 000000000000..e836de4f66e1 --- /dev/null +++ b/scripts/sync-roadmap-to-database.ts @@ -0,0 +1,82 @@ +import { execSync } from 'node:child_process'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const args = process.argv.slice(2); +const roadmapSlug = args + .find((arg) => arg.startsWith('--roadmap=')) + ?.replace('--roadmap=', ''); +const secret = args + .find((arg) => arg.startsWith('--secret=')) + ?.replace('--secret=', ''); + +if (!roadmapSlug) { + console.error('❌ Roadmap slug is required. Use --roadmap='); + console.error(' Example: npm run sync:roadmap -- --roadmap=frontend --secret='); + process.exit(1); +} + +if (!secret) { + console.error('❌ Secret is required. Use --secret='); + console.error(' Example: npm run sync:roadmap -- --roadmap=frontend --secret='); + process.exit(1); +} + +const roadmapDir = path.join(__dirname, '../src/data/roadmaps', roadmapSlug); + +if (!fs.existsSync(roadmapDir)) { + console.error(`❌ Roadmap directory not found: ${roadmapDir}`); + process.exit(1); +} + +console.log(`🔍 Finding all content files in: ${roadmapDir}`); + +function getAllFiles(dir: string): string[] { + const files: string[] = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...getAllFiles(fullPath)); + } else { + files.push(fullPath); + } + } + + return files; +} + +const allFiles = getAllFiles(roadmapDir); +const relativeFiles = allFiles.map((file) => + file.replace(path.join(__dirname, '../'), ''), +); + +console.log(`📁 Found ${relativeFiles.length} files`); + +if (relativeFiles.length === 0) { + console.log('⚠️ No files found to sync'); + process.exit(0); +} + +const filesArg = relativeFiles.join(','); + +console.log(`🚀 Syncing roadmap "${roadmapSlug}" to database...`); + +try { + execSync( + `npx tsx ./scripts/sync-repo-to-database.ts --files="${filesArg}" --secret=${secret}`, + { + cwd: path.join(__dirname, '..'), + stdio: 'inherit', + }, + ); + console.log(`✅ Successfully synced roadmap "${roadmapSlug}" to database`); +} catch (error) { + console.error(`❌ Failed to sync roadmap "${roadmapSlug}" to database`); + process.exit(1); +} diff --git a/scripts/update-sponsors.cjs b/scripts/update-sponsors.cjs new file mode 100644 index 000000000000..55f24fda7751 --- /dev/null +++ b/scripts/update-sponsors.cjs @@ -0,0 +1,167 @@ +const path = require('path'); +const fs = require('fs'); +const yaml = require('js-yaml'); + +const apiKey = process.env.SPONSOR_SHEET_API_KEY; +const sheetId = process.env.SPONSOR_SHEET_ID; + +if (!apiKey || !sheetId) { + console.error('Missing API key or sheet ID'); + process.exit(1); +} + +const sheetRange = 'A3:I1001'; +const sheetUrl = `https://sheets.googleapis.com/v4/spreadsheets/${sheetId}/values/${sheetRange}?key=${apiKey}`; + +function removeAllSponsors(baseContentDir) { + console.log('------------------------'); + console.log('Removing sponsors from: ', baseContentDir); + console.log('------------------------'); + const dataDirPath = path.join(__dirname, '../src/data'); + const contentDirPath = path.join(dataDirPath, baseContentDir); + + const contentDir = fs.readdirSync(contentDirPath); + contentDir.forEach((content) => { + console.log('Removing sponsors from: ', content); + + const pageFilePath = path.join(contentDirPath, content, `${content}.md`); + const pageFileContent = fs.readFileSync(pageFilePath, 'utf8'); + + const frontMatterRegex = /---\n([\s\S]*?)\n---/; + + const existingFrontmatter = pageFileContent.match(frontMatterRegex)[1]; + const contentWithoutFrontmatter = pageFileContent + .replace(frontMatterRegex, ``) + .trim(); + + let frontmatterObj = yaml.load(existingFrontmatter); + delete frontmatterObj.sponsors; + + const newFrontmatter = yaml.dump(frontmatterObj, { + lineWidth: 10000, + forceQuotes: true, + quotingType: "'", + }); + const newContent = `---\n${newFrontmatter}---\n${contentWithoutFrontmatter}`; + + fs.writeFileSync(pageFilePath, newContent, 'utf8'); + }); +} + +function addPageSponsor({ + pageUrl, + company, + redirectUrl, + imageUrl, + adTitle, + adDescription, +}) { + const urlPart = pageUrl + .replace('https://roadmap.sh/', '') + .replace(/\?.+?$/, ''); + + const parentDir = urlPart.startsWith('best-practices/') + ? 'best-practices' + : 'roadmaps'; + const pageId = urlPart.replace(`${parentDir}/`, ''); + + const pageFilePath = path.join( + __dirname, + `../src/data/${parentDir}`, + `${pageId}/${pageId}.md` + ); + + if (!fs.existsSync(pageFilePath)) { + console.error(`Page file not found: ${pageFilePath}`); + process.exit(1); + } + + console.log(`Updating page: ${urlPart}`); + const pageFileContent = fs.readFileSync(pageFilePath, 'utf8'); + + const frontMatterRegex = /---\n([\s\S]*?)\n---/; + + const existingFrontmatter = pageFileContent.match(frontMatterRegex)[1]; + const contentWithoutFrontmatter = pageFileContent + .replace(frontMatterRegex, ``) + .trim(); + + let frontmatterObj = yaml.load(existingFrontmatter); + const sponsors = frontmatterObj.sponsors || []; + + const frontmatterValues = Object.entries(frontmatterObj); + const roadmapLabel = frontmatterObj.briefTitle; + + sponsors.push({ + url: redirectUrl, + title: adTitle, + imageUrl, + description: adDescription, + page: roadmapLabel, + company, + }); + + // Insert sponsor data at 10 index i.e. after + // roadmap dimensions in the frontmatter + frontmatterValues.splice(10, 0, ['sponsors', sponsors]); + + frontmatterObj = Object.fromEntries(frontmatterValues); + + const newFrontmatter = yaml.dump(frontmatterObj, { + lineWidth: 10000, + forceQuotes: true, + quotingType: "'", + }); + const newContent = `---\n${newFrontmatter}---\n\n${contentWithoutFrontmatter}`; + + fs.writeFileSync(pageFilePath, newContent, 'utf8'); +} + +// Remove sponsors from all roadmaps +removeAllSponsors('roadmaps'); +removeAllSponsors('best-practices'); + +console.log('------------------------'); +console.log('Adding sponsors'); +console.log('------------------------'); +fetch(sheetUrl) + .then((res) => res.json()) + .then((rawData) => { + const rows = rawData.values; + + rows.map((row) => { + // prettier-ignore + const [ + pageUrl, + company, + redirectUrl, + imageUrl, + adTitle, + adDescription, + startDate, + endDate, + isActive, + ] = row; + + const isConfiguredActive = isActive?.toLowerCase() === 'yes'; + const currentDate = new Date(); + const isDateInRange = + currentDate >= new Date(startDate) && currentDate <= new Date(endDate); + + if (!isConfiguredActive || !isDateInRange) { + return; + } + + addPageSponsor({ + pageUrl, + company, + redirectUrl, + imageUrl, + adTitle, + adDescription, + startDate, + endDate, + isActive, + }); + }); + }); diff --git a/scripts/warm-urls.sh b/scripts/warm-urls.sh new file mode 100755 index 000000000000..802b16b1edae --- /dev/null +++ b/scripts/warm-urls.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# Usage: warm-urls.sh +# Example: warm-urls.sh https://www.example.com/sitemap.xml + +# Check if sitemap url is provided +if [ -z "$1" ]; then + echo "Please provide sitemap URL" >&2 + exit 1 +fi + +# Get all URLs from sitemap +urls=$(curl -s "$1" | grep -o "[^<]*" | sed 's#\(.*\)#\1#') + +failed_urls=() + +# Warm up URLs +for url in $urls; do + # Fetch the og:image URL from the meta tags + og_image_url=$(curl -s "$url" | grep -o " /dev/null; then + failed_urls+=("$url") + fi + + # Warm up the og:image URL + if [ -n "$og_image_url" ]; then + echo "Warming up OG: $og_image_url" + if ! curl -s -I "$og_image_url" > /dev/null; then + failed_urls+=("$og_image_url") + fi + else + echo "No og:image found for $url" + fi +done + +# Print failed URLs +if [ ${#failed_urls[@]} -gt 0 ]; then + echo "Failed to warm up the following URLs:" >&2 + for failed_url in "${failed_urls[@]}"; do + echo "$failed_url" >&2 + done +fi diff --git a/sitemap.mjs b/sitemap.mjs new file mode 100644 index 000000000000..1a522e2bc48a --- /dev/null +++ b/sitemap.mjs @@ -0,0 +1,65 @@ +import path from 'node:path'; +import fs from 'node:fs/promises'; + +async function getRoadmapIds() { + return fs.readdir(path.join(process.cwd(), 'src/data/roadmaps')); +} + +async function getBestPracticesIds() { + return fs.readdir(path.join(process.cwd(), 'src/data/best-practices')); +} + +export function shouldIndexPage(pageUrl) { + return ![ + 'https://roadmap.sh/404', + 'https://roadmap.sh/terms', + 'https://roadmap.sh/privacy', + 'https://roadmap.sh/pdfs', + 'https://roadmap.sh/g', + ].includes(pageUrl); +} + +export async function serializeSitemap(item) { + const highPriorityPages = [ + 'https://roadmap.sh', + 'https://roadmap.sh/about', + 'https://roadmap.sh/roadmaps', + 'https://roadmap.sh/best-practices', + 'https://roadmap.sh/guides', + 'https://roadmap.sh/videos', + ...(await getRoadmapIds()).flatMap((id) => [ + `https://roadmap.sh/${id}`, + `https://roadmap.sh/${id}/topics`, + ]), + ...(await getBestPracticesIds()).map( + (id) => `https://roadmap.sh/best-practices/${id}` + ), + ]; + + // Roadmaps and other high priority pages + for (let pageUrl of highPriorityPages) { + if (item.url === pageUrl) { + return { + ...item, + // @ts-ignore + changefreq: 'monthly', + priority: 1, + }; + } + } + + // Guide and video pages + if ( + item.url.startsWith('https://roadmap.sh/guides') || + item.url.startsWith('https://roadmap.sh/videos') + ) { + return { + ...item, + // @ts-ignore + changefreq: 'monthly', + priority: 0.9, + }; + } + + return undefined; +} diff --git a/src/api/ai-roadmap.ts b/src/api/ai-roadmap.ts new file mode 100644 index 000000000000..9a4227f7150c --- /dev/null +++ b/src/api/ai-roadmap.ts @@ -0,0 +1,33 @@ +import { type APIContext } from 'astro'; +import { api } from './api.ts'; + +export type GetAIRoadmapBySlugResponse = { + id: string; + term: string; + title: string; + data: string; + isAuthenticatedUser: boolean; +}; + +export function aiRoadmapApi(context: APIContext) { + return { + getAIRoadmapBySlug: async function (roadmapSlug: string) { + return api(context).get( + `${import.meta.env.PUBLIC_API_URL}/v1-get-ai-roadmap-by-slug/${roadmapSlug}`, + ); + }, + }; +} + +export interface AICourseDocument { + _id: string; + userId: string; + title: string; + slug?: string; + keyword: string; + difficulty: string; + data: string; + viewCount: number; + createdAt: Date; + updatedAt: Date; +} \ No newline at end of file diff --git a/src/api/api.ts b/src/api/api.ts new file mode 100644 index 000000000000..911a2a9f2cc2 --- /dev/null +++ b/src/api/api.ts @@ -0,0 +1,153 @@ +import { TOKEN_COOKIE_NAME } from '../lib/jwt.ts'; +import type { APIContext } from 'astro'; + +type HttpOptionsType = RequestInit | { headers: Record }; + +type AppResponse = Record; + +export type FetchError = { + status: number; + message: string; +}; + +export type AppError = { + status: number; + message: string; + errors?: { message: string; location: string }[]; +}; + +export type ApiReturn = { + response?: ResponseType; + error?: ErrorType | FetchError; +}; + +export function api(context: APIContext) { + const token = context.cookies.get(TOKEN_COOKIE_NAME)?.value; + + async function apiCall( + url: string, + options?: HttpOptionsType, + ): Promise> { + try { + const response = await fetch(url, { + credentials: 'include', + ...options, + headers: new Headers({ + 'Content-Type': 'application/json', + Accept: 'application/json', + ...(token ? { Authorization: `Bearer ${token}` } : {}), + ...(options?.headers ?? {}), + }), + }); + + // @ts-ignore + const doesAcceptHtml = options?.headers?.['Accept'] === 'text/html'; + + const data = doesAcceptHtml + ? await response.text() + : await response.json(); + + if (response.ok) { + return { + response: data as ResponseType, + error: undefined, + }; + } + + // Logout user if token is invalid + if (data.status === 401) { + context.cookies.delete(TOKEN_COOKIE_NAME); + context.redirect(context.request.url); + + return { response: undefined, error: data as ErrorType }; + } + + if (data.status === 403) { + return { response: undefined, error: data as ErrorType }; + } + + return { + response: undefined, + error: data as ErrorType, + }; + } catch (error: any) { + return { + response: undefined, + error: { + status: 0, + message: error.message, + }, + }; + } + } + + return { + get: function apiGet( + url: string, + queryParams?: Record, + options?: HttpOptionsType, + ): Promise> { + const searchParams = new URLSearchParams(queryParams).toString(); + const queryUrl = searchParams ? `${url}?${searchParams}` : url; + + return apiCall(queryUrl, { + ...options, + method: 'GET', + }); + }, + post: async function apiPost< + ResponseType = AppResponse, + ErrorType = AppError, + >( + url: string, + body: Record, + options?: HttpOptionsType, + ): Promise> { + return apiCall(url, { + ...options, + method: 'POST', + body: JSON.stringify(body), + }); + }, + patch: async function apiPatch< + ResponseType = AppResponse, + ErrorType = AppError, + >( + url: string, + body: Record, + options?: HttpOptionsType, + ): Promise> { + return apiCall(url, { + ...options, + method: 'PATCH', + body: JSON.stringify(body), + }); + }, + put: async function apiPut< + ResponseType = AppResponse, + ErrorType = AppError, + >( + url: string, + body: Record, + options?: HttpOptionsType, + ): Promise> { + return apiCall(url, { + ...options, + method: 'PUT', + body: JSON.stringify(body), + }); + }, + delete: async function apiDelete< + ResponseType = AppResponse, + ErrorType = AppError, + >( + url: string, + options?: HttpOptionsType, + ): Promise> { + return apiCall(url, { + ...options, + method: 'DELETE', + }); + }, + }; +} diff --git a/src/api/leaderboard.ts b/src/api/leaderboard.ts new file mode 100644 index 000000000000..5589ab174290 --- /dev/null +++ b/src/api/leaderboard.ts @@ -0,0 +1,38 @@ +import { type APIContext } from 'astro'; +import { api } from './api.ts'; + +export type LeaderboardUserDetails = { + id: string; + name: string; + avatar?: string; + count: number; +}; + +export type ListLeaderboardStatsResponse = { + streaks: { + active: LeaderboardUserDetails[]; + lifetime: LeaderboardUserDetails[]; + }; + projectSubmissions: { + currentMonth: LeaderboardUserDetails[]; + lifetime: LeaderboardUserDetails[]; + }; + githubContributors: { + currentMonth: LeaderboardUserDetails[]; + }; + referrals: { + currentMonth: LeaderboardUserDetails[]; + lifetime: LeaderboardUserDetails[]; + }; +}; + +export function leaderboardApi(context: APIContext) { + return { + listLeaderboardStats: async function () { + return api(context).get( + `${import.meta.env.PUBLIC_API_URL}/v1-list-leaderboard-stats`, + {}, + ); + }, + }; +} diff --git a/src/api/project.ts b/src/api/project.ts new file mode 100644 index 000000000000..18647eabdb15 --- /dev/null +++ b/src/api/project.ts @@ -0,0 +1,15 @@ +import { type APIContext } from 'astro'; +import { api } from './api.ts'; + +export function projectApi(context: APIContext) { + return { + listProjectsUserCount: async function (projectIds: string[]) { + return api(context).post>( + `${import.meta.env.PUBLIC_API_URL}/v1-list-projects-user-count`, + { + projectIds, + }, + ); + }, + }; +} diff --git a/src/api/roadmap.ts b/src/api/roadmap.ts new file mode 100644 index 000000000000..2df83215914f --- /dev/null +++ b/src/api/roadmap.ts @@ -0,0 +1,67 @@ +import { type APIContext } from 'astro'; +import { api } from './api.ts'; +import type { RoadmapDocument } from '../components/CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx'; +import type { PageType } from '../components/CommandMenu/CommandMenu.tsx'; + +export type ListShowcaseRoadmapResponse = { + data: Pick< + RoadmapDocument, + | '_id' + | 'title' + | 'description' + | 'slug' + | 'creatorId' + | 'visibility' + | 'createdAt' + | 'topicCount' + | 'ratings' + >[]; + totalCount: number; + totalPages: number; + currPage: number; + perPage: number; +}; + +export function roadmapApi(context: APIContext) { + return { + listShowcaseRoadmap: async function () { + const searchParams = new URLSearchParams(context.url.searchParams); + return api(context).get( + `${import.meta.env.PUBLIC_API_URL}/v1-list-showcase-roadmap`, + searchParams, + ); + }, + isShowcaseRoadmap: async function (slug: string) { + return api(context).get<{ + isShowcase: boolean; + }>(`${import.meta.env.PUBLIC_API_URL}/v1-is-showcase-roadmap/${slug}`); + }, + }; +} + +export type ProjectPageType = { + id: string; + title: string; + url: string; +}; + +export async function getProjectList() { + const baseUrl = import.meta.env.DEV + ? 'http://localhost:3000' + : 'https://roadmap.sh'; + const pages = await fetch(`${baseUrl}/pages.json`).catch((err) => { + console.error(err); + return []; + }); + + const pagesJson = await (pages as any).json(); + const projects: ProjectPageType[] = pagesJson + .filter((page: any) => page?.group?.toLowerCase() === 'projects') + .map((page: any) => ({ + id: page.id, + title: page.title, + url: page.url, + })); + + return projects; +} diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 000000000000..4e557e16693e --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,142 @@ +import { type APIContext } from 'astro'; +import { api } from './api.ts'; +import type { ResourceType } from '../lib/resource-progress.ts'; +import type { ProjectStatusDocument } from '../components/Projects/ListProjectSolutions.tsx'; + +export const allowedRoadmapVisibility = ['all', 'none', 'selected'] as const; +export type AllowedRoadmapVisibility = + (typeof allowedRoadmapVisibility)[number]; + +export const allowedCustomRoadmapVisibility = [ + 'all', + 'none', + 'selected', +] as const; +export type AllowedCustomRoadmapVisibility = + (typeof allowedCustomRoadmapVisibility)[number]; + +export const allowedProfileVisibility = ['public', 'private'] as const; +export type AllowedProfileVisibility = + (typeof allowedProfileVisibility)[number]; + +export const allowedOnboardingStatus = ['done', 'pending', 'ignored'] as const; +export type AllowedOnboardingStatus = (typeof allowedOnboardingStatus)[number]; + +export interface UserDocument { + _id?: string; + name: string; + email: string; + avatar?: string; + password: string; + isEnabled: boolean; + authProvider: 'github' | 'google' | 'email' | 'linkedin'; + metadata: Record; + calculatedStats: { + activityCount: number; + totalVisitCount: number; + longestVisitStreak: number; + currentVisitStreak: number; + updatedAt: Date; + }; + verificationCode: string; + resetPasswordCode: string; + isSyncedWithSendy: boolean; + links?: { + github?: string; + linkedin?: string; + twitter?: string; + dailydev?: string; + website?: string; + }; + username?: string; + profileVisibility: AllowedProfileVisibility; + publicConfig?: { + isAvailableForHire: boolean; + isEmailVisible: boolean; + headline: string; + roadmaps: string[]; + customRoadmaps: string[]; + roadmapVisibility: AllowedRoadmapVisibility; + customRoadmapVisibility: AllowedCustomRoadmapVisibility; + }; + resetPasswordCodeAt: string; + verifiedAt: string; + + // Onboarding fields + onboardingStatus?: AllowedOnboardingStatus; + onboarding?: { + updateProgress: AllowedOnboardingStatus; + publishProfile: AllowedOnboardingStatus; + customRoadmap: AllowedOnboardingStatus; + addFriends: AllowedOnboardingStatus; + roadCard: AllowedOnboardingStatus; + inviteTeam: AllowedOnboardingStatus; + }; + + createdAt: string; + updatedAt: string; +} + +export type UserActivityCount = { + activityCount: Record; + totalActivityCount: number; +}; + +type ProgressResponse = { + updatedAt: string; + title: string; + id: string; + learning: number; + skipped: number; + done: number; + total: number; + isCustomResource?: boolean; + roadmapSlug?: string; +}; + +export type GetPublicProfileResponse = Omit< + UserDocument, + 'password' | 'verificationCode' | 'resetPasswordCode' | 'resetPasswordCodeAt' +> & { + activity: UserActivityCount; + roadmaps: ProgressResponse[]; + projects: ProjectStatusDocument[]; + isOwnProfile: boolean; +}; + +export type GetUserProfileRoadmapResponse = { + title: string; + topicCount: number; + roadmapSlug?: string; + isCustomResource?: boolean; + done: string[]; + learning: string[]; + skipped: string[]; + nodes: any[]; + edges: any[]; +}; + +export function userApi(context: APIContext) { + return { + getPublicProfile: async function (username: string) { + return api(context).get( + `${import.meta.env.PUBLIC_API_URL}/v1-get-public-profile/${username}`, + ); + }, + getUserProfileRoadmap: async function ( + username: string, + resourceId: string, + resourceType: ResourceType = 'roadmap', + ) { + return api(context).get( + `${ + import.meta.env.PUBLIC_API_URL + }/v1-get-user-profile-roadmap/${username}`, + { + resourceId, + resourceType, + }, + ); + }, + }; +} diff --git a/src/components/AIChat/AIChat.css b/src/components/AIChat/AIChat.css new file mode 100644 index 000000000000..0371f99520f7 --- /dev/null +++ b/src/components/AIChat/AIChat.css @@ -0,0 +1,131 @@ +.ai-chat .prose ul li > code, +.ai-chat .prose ol li > code, +.ai-chat p code, +.ai-chat a > code, +.ai-chat strong > code, +.ai-chat em > code, +.ai-chat h1 > code, +.ai-chat h2 > code, +.ai-chat h3 > code { + background: #ebebeb !important; + color: currentColor !important; + font-size: 14px; + font-weight: normal !important; +} + +.ai-chat .course-ai-content.course-content.prose ul li > code, +.ai-chat .course-ai-content.course-content.prose ol li > code, +.ai-chat .course-ai-content.course-content.prose p code, +.ai-chat .course-ai-content.course-content.prose a > code, +.ai-chat .course-ai-content.course-content.prose strong > code, +.ai-chat .course-ai-content.course-content.prose em > code, +.ai-chat .course-ai-content.course-content.prose h1 > code, +.ai-chat .course-ai-content.course-content.prose h2 > code, +.ai-chat .course-ai-content.course-content.prose h3 > code, +.ai-chat .course-notes-content.prose ul li > code, +.ai-chat .course-notes-content.prose ol li > code, +.ai-chat .course-notes-content.prose p code, +.ai-chat .course-notes-content.prose a > code, +.ai-chat .course-notes-content.prose strong > code, +.ai-chat .course-notes-content.prose em > code, +.ai-chat .course-notes-content.prose h1 > code, +.ai-chat .course-notes-content.prose h2 > code, +.ai-chat .course-notes-content.prose h3 > code { + font-size: 12px !important; +} + +.ai-chat .course-ai-content pre { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.ai-chat .course-ai-content pre::-webkit-scrollbar { + display: none; +} + +.ai-chat .course-ai-content pre, +.ai-chat .course-notes-content pre { + overflow: scroll; + font-size: 15px; + margin: 10px 0; +} + +.ai-chat .prose ul li > code:before, +.ai-chat p > code:before, +.ai-chat .prose ul li > code:after, +.prose ol li > code:before, +p > code:before, +.ai-chat .prose ol li > code:after, +.ai-chat .course-content h1 > code:after, +.ai-chat .course-content h1 > code:before, +.ai-chat .course-content h2 > code:after, +.ai-chat .course-content h2 > code:before, +.ai-chat .course-content h3 > code:after, +.ai-chat .course-content h3 > code:before, +.ai-chat .course-content h4 > code:after, +.ai-chat .course-content h4 > code:before, +.ai-chat p > code:after, +.ai-chat a > code:after, +.ai-chat a > code:before { + content: '' !important; +} + +.ai-chat .course-content.prose ul li > code, +.ai-chat .course-content.prose ol li > code, +.ai-chat .course-content p code, +.ai-chat .course-content a > code, +.ai-chat .course-content strong > code, +.ai-chat .course-content em > code, +.ai-chat .course-content h1 > code, +.ai-chat .course-content h2 > code, +.ai-chat .course-content h3 > code, +.ai-chat .course-content table code { + background: #f4f4f5 !important; + border: 1px solid #282a36 !important; + color: #282a36 !important; + padding: 2px 4px; + border-radius: 5px; + font-size: 16px !important; + white-space: pre; + font-weight: normal; +} + +.ai-chat .course-content blockquote { + font-style: normal; +} + +.ai-chat .course-content.prose blockquote h1, +.ai-chat .course-content.prose blockquote h2, +.ai-chat .course-content.prose blockquote h3, +.ai-chat .course-content.prose blockquote h4 { + font-style: normal; + margin-bottom: 8px; +} + +.ai-chat .course-content.prose ul li > code:before, +.ai-chat .course-content p > code:before, +.ai-chat .course-content.prose ul li > code:after, +.ai-chat .course-content p > code:after, +.ai-chat .course-content h2 > code:after, +.ai-chat .course-content h2 > code:before, +.ai-chat .course-content table code:before, +.ai-chat .course-content table code:after, +.ai-chat .course-content a > code:after, +.ai-chat .course-content a > code:before, +.ai-chat .course-content h2 code:after, +.ai-chat .course-content h2 code:before, +.ai-chat .course-content h2 code:after, +.ai-chat .course-content h2 code:before { + content: '' !important; +} + +.ai-chat .course-content table { + border-collapse: collapse; + border: 1px solid black; + border-radius: 5px; +} + +.ai-chat .course-content table td, +.ai-chat .course-content table th { + padding: 5px 10px; +} diff --git a/src/components/AIChat/AIChat.tsx b/src/components/AIChat/AIChat.tsx new file mode 100644 index 000000000000..1213580d8f0b --- /dev/null +++ b/src/components/AIChat/AIChat.tsx @@ -0,0 +1,562 @@ +import './AIChat.css'; +import { + ArrowDownIcon, + FileUpIcon, + LockIcon, + PersonStandingIcon, + SendIcon, + TrashIcon, +} from 'lucide-react'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { flushSync } from 'react-dom'; +import AutogrowTextarea from 'react-textarea-autosize'; +import { QuickHelpPrompts } from './QuickHelpPrompts'; +import { QuickActionButton } from './QuickActionButton'; +import { aiLimitOptions } from '../../queries/ai-course'; +import { isLoggedIn, removeAuthToken } from '../../lib/jwt'; +import { useMutation, useQuery } from '@tanstack/react-query'; +import { queryClient } from '../../stores/query-client'; +import { billingDetailsOptions } from '../../queries/billing'; +import { useToast } from '../../hooks/use-toast'; +import { markdownToHtml } from '../../lib/markdown'; +import { ChatHistory } from './ChatHistory'; +import { PersonalizedResponseForm } from './PersonalizedResponseForm'; +import { userPersonaOptions } from '../../queries/user-persona'; +import { UploadResumeModal } from './UploadResumeModal'; +import { userResumeOptions } from '../../queries/user-resume'; +import { httpPost } from '../../lib/query-http'; +import { + renderMessage, + type MessagePartRenderer, +} from '../../lib/render-chat-message'; +import { RoadmapRecommendations } from '../RoadmapAIChat/RoadmapRecommendations'; +import { AIChatCourse } from './AIChatCouse'; +import { showLoginPopup } from '../../lib/popup'; +import { readChatStream } from '../../lib/chat'; +import { chatHistoryOptions } from '../../queries/chat-history'; +import { cn } from '../../lib/classname'; +import type { RoadmapAIChatHistoryType } from '../../hooks/use-roadmap-ai-chat'; + +export const aiChatRenderer: Record = { + 'roadmap-recommendations': (options) => { + return ; + }, + 'generate-course': (options) => { + return ; + }, +}; + +type AIChatProps = { + messages?: RoadmapAIChatHistoryType[]; + chatHistoryId?: string; + setChatHistoryId?: (chatHistoryId: string) => void; + onUpgrade?: () => void; +}; + +export function AIChat(props: AIChatProps) { + const { + messages: defaultMessages, + chatHistoryId: defaultChatHistoryId, + setChatHistoryId: setDefaultChatHistoryId, + onUpgrade, + } = props; + + const toast = useToast(); + + const [message, setMessage] = useState(''); + const [isStreamingMessage, setIsStreamingMessage] = useState(false); + const [streamedMessage, setStreamedMessage] = + useState(null); + const [aiChatHistory, setAiChatHistory] = useState< + RoadmapAIChatHistoryType[] + >(defaultMessages ?? []); + + const [isPersonalizedResponseFormOpen, setIsPersonalizedResponseFormOpen] = + useState(false); + const [isUploadResumeModalOpen, setIsUploadResumeModalOpen] = useState(false); + + const [showScrollToBottomButton, setShowScrollToBottomButton] = + useState(false); + + const scrollableContainerRef = useRef(null); + const chatContainerRef = useRef(null); + const textareaMessageRef = useRef(null); + + const { data: tokenUsage, isLoading } = useQuery( + aiLimitOptions(), + queryClient, + ); + + const { data: userBillingDetails, isLoading: isBillingDetailsLoading } = + useQuery(billingDetailsOptions(), queryClient); + const { data: userPersona, isLoading: isUserPersonaLoading } = useQuery( + userPersonaOptions(), + queryClient, + ); + const { data: userResume, isLoading: isUserResumeLoading } = useQuery( + userResumeOptions(), + queryClient, + ); + const { mutate: deleteChatMessage, isPending: isDeletingChatMessage } = + useMutation( + { + mutationFn: (messages: RoadmapAIChatHistoryType[]) => { + if (!defaultChatHistoryId) { + return Promise.resolve({ + status: 200, + message: 'Chat history not found', + }); + } + + return httpPost(`/v1-delete-chat-message/${defaultChatHistoryId}`, { + messages, + }); + }, + onSuccess: () => { + textareaMessageRef.current?.focus(); + + queryClient.invalidateQueries( + chatHistoryOptions(defaultChatHistoryId), + ); + }, + onError: (error) => { + toast.error(error?.message || 'Failed to delete message'); + }, + }, + queryClient, + ); + + const isLimitExceeded = (tokenUsage?.used || 0) >= (tokenUsage?.limit || 0); + const isPaidUser = userBillingDetails?.status === 'active'; + + const handleChatSubmit = () => { + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + + if (isLimitExceeded) { + if (!isPaidUser) { + onUpgrade?.(); + } + + toast.error('Limit reached for today. Please wait until tomorrow.'); + return; + } + + const trimmedMessage = message.trim(); + if (!trimmedMessage || isStreamingMessage) { + return; + } + + const newMessages: RoadmapAIChatHistoryType[] = [ + ...aiChatHistory, + { + role: 'user', + content: trimmedMessage, + // it's just a simple message, so we can use markdownToHtml + html: markdownToHtml(trimmedMessage), + }, + ]; + + flushSync(() => { + setAiChatHistory(newMessages); + setMessage(''); + }); + + setTimeout(() => { + scrollToBottom(); + }, 0); + + textareaMessageRef.current?.focus(); + completeAIChat(newMessages); + }; + + const canScrollToBottom = useCallback(() => { + const scrollableContainer = scrollableContainerRef?.current; + if (!scrollableContainer) { + return false; + } + + const paddingBottom = parseInt( + getComputedStyle(scrollableContainer).paddingBottom, + ); + + const distanceFromBottom = + scrollableContainer.scrollHeight - + (scrollableContainer.scrollTop + scrollableContainer.clientHeight) - + paddingBottom; + + return distanceFromBottom > -(paddingBottom - 80); + }, []); + + const scrollToBottom = useCallback( + (behavior: 'instant' | 'smooth' = 'smooth') => { + const scrollableContainer = scrollableContainerRef?.current; + if (!scrollableContainer) { + return; + } + + scrollableContainer.scrollTo({ + top: scrollableContainer.scrollHeight, + behavior: behavior === 'instant' ? 'instant' : 'smooth', + }); + }, + [scrollableContainerRef], + ); + + const completeAIChat = async ( + messages: RoadmapAIChatHistoryType[], + force: boolean = false, + ) => { + setIsStreamingMessage(true); + + const response = await fetch(`${import.meta.env.PUBLIC_API_URL}/v1-chat`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ + chatHistoryId: defaultChatHistoryId, + messages, + force, + }), + }); + + if (!response.ok) { + const data = await response.json(); + + toast.error(data?.message || 'Something went wrong'); + setAiChatHistory([...messages].slice(0, messages.length - 1)); + setIsStreamingMessage(false); + + if (data.status === 401) { + removeAuthToken(); + window.location.reload(); + } + } + + const stream = response.body; + if (!stream) { + setIsStreamingMessage(false); + toast.error('Something went wrong'); + return; + } + + await readChatStream(stream, { + onMessage: async (content) => { + const jsx = await renderMessage(content, aiChatRenderer, { + isLoading: true, + }); + + flushSync(() => { + setStreamedMessage(jsx); + }); + setShowScrollToBottomButton(canScrollToBottom()); + }, + onMessageEnd: async (content) => { + const jsx = await renderMessage(content, aiChatRenderer, { + isLoading: false, + }); + + const newMessages: RoadmapAIChatHistoryType[] = [ + ...messages, + { + role: 'assistant', + content, + jsx, + }, + ]; + + flushSync(() => { + setStreamedMessage(null); + setIsStreamingMessage(false); + setAiChatHistory(newMessages); + }); + + queryClient.invalidateQueries(aiLimitOptions()); + queryClient.invalidateQueries({ + predicate: (query) => { + return query.queryKey[0] === 'list-chat-history'; + }, + }); + }, + onDetails: (details) => { + const chatHistoryId = details?.chatHistoryId; + if (!chatHistoryId) { + return; + } + + setDefaultChatHistoryId?.(chatHistoryId); + }, + }); + + setIsStreamingMessage(false); + }; + + const { mutate: uploadResume, isPending: isUploading } = useMutation( + { + mutationFn: (formData: FormData) => { + return httpPost('/v1-upload-resume', formData); + }, + onSuccess: () => { + toast.success('Resume uploaded successfully'); + setIsUploadResumeModalOpen(false); + queryClient.invalidateQueries(userResumeOptions()); + }, + onError: (error) => { + toast.error(error?.message || 'Failed to upload resume'); + }, + onMutate: () => { + setIsUploadResumeModalOpen(false); + }, + }, + queryClient, + ); + + useEffect(() => { + const scrollableContainer = scrollableContainerRef.current; + if (!scrollableContainer) { + return; + } + + const abortController = new AbortController(); + let timeoutId: NodeJS.Timeout; + const debouncedHandleScroll = () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + + timeoutId = setTimeout(() => { + setShowScrollToBottomButton(canScrollToBottom()); + }, 100); + }; + + debouncedHandleScroll(); + scrollableContainer.addEventListener('scroll', debouncedHandleScroll, { + signal: abortController.signal, + }); + + return () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + abortController.abort(); + }; + }, [aiChatHistory]); + + const handleRegenerate = useCallback( + (index: number) => { + if (isLimitExceeded) { + if (!isPaidUser) { + onUpgrade?.(); + } + + toast.error('Limit reached for today. Please wait until tomorrow.'); + return; + } + + const filteredChatHistory = aiChatHistory.slice(0, index); + + flushSync(() => { + setAiChatHistory(filteredChatHistory); + }); + scrollToBottom(); + completeAIChat(filteredChatHistory, true); + }, + [aiChatHistory], + ); + + const handleDelete = useCallback( + (index: number) => { + const filteredChatHistory = aiChatHistory.filter((_, i) => i !== index); + setAiChatHistory(filteredChatHistory); + deleteChatMessage(filteredChatHistory); + }, + [aiChatHistory], + ); + + const shouldShowQuickHelpPrompts = + message.length === 0 && aiChatHistory.length === 0; + const isDataLoading = + isLoading || + isBillingDetailsLoading || + isUserPersonaLoading || + isUserResumeLoading; + + useEffect(() => { + scrollToBottom('instant'); + }, []); + + const shouldShowUpgradeBanner = !isPaidUser && aiChatHistory.length > 0; + + return ( +
+
+
+ {shouldShowQuickHelpPrompts && ( + { + textareaMessageRef.current?.focus(); + setMessage(question); + }} + /> + )} + {!shouldShowQuickHelpPrompts && ( + + )} +
+
+ + {isPersonalizedResponseFormOpen && ( + setIsPersonalizedResponseFormOpen(false)} + /> + )} + + {isUploadResumeModalOpen && ( + setIsUploadResumeModalOpen(false)} + userResume={userResume} + isUploading={isUploading} + uploadResume={uploadResume} + /> + )} + +
+
+
+ { + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + + setIsPersonalizedResponseFormOpen(true); + }} + /> + { + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + + setIsUploadResumeModalOpen(true); + }} + isLoading={isUploading} + /> +
+ +
+ {showScrollToBottomButton && ( + + )} + {aiChatHistory.length > 0 && !isPaidUser && ( + { + setAiChatHistory([]); + deleteChatMessage([]); + }} + /> + )} +
+
+ +
{ + e.preventDefault(); + if (isDataLoading) { + return; + } + + handleChatSubmit(); + }} + > + setMessage(e.target.value)} + className="min-h-10 w-full resize-none bg-transparent text-sm focus:outline-none" + placeholder="Ask me anything..." + disabled={isStreamingMessage} + autoFocus + onKeyDown={(e) => { + if (e.key === 'Enter' && !e.shiftKey) { + if (isDataLoading) { + return; + } + + e.preventDefault(); + handleChatSubmit(); + } + }} + /> + + {isLimitExceeded && isLoggedIn() && !isDataLoading && ( +
+ +

+ Limit reached for today + {isPaidUser ? '. Please wait until tomorrow.' : ''} +

+ {!isPaidUser && ( + + )} +
+ )} + +
+ +
+ +
+
+ ); +} diff --git a/src/components/AIChat/AIChatCouse.tsx b/src/components/AIChat/AIChatCouse.tsx new file mode 100644 index 000000000000..ecbc7d21c472 --- /dev/null +++ b/src/components/AIChat/AIChatCouse.tsx @@ -0,0 +1,51 @@ +import { Book } from 'lucide-react'; + +type AIChatCourseType = { + keyword: string; + difficulty: string; +}; + +function parseAIChatCourse(content: string): AIChatCourseType | null { + const courseKeywordRegex = /(.*?)<\/keyword>/; + const courseKeyword = content.match(courseKeywordRegex)?.[1]?.trim(); + if (!courseKeyword) { + return null; + } + + const courseDifficultyRegex = /(.*?)<\/difficulty>/; + const courseDifficulty = content.match(courseDifficultyRegex)?.[1]?.trim(); + if (!courseDifficulty) { + return null; + } + + return { keyword: courseKeyword, difficulty: courseDifficulty || 'beginner' }; +} + +type AIChatCourseProps = { + content: string; +}; + +export function AIChatCourse(props: AIChatCourseProps) { + const { content } = props; + + const course = parseAIChatCourse(content); + if (!course) { + return null; + } + + const courseSearchUrl = `/ai/course?term=${course?.keyword}&difficulty=${course?.difficulty}`; + + return ( + + ); +} diff --git a/src/components/AIChat/ChatHistory.tsx b/src/components/AIChat/ChatHistory.tsx new file mode 100644 index 000000000000..e770b437c4c8 --- /dev/null +++ b/src/components/AIChat/ChatHistory.tsx @@ -0,0 +1,174 @@ +import { Fragment, memo } from 'react'; +import { cn } from '../../lib/classname'; +import { + CopyIcon, + CheckIcon, + TrashIcon, + type LucideIcon, + RotateCwIcon, +} from 'lucide-react'; +import { useCopyText } from '../../hooks/use-copy-text'; +import { Tooltip } from '../Tooltip'; +import type { RoadmapAIChatHistoryType } from '../../hooks/use-roadmap-ai-chat'; + +type ChatHistoryProps = { + chatHistory: RoadmapAIChatHistoryType[]; + onDelete?: (index: number) => void; + onRegenerate?: (index: number) => void; + isStreamingMessage: boolean; + streamedMessage: React.ReactNode; +}; + +export const ChatHistory = memo((props: ChatHistoryProps) => { + const { + chatHistory, + onDelete, + isStreamingMessage, + streamedMessage, + onRegenerate, + } = props; + + return ( +
+
+
+ {chatHistory.map((chat, index) => { + return ( + + { + onDelete?.(index); + }} + onRegenerate={() => { + onRegenerate?.(index); + }} + /> + + ); + })} + + {isStreamingMessage && !streamedMessage && ( + + )} + + {streamedMessage && ( + + )} +
+
+
+ ); +}); + +type AIChatCardProps = RoadmapAIChatHistoryType & { + onDelete?: () => void; + onRegenerate?: () => void; + showActions?: boolean; +}; + +export const AIChatCard = memo((props: AIChatCardProps) => { + const { + role, + content, + jsx, + html, + showActions = true, + onDelete, + onRegenerate, + } = props; + const { copyText, isCopied } = useCopyText(); + + return ( +
+
+ {!!jsx && jsx} + + {!!html && ( +
+ )} +
+ + {showActions && ( +
+ copyText(content ?? '')} + tooltip={isCopied ? 'Copied' : 'Copy'} + /> + + {role === 'assistant' && onRegenerate && ( + + )} + + {onDelete && ( + + )} +
+ )} +
+ ); +}); + +type ActionButtonProps = { + icon: LucideIcon; + tooltip?: string; + onClick: () => void; +}; + +function ActionButton(props: ActionButtonProps) { + const { icon: Icon, onClick, tooltip } = props; + + return ( +
+ + + {tooltip && ( + + {tooltip} + + )} +
+ ); +} diff --git a/src/components/AIChat/PersonalizedResponseForm.tsx b/src/components/AIChat/PersonalizedResponseForm.tsx new file mode 100644 index 000000000000..ea36eac6022c --- /dev/null +++ b/src/components/AIChat/PersonalizedResponseForm.tsx @@ -0,0 +1,240 @@ +import { Loader2Icon } from 'lucide-react'; +import { MessageCircle } from 'lucide-react'; +import { memo, useId, useRef, useState } from 'react'; +import { Modal } from '../Modal'; +import { cn } from '../../lib/classname'; +import { SelectNative } from '../SelectNative'; +import { useMutation } from '@tanstack/react-query'; +import { queryClient } from '../../stores/query-client'; +import { httpPost } from '../../lib/query-http'; +import { userPersonaOptions } from '../../queries/user-persona'; +import { useToast } from '../../hooks/use-toast'; +import { isLoggedIn } from '../../lib/jwt'; +import { showLoginPopup } from '../../lib/popup'; + +export type ChatPreferencesFormData = { + expertise: string; + goal: string; + about: string; + specialInstructions?: string; +}; + +type PersonalizedResponseFormProps = { + defaultValues?: ChatPreferencesFormData; + onClose: () => void; +}; + +export const PersonalizedResponseForm = memo( + (props: PersonalizedResponseFormProps) => { + const { defaultValues, onClose } = props; + const toast = useToast(); + + const [expertise, setExpertise] = useState(defaultValues?.expertise ?? ''); + const [about, setAbout] = useState(defaultValues?.about ?? ''); + const [specialInstructions, setSpecialInstructions] = useState( + defaultValues?.specialInstructions ?? '' + ); + + const goalOptions = [ + 'Finding a job', + 'Learning for fun', + 'Building a side project', + 'Switching careers', + 'Getting a promotion', + 'Filling knowledge gaps', + 'Other', + ]; + + const getInitialGoalSelection = () => { + if (!defaultValues?.goal) { + return ''; + } + + for (const option of goalOptions.slice(0, -1)) { + if (defaultValues.goal.startsWith(option)) { + return option; + } + } + + return 'Other'; + }; + + const [selectedGoal, setSelectedGoal] = useState(getInitialGoalSelection()); + const [goal, setGoal] = useState(defaultValues?.goal ?? ''); + + const expertiseFieldId = useId(); + const goalFieldId = useId(); + const goalSelectId = useId(); + const aboutFieldId = useId(); + const specialInstructionsFieldId = useId(); + + const goalRef = useRef(null); + + const handleGoalSelectionChange = (value: string) => { + setSelectedGoal(value); + + if (value === 'Other') { + setGoal(''); + setTimeout(() => { + goalRef.current?.focus(); + }, 0); + } else { + setGoal(value); + } + }; + + const { mutate: setChatPreferences, isPending } = useMutation( + { + mutationFn: (data: ChatPreferencesFormData) => { + return httpPost('/v1-set-chat-preferences', data); + }, + onSuccess: () => { + onClose(); + queryClient.invalidateQueries(userPersonaOptions()); + }, + onError: (error) => { + toast.error(error?.message ?? 'Something went wrong'); + }, + }, + queryClient + ); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + + setChatPreferences({ + expertise, + goal, + about, + specialInstructions, + }); + }; + + const hasFormCompleted = !!expertise && !!goal && !!about; + + return ( + +
+
+
+ + setExpertise(e.target.value)} + className="h-[40px] border-gray-300 text-sm focus:border-gray-500 focus:ring-1 focus:ring-gray-500" + > + + {[ + 'No experience (just starting out)', + 'Beginner (less than 1 year of experience)', + 'Intermediate (1-3 years of experience)', + 'Expert (3-5 years of experience)', + 'Master (5+ years of experience)', + ].map((expertise) => ( + + ))} + +
+ +
+ + + handleGoalSelectionChange(e.target.value)} + className="h-[40px] border-gray-300 text-sm focus:border-gray-500 focus:ring-1 focus:ring-gray-500" + > + + {goalOptions.map((goalOption) => ( + + ))} + + + {selectedGoal === 'Other' && ( + + ) : ( + + )} +
+ ); +} + +export function AdvertiseForm() { + const [status, setStatus] = useState<'submitting' | 'submitted'>(); + const [error, setError] = useState(null); + + const [formData, setFormData] = useState({ + firstName: '', + lastName: '', + title: '', + company: '', + email: '', + phone: '', + message: '', + updates: false, + }); + + const handleInputChange = ( + e: React.ChangeEvent, + ) => { + const { name, value, type, checked } = e.target as any; + setFormData({ + ...formData, + [name]: type === 'checkbox' ? checked : value, + }); + }; + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + + pageProgressMessage.set('Please wait'); + + const { response, error } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-advertise`, + formData, + ); + if (!response || error) { + pageProgressMessage.set(''); + setError(error?.message || 'Something went wrong. Please try again.'); + return; + } + + setStatus('submitted'); + pageProgressMessage.set(''); + } + + if (status === 'submitted') { + return ( +
+ +

+ Thank you for your interest in advertising with roadmap.sh +

+

+ We will get back to you soon. +

+
+ ); + } + + return ( + <> +

+ Ready to learn more? Fill out the form below to get started! +

+ {error && ( +
+ {error} +
+ )} + +
+ + +
+ +
+ + + +
+ +
+ + + +
+ + +
+
+ +
+
+ +
+
+ +
+ +
+ + + ); +} diff --git a/src/components/Analytics/Analytics.astro b/src/components/Analytics/Analytics.astro new file mode 100644 index 000000000000..53f7a5247f00 --- /dev/null +++ b/src/components/Analytics/Analytics.astro @@ -0,0 +1,13 @@ +--- +--- + + + + \ No newline at end of file diff --git a/src/components/Analytics/Bluconic.astro b/src/components/Analytics/Bluconic.astro new file mode 100644 index 000000000000..97deb39b5c9e --- /dev/null +++ b/src/components/Analytics/Bluconic.astro @@ -0,0 +1 @@ + diff --git a/src/components/Analytics/Clarity.astro b/src/components/Analytics/Clarity.astro new file mode 100644 index 000000000000..76125f232a8c --- /dev/null +++ b/src/components/Analytics/Clarity.astro @@ -0,0 +1,14 @@ + diff --git a/src/components/Analytics/GoogleAd.astro b/src/components/Analytics/GoogleAd.astro new file mode 100644 index 000000000000..f4197950f60f --- /dev/null +++ b/src/components/Analytics/GoogleAd.astro @@ -0,0 +1,132 @@ + + diff --git a/src/components/Analytics/GoogleAdSlot.astro b/src/components/Analytics/GoogleAdSlot.astro new file mode 100644 index 000000000000..4556c571df19 --- /dev/null +++ b/src/components/Analytics/GoogleAdSlot.astro @@ -0,0 +1,59 @@ +
+ +
+ + diff --git a/src/components/Analytics/Hubspot.astro b/src/components/Analytics/Hubspot.astro new file mode 100644 index 000000000000..fc442611b88f --- /dev/null +++ b/src/components/Analytics/Hubspot.astro @@ -0,0 +1,6 @@ + diff --git a/src/components/Analytics/LinkedIn.astro b/src/components/Analytics/LinkedIn.astro new file mode 100644 index 000000000000..a6ed5a82ca82 --- /dev/null +++ b/src/components/Analytics/LinkedIn.astro @@ -0,0 +1,22 @@ +--- +// LinkedIn Analytics component +--- + + + + \ No newline at end of file diff --git a/src/components/Analytics/OneTrust.astro b/src/components/Analytics/OneTrust.astro new file mode 100644 index 000000000000..2c584d491e72 --- /dev/null +++ b/src/components/Analytics/OneTrust.astro @@ -0,0 +1,10 @@ + + + + diff --git a/src/components/Analytics/RedditPixel.astro b/src/components/Analytics/RedditPixel.astro new file mode 100644 index 000000000000..b6c7811235f9 --- /dev/null +++ b/src/components/Analytics/RedditPixel.astro @@ -0,0 +1,19 @@ + diff --git a/src/components/Analytics/analytics.ts b/src/components/Analytics/analytics.ts new file mode 100644 index 000000000000..5497e7608754 --- /dev/null +++ b/src/components/Analytics/analytics.ts @@ -0,0 +1,92 @@ +import { httpPost } from '../../lib/query-http'; +import { getPageTrackingData } from '../../lib/browser'; + +declare global { + interface Window { + gtag: any; + fireEvent: (props: { + action: string; + category: string; + label?: string; + value?: string; + callback?: () => void; + }) => void; + } +} + +/** + * Tracks the event on google analytics + * @see https://developers.google.com/analytics/devguides/collection/gtagjs/events + * @param props Event properties + * @returns void + */ +window.fireEvent = (props) => { + const { action, category, label, value, callback } = props; + + const eventId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; + + if (['course', 'ai_tutor'].includes(category)) { + const trackingData = getPageTrackingData(); + const url = new URL(import.meta.env.PUBLIC_API_URL); + url.pathname = '/api/_t'; + url.searchParams.set('action', action); + url.searchParams.set('category', category); + url.searchParams.set('label', label ?? ''); + url.searchParams.set('value', value ?? ''); + url.searchParams.set('event_id', eventId); + + httpPost(url.toString(), { + page_location: trackingData.page_location, + page_path: trackingData.page_path, + page_referrer: trackingData.page_referrer, + page_title: trackingData.page_title, + user_agent: trackingData.user_agent, + screen_resolution: trackingData.screen_resolution, + viewport_size: trackingData.viewport_size, + session_id: trackingData.session_id, + gclid: trackingData.gclid, + utm_source: trackingData.utm_source, + utm_medium: trackingData.utm_medium, + utm_campaign: trackingData.utm_campaign, + utm_content: trackingData.utm_content, + utm_term: trackingData.utm_term, + }).catch(console.error); + + return; + } + + if (!window.gtag) { + console.warn('Missing GTAG - Analytics disabled'); + return; + } + + if (import.meta.env.DEV) { + console.log('Analytics event fired', props); + callback?.(); + return; + } + + const trackingData = getPageTrackingData(); + + window.gtag('event', action, { + event_category: category, + event_label: label, + value: value, + event_id: eventId, + source: 'client', + page_location: trackingData.page_location, + page_path: trackingData.page_path, + page_referrer: trackingData.page_referrer, + page_title: trackingData.page_title, + session_id: trackingData.session_id, + gclid: trackingData.gclid, + utm_source: trackingData.utm_source, + utm_medium: trackingData.utm_medium, + utm_campaign: trackingData.utm_campaign, + utm_content: trackingData.utm_content, + utm_term: trackingData.utm_term, + ...(callback ? { event_callback: callback } : {}), + }); +}; + +export {}; diff --git a/src/components/AppChecklist.tsx b/src/components/AppChecklist.tsx new file mode 100644 index 000000000000..ed7aece68f0f --- /dev/null +++ b/src/components/AppChecklist.tsx @@ -0,0 +1,15 @@ +import { PartyPopper } from 'lucide-react'; + +export function AppChecklist() { + return ( + + ); +} diff --git a/src/components/AstroIcon.astro b/src/components/AstroIcon.astro new file mode 100644 index 000000000000..fbf06880b468 --- /dev/null +++ b/src/components/AstroIcon.astro @@ -0,0 +1,37 @@ +--- +import { parse } from 'node-html-parser'; + +export interface Props { + icon: string; + class?: string; +} + +async function getSVG(name: string) { + const filepath = `/src/icons/${name}.svg`; + + const files = import.meta.glob('/src/icons/**/*.svg', { + query: '?raw', + eager: true, + }); + + if (!(filepath in files)) { + throw new Error(`${filepath} not found`); + } + + const root = parse((files[filepath] as any).default as string); + + const svg = root.querySelector('svg'); + + return { + attributes: svg?.attributes, + innerHTML: svg?.innerHTML, + }; +} + +const { icon, ...attributes } = Astro.props as Props; +const { attributes: baseAttributes, innerHTML } = await getSVG(icon); + +const svgAttributes = { ...baseAttributes, ...attributes }; +--- + + diff --git a/src/components/AuthenticationFlow/AuthenticationForm.tsx b/src/components/AuthenticationFlow/AuthenticationForm.tsx new file mode 100644 index 000000000000..70f07c5f48c6 --- /dev/null +++ b/src/components/AuthenticationFlow/AuthenticationForm.tsx @@ -0,0 +1,41 @@ +import { useState } from 'react'; +import { GitHubButton } from './GitHubButton'; +import { GoogleButton } from './GoogleButton'; +import { LinkedInButton } from './LinkedInButton'; +import { EmailLoginForm } from './EmailLoginForm'; +import { EmailSignupForm } from './EmailSignupForm'; + +type AuthenticationFormProps = { + type?: 'login' | 'signup'; +}; + +export function AuthenticationForm(props: AuthenticationFormProps) { + const { type = 'login' } = props; + + const [isDisabled, setIsDisabled] = useState(false); + + return ( + <> +
+ + + +
+ +
+
+ OR +
+
+ + {type === 'login' ? ( + + ) : ( + + )} + + ); +} diff --git a/src/components/AuthenticationFlow/CourseLoginPopup.tsx b/src/components/AuthenticationFlow/CourseLoginPopup.tsx new file mode 100644 index 000000000000..0a6c7a20cdef --- /dev/null +++ b/src/components/AuthenticationFlow/CourseLoginPopup.tsx @@ -0,0 +1,145 @@ +import { useEffect, useState } from 'react'; +import { Modal } from '../Modal'; +import { GitHubButton } from './GitHubButton'; +import { GoogleButton } from './GoogleButton'; +import { LinkedInButton } from './LinkedInButton'; +import { EmailLoginForm } from './EmailLoginForm'; +import { EmailSignupForm } from './EmailSignupForm'; + +type CourseLoginPopupProps = { + onClose: () => void; + checkoutAfterLogin?: boolean; +}; + +export const CHECKOUT_AFTER_LOGIN_KEY = 'checkoutAfterLogin'; +export const SAMPLE_AFTER_LOGIN_KEY = 'sampleAfterLogin'; + +export function CourseLoginPopup(props: CourseLoginPopupProps) { + const { onClose: parentOnClose, checkoutAfterLogin = true } = props; + + const [isDisabled, setIsDisabled] = useState(false); + const [isUsingEmail, setIsUsingEmail] = useState(false); + + const [emailNature, setEmailNature] = useState<'login' | 'signup' | null>( + null, + ); + + function onClose() { + // if user didn't login and closed the popup, we remove the checkoutAfterLogin flag + // so that login from other buttons on course page will trigger purchase + localStorage.removeItem(CHECKOUT_AFTER_LOGIN_KEY); + localStorage.removeItem(SAMPLE_AFTER_LOGIN_KEY); + parentOnClose(); + } + + useEffect(() => { + localStorage.setItem( + CHECKOUT_AFTER_LOGIN_KEY, + checkoutAfterLogin ? '1' : '0', + ); + }, [checkoutAfterLogin]); + + if (emailNature) { + const emailHeader = ( +
+

+ {emailNature === 'login' + ? 'Login to your account' + : 'Create an account'} +

+

+ Fill in the details below to continue +

+
+ ); + + return ( + + {emailHeader} + {emailNature === 'login' && ( + + )} + {emailNature === 'signup' && ( + + )} + + + + ); + } + + return ( + +
+

+ Create or login to Enroll +

+

+ Login or sign up for an account to start learning +

+
+ +
+ + + +
+ +
+
+ OR +
+
+ +
+ {!isUsingEmail && ( + + )} + {isUsingEmail && ( + <> + + + + )} +
+ + ); +} diff --git a/src/components/AuthenticationFlow/Divider.astro b/src/components/AuthenticationFlow/Divider.astro new file mode 100644 index 000000000000..49d9955edbd2 --- /dev/null +++ b/src/components/AuthenticationFlow/Divider.astro @@ -0,0 +1,5 @@ +
+
+ OR +
+
diff --git a/src/components/AuthenticationFlow/EmailLoginForm.tsx b/src/components/AuthenticationFlow/EmailLoginForm.tsx new file mode 100644 index 000000000000..75406960a127 --- /dev/null +++ b/src/components/AuthenticationFlow/EmailLoginForm.tsx @@ -0,0 +1,125 @@ +import type { FormEvent } from 'react'; +import { useId, useState } from 'react'; +import { httpPost } from '../../lib/http'; +import { + COURSE_PURCHASE_PARAM, + FIRST_LOGIN_PARAM, + setAuthToken, +} from '../../lib/jwt'; + +type EmailLoginFormProps = { + isDisabled?: boolean; + setIsDisabled?: (isDisabled: boolean) => void; +}; + +export function EmailLoginForm(props: EmailLoginFormProps) { + const { isDisabled, setIsDisabled } = props; + + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(''); + + const [isLoading, setIsLoading] = useState(false); + + const handleFormSubmit = async (e: FormEvent) => { + e.preventDefault(); + setIsLoading(true); + setIsDisabled?.(true); + setError(''); + + const { response, error } = await httpPost<{ + token: string; + isNewUser: boolean; + }>(`${import.meta.env.PUBLIC_API_URL}/v1-login`, { + email, + password, + }); + + // Log the user in and reload the page + if (response?.token) { + setAuthToken(response.token); + + const currentLocation = window.location.href; + const url = new URL(currentLocation, window.location.origin); + + url.searchParams.set(FIRST_LOGIN_PARAM, response?.isNewUser ? '1' : '0'); + url.searchParams.set(COURSE_PURCHASE_PARAM, '1'); + + window.location.href = url.toString(); + return; + } + + // @todo use proper types + if ((error as any).type === 'user_not_verified') { + window.location.href = `/verification-pending?email=${encodeURIComponent( + email, + )}`; + return; + } + + setIsLoading(false); + setIsDisabled?.(false); + setError(error?.message || 'Something went wrong. Please try again later.'); + }; + + const emailFieldId = `form:${useId()}`; + const passwordFieldId = `form:${useId()}`; + + return ( +
+ + setEmail(String((e.target as any).value))} + /> + + setPassword(String((e.target as any).value))} + /> + +

+ + Reset your password? + +

+ + {error && ( +

{error}

+ )} + + +
+ ); +} diff --git a/src/components/AuthenticationFlow/EmailSignupForm.tsx b/src/components/AuthenticationFlow/EmailSignupForm.tsx new file mode 100644 index 000000000000..5fd452fe0d11 --- /dev/null +++ b/src/components/AuthenticationFlow/EmailSignupForm.tsx @@ -0,0 +1,130 @@ +import { type FormEvent, useEffect, useState } from 'react'; +import { httpPost } from '../../lib/http'; +import { + deleteUrlParam, + getLastPath, + getUrlParams, + urlToId, +} from '../../lib/browser'; +import { isLoggedIn, setAIReferralCode } from '../../lib/jwt'; + +type EmailSignupFormProps = { + isDisabled?: boolean; + setIsDisabled?: (isDisabled: boolean) => void; +}; + +export function EmailSignupForm(props: EmailSignupFormProps) { + const { isDisabled, setIsDisabled } = props; + + const { rc: referralCode } = getUrlParams() as { + rc?: string; + }; + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + + const [error, setError] = useState(''); + const [isLoading, setIsLoading] = useState(false); + + const onSubmit = async (e: FormEvent) => { + e.preventDefault(); + + setIsLoading(true); + setIsDisabled?.(true); + setError(''); + + const { response, error } = await httpPost<{ status: 'ok' }>( + `${import.meta.env.PUBLIC_API_URL}/v1-register`, + { + email, + password, + name, + src: urlToId(getLastPath() || window.location.pathname), + }, + ); + + if (error || response?.status !== 'ok') { + setIsLoading(false); + setIsDisabled?.(false); + setError( + error?.message || 'Something went wrong. Please try again later.', + ); + + return; + } + + window.location.href = `/verification-pending?email=${encodeURIComponent( + email, + )}`; + }; + + useEffect(() => { + if (!referralCode || isLoggedIn()) { + deleteUrlParam('rc'); + return; + } + + setAIReferralCode(referralCode); + deleteUrlParam('rc'); + }, []); + + return ( +
+ + setName(String((e.target as any).value))} + /> + + setEmail(String((e.target as any).value))} + /> + + setPassword(String((e.target as any).value))} + /> + + {error && ( +

{error}.

+ )} + + +
+ ); +} diff --git a/src/components/AuthenticationFlow/ForgotPasswordForm.tsx b/src/components/AuthenticationFlow/ForgotPasswordForm.tsx new file mode 100644 index 000000000000..7096ffa95f72 --- /dev/null +++ b/src/components/AuthenticationFlow/ForgotPasswordForm.tsx @@ -0,0 +1,64 @@ +import { type FormEvent, useState } from 'react'; +import { httpPost } from '../../lib/http'; + +export function ForgotPasswordForm() { + const [email, setEmail] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(''); + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + setIsLoading(true); + setError(''); + + const { response, error } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-forgot-password`, + { + email, + } + ); + + setIsLoading(false); + if (error) { + setError(error.message); + } else { + setEmail(''); + setSuccess('Check your email for a link to reset your password.'); + } + }; + + return ( +
+ setEmail((e.target as HTMLInputElement).value)} + /> + + {error && ( +

+ {error} +

+ )} + + {success && ( +

+ {success} +

+ )} + + +
+ ); +} diff --git a/src/components/AuthenticationFlow/GitHubButton.tsx b/src/components/AuthenticationFlow/GitHubButton.tsx new file mode 100644 index 000000000000..6a97540b21da --- /dev/null +++ b/src/components/AuthenticationFlow/GitHubButton.tsx @@ -0,0 +1,169 @@ +import { useEffect, useState } from 'react'; +import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx'; +import { + FIRST_LOGIN_PARAM, + COURSE_PURCHASE_PARAM, + setAuthToken, +} from '../../lib/jwt'; +import { cn } from '../../lib/classname.ts'; +import { httpGet } from '../../lib/http'; +import { Spinner } from '../ReactIcons/Spinner.tsx'; +import { CHECKOUT_AFTER_LOGIN_KEY } from './CourseLoginPopup.tsx'; +import { getLastPath, triggerUtmRegistration, urlToId } from '../../lib/browser.ts'; + +type GitHubButtonProps = { + isDisabled?: boolean; + setIsDisabled?: (isDisabled: boolean) => void; + className?: string; +}; + +const GITHUB_REDIRECT_AT = 'githubRedirectAt'; +const GITHUB_LAST_PAGE = 'githubLastPage'; + +export function GitHubButton(props: GitHubButtonProps) { + const { isDisabled, setIsDisabled, className } = props; + + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + const state = urlParams.get('state'); + const provider = urlParams.get('provider'); + + if (!code || !state || provider !== 'github') { + return; + } + + setIsLoading(true); + setIsDisabled?.(true); + const lastPageBeforeGithub = localStorage.getItem(GITHUB_LAST_PAGE); + + httpGet<{ token: string; isNewUser: boolean }>( + `${import.meta.env.PUBLIC_API_URL}/v1-github-callback${ + window.location.search + }&src=${urlToId(lastPageBeforeGithub || getLastPath() || window.location.pathname)}`, + ) + .then(({ response, error }) => { + if (!response?.token) { + const errMessage = error?.message || 'Something went wrong.'; + setError(errMessage); + setIsLoading(false); + setIsDisabled?.(false); + + return; + } + + triggerUtmRegistration(); + + let redirectUrl = new URL('/', window.location.origin); + const gitHubRedirectAt = localStorage.getItem(GITHUB_REDIRECT_AT); + + // If the social redirect is there and less than 30 seconds old + // redirect to the page that user was on before they clicked the github login button + if (gitHubRedirectAt && lastPageBeforeGithub) { + const socialRedirectAtTime = parseInt(gitHubRedirectAt, 10); + const now = Date.now(); + const timeSinceRedirect = now - socialRedirectAtTime; + + if (timeSinceRedirect < 30 * 1000) { + redirectUrl = new URL(lastPageBeforeGithub, window.location.origin); + } + } + + const authRedirectUrl = localStorage.getItem('authRedirect'); + if (authRedirectUrl) { + localStorage.removeItem('authRedirect'); + redirectUrl = new URL(authRedirectUrl, window.location.origin); + } + + localStorage.removeItem(GITHUB_REDIRECT_AT); + localStorage.removeItem(GITHUB_LAST_PAGE); + setAuthToken(response.token); + + redirectUrl.searchParams.set( + FIRST_LOGIN_PARAM, + response?.isNewUser ? '1' : '0', + ); + + const shouldTriggerPurchase = + localStorage.getItem(CHECKOUT_AFTER_LOGIN_KEY) !== '0'; + + if ( + redirectUrl.pathname.includes('/courses/sql') && + shouldTriggerPurchase + ) { + redirectUrl.searchParams.set(COURSE_PURCHASE_PARAM, '1'); + localStorage.removeItem(CHECKOUT_AFTER_LOGIN_KEY); + } + + window.location.href = redirectUrl.toString(); + }) + .catch((err) => { + setError('Something went wrong. Please try again later.'); + setIsLoading(false); + setIsDisabled?.(false); + }); + }, []); + + const handleClick = async () => { + setIsLoading(true); + setIsDisabled?.(true); + + const { response, error } = await httpGet<{ loginUrl: string }>( + `${import.meta.env.PUBLIC_API_URL}/v1-github-login`, + ); + + if (error || !response?.loginUrl) { + setError( + error?.message || 'Something went wrong. Please try again later.', + ); + + setIsLoading(false); + setIsDisabled?.(false); + return; + } + + // For non authentication pages, we want to redirect back to the page + // the user was on before they clicked the social login button + if (!['/login', '/signup'].includes(window.location.pathname)) { + const pagePath = [ + '/respond-invite', + '/befriend', + '/r', + '/ai-roadmaps', + ].includes(window.location.pathname) + ? window.location.pathname + window.location.search + : window.location.pathname; + + localStorage.setItem(GITHUB_REDIRECT_AT, Date.now().toString()); + localStorage.setItem(GITHUB_LAST_PAGE, pagePath); + } + + window.location.href = response.loginUrl; + }; + + return ( + <> + + {error && ( +

{error}

+ )} + + ); +} diff --git a/src/components/AuthenticationFlow/GoogleButton.tsx b/src/components/AuthenticationFlow/GoogleButton.tsx new file mode 100644 index 000000000000..8f5e5ec64054 --- /dev/null +++ b/src/components/AuthenticationFlow/GoogleButton.tsx @@ -0,0 +1,168 @@ +import { useEffect, useState } from 'react'; +import { FIRST_LOGIN_PARAM, setAuthToken } from '../../lib/jwt'; +import { httpGet } from '../../lib/http'; +import { COURSE_PURCHASE_PARAM } from '../../lib/jwt'; +import { GoogleIcon } from '../ReactIcons/GoogleIcon.tsx'; +import { Spinner } from '../ReactIcons/Spinner.tsx'; +import { CHECKOUT_AFTER_LOGIN_KEY } from './CourseLoginPopup.tsx'; +import { triggerUtmRegistration, urlToId, getLastPath } from '../../lib/browser.ts'; +import { cn } from '../../lib/classname.ts'; + +type GoogleButtonProps = { + isDisabled?: boolean; + setIsDisabled?: (isDisabled: boolean) => void; + className?: string; +}; + +const GOOGLE_REDIRECT_AT = 'googleRedirectAt'; +const GOOGLE_LAST_PAGE = 'googleLastPage'; + +export function GoogleButton(props: GoogleButtonProps) { + const { isDisabled, setIsDisabled, className } = props; + + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + const state = urlParams.get('state'); + const provider = urlParams.get('provider'); + + if (!code || !state || provider !== 'google') { + return; + } + + setIsLoading(true); + setIsDisabled?.(true); + const lastPageBeforeGoogle = localStorage.getItem(GOOGLE_LAST_PAGE); + + httpGet<{ token: string; isNewUser: boolean }>( + `${import.meta.env.PUBLIC_API_URL}/v1-google-callback${ + window.location.search + }&src=${urlToId(lastPageBeforeGoogle || getLastPath() || window.location.pathname)}`, + ) + .then(({ response, error }) => { + if (!response?.token) { + setError(error?.message || 'Something went wrong.'); + setIsLoading(false); + setIsDisabled?.(false); + + return; + } + + triggerUtmRegistration(); + + let redirectUrl = new URL('/', window.location.origin); + const googleRedirectAt = localStorage.getItem(GOOGLE_REDIRECT_AT); + + // If the social redirect is there and less than 30 seconds old + // redirect to the page that user was on before they clicked the github login button + if (googleRedirectAt && lastPageBeforeGoogle) { + const socialRedirectAtTime = parseInt(googleRedirectAt, 10); + const now = Date.now(); + const timeSinceRedirect = now - socialRedirectAtTime; + + if (timeSinceRedirect < 30 * 1000) { + redirectUrl = new URL(lastPageBeforeGoogle, window.location.origin); + } + } + + const authRedirectUrl = localStorage.getItem('authRedirect'); + if (authRedirectUrl) { + localStorage.removeItem('authRedirect'); + redirectUrl = new URL(authRedirectUrl, window.location.origin); + } + + redirectUrl.searchParams.set( + FIRST_LOGIN_PARAM, + response?.isNewUser ? '1' : '0', + ); + + const shouldTriggerPurchase = + localStorage.getItem(CHECKOUT_AFTER_LOGIN_KEY) !== '0'; + if ( + redirectUrl.pathname.includes('/courses/sql') && + shouldTriggerPurchase + ) { + redirectUrl.searchParams.set(COURSE_PURCHASE_PARAM, '1'); + + localStorage.removeItem(CHECKOUT_AFTER_LOGIN_KEY); + } + + localStorage.removeItem(GOOGLE_REDIRECT_AT); + localStorage.removeItem(GOOGLE_LAST_PAGE); + setAuthToken(response.token); + + window.location.href = redirectUrl.toString(); + }) + .catch((err) => { + setError('Something went wrong. Please try again later.'); + setIsLoading(false); + setIsDisabled?.(false); + }); + }, []); + + const handleClick = () => { + setIsLoading(true); + setIsDisabled?.(true); + httpGet<{ loginUrl: string }>( + `${import.meta.env.PUBLIC_API_URL}/v1-google-login`, + ) + .then(({ response, error }) => { + if (!response?.loginUrl) { + setError(error?.message || 'Something went wrong.'); + setIsLoading(false); + setIsDisabled?.(false); + + return; + } + + // For non authentication pages, we want to redirect back to the page + // the user was on before they clicked the social login button + if (!['/login', '/signup'].includes(window.location.pathname)) { + const pagePath = [ + '/respond-invite', + '/befriend', + '/r', + '/ai-roadmaps', + ].includes(window.location.pathname) + ? window.location.pathname + window.location.search + : window.location.pathname; + + localStorage.setItem(GOOGLE_REDIRECT_AT, Date.now().toString()); + localStorage.setItem(GOOGLE_LAST_PAGE, pagePath); + } + + window.location.href = response.loginUrl; + }) + .catch((err) => { + setError('Something went wrong. Please try again later.'); + setIsLoading(false); + setIsDisabled?.(false); + }); + }; + + return ( + <> + + {error && ( +

{error}

+ )} + + ); +} diff --git a/src/components/AuthenticationFlow/LinkedInButton.tsx b/src/components/AuthenticationFlow/LinkedInButton.tsx new file mode 100644 index 000000000000..5021d9f90d1a --- /dev/null +++ b/src/components/AuthenticationFlow/LinkedInButton.tsx @@ -0,0 +1,173 @@ +import { useEffect, useState } from 'react'; +import { + FIRST_LOGIN_PARAM, + COURSE_PURCHASE_PARAM, + setAuthToken, +} from '../../lib/jwt'; +import { cn } from '../../lib/classname.ts'; +import { httpGet } from '../../lib/http'; +import { LinkedInIcon } from '../ReactIcons/LinkedInIcon.tsx'; +import { Spinner } from '../ReactIcons/Spinner.tsx'; +import { CHECKOUT_AFTER_LOGIN_KEY } from './CourseLoginPopup.tsx'; +import { getLastPath, triggerUtmRegistration, urlToId } from '../../lib/browser.ts'; + +type LinkedInButtonProps = { + isDisabled?: boolean; + setIsDisabled?: (isDisabled: boolean) => void; + className?: string; +}; + +const LINKEDIN_REDIRECT_AT = 'linkedInRedirectAt'; +const LINKEDIN_LAST_PAGE = 'linkedInLastPage'; + +export function LinkedInButton(props: LinkedInButtonProps) { + const { isDisabled, setIsDisabled, className } = props; + + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + const state = urlParams.get('state'); + const provider = urlParams.get('provider'); + + if (!code || !state || provider !== 'linkedin') { + return; + } + + setIsLoading(true); + setIsDisabled?.(true); + const lastPageBeforeLinkedIn = localStorage.getItem(LINKEDIN_LAST_PAGE); + + httpGet<{ token: string; isNewUser: boolean }>( + `${import.meta.env.PUBLIC_API_URL}/v1-linkedin-callback${ + window.location.search + }&src=${urlToId(lastPageBeforeLinkedIn || getLastPath() || window.location.pathname)}`, + ) + .then(({ response, error }) => { + if (!response?.token) { + setError(error?.message || 'Something went wrong.'); + setIsLoading(false); + setIsDisabled?.(false); + + return; + } + + triggerUtmRegistration(); + + let redirectUrl = new URL('/', window.location.origin); + const linkedInRedirectAt = localStorage.getItem(LINKEDIN_REDIRECT_AT); + + // If the social redirect is there and less than 30 seconds old + // redirect to the page that user was on before they clicked the github login button + if (linkedInRedirectAt && lastPageBeforeLinkedIn) { + const socialRedirectAtTime = parseInt(linkedInRedirectAt, 10); + const now = Date.now(); + const timeSinceRedirect = now - socialRedirectAtTime; + + if (timeSinceRedirect < 30 * 1000) { + redirectUrl = new URL( + lastPageBeforeLinkedIn, + window.location.origin, + ); + } + } + + const authRedirectUrl = localStorage.getItem('authRedirect'); + if (authRedirectUrl) { + localStorage.removeItem('authRedirect'); + redirectUrl = new URL(authRedirectUrl, window.location.origin); + } + + redirectUrl.searchParams.set( + FIRST_LOGIN_PARAM, + response?.isNewUser ? '1' : '0', + ); + + const shouldTriggerPurchase = + localStorage.getItem(CHECKOUT_AFTER_LOGIN_KEY) !== '0'; + if ( + redirectUrl.pathname.includes('/courses/sql') && + shouldTriggerPurchase + ) { + redirectUrl.searchParams.set(COURSE_PURCHASE_PARAM, '1'); + localStorage.removeItem(CHECKOUT_AFTER_LOGIN_KEY); + } + + localStorage.removeItem(LINKEDIN_REDIRECT_AT); + localStorage.removeItem(LINKEDIN_LAST_PAGE); + setAuthToken(response.token); + + window.location.href = redirectUrl.toString(); + }) + .catch((err) => { + setError('Something went wrong. Please try again later.'); + setIsLoading(false); + setIsDisabled?.(false); + }); + }, []); + + const handleClick = () => { + setIsLoading(true); + setIsDisabled?.(true); + httpGet<{ loginUrl: string }>( + `${import.meta.env.PUBLIC_API_URL}/v1-linkedin-login`, + ) + .then(({ response, error }) => { + if (!response?.loginUrl) { + setError(error?.message || 'Something went wrong.'); + setIsLoading(false); + setIsDisabled?.(false); + + return; + } + + // For non authentication pages, we want to redirect back to the page + // the user was on before they clicked the social login button + if (!['/login', '/signup'].includes(window.location.pathname)) { + const pagePath = [ + '/respond-invite', + '/befriend', + '/r', + '/ai-roadmaps', + ].includes(window.location.pathname) + ? window.location.pathname + window.location.search + : window.location.pathname; + + localStorage.setItem(LINKEDIN_REDIRECT_AT, Date.now().toString()); + localStorage.setItem(LINKEDIN_LAST_PAGE, pagePath); + } + + window.location.href = response.loginUrl; + }) + .catch((err) => { + setError('Something went wrong. Please try again later.'); + setIsLoading(false); + setIsDisabled?.(false); + }); + }; + + return ( + <> + + {error && ( +

{error}

+ )} + + ); +} diff --git a/src/components/AuthenticationFlow/LoginPopup.astro b/src/components/AuthenticationFlow/LoginPopup.astro new file mode 100644 index 000000000000..25ef117b3dde --- /dev/null +++ b/src/components/AuthenticationFlow/LoginPopup.astro @@ -0,0 +1,30 @@ +--- +import Popup from '../Popup/Popup.astro'; +import { AccountTerms } from '../AccountTerms'; +import { AuthenticationForm } from './AuthenticationForm'; +--- + + +
+

+ Login or Signup +

+

+ You must be logged in to perform this action. +

+
+ +
+ Don't have an account?{' '} + + Sign up + +
+ + +
diff --git a/src/components/AuthenticationFlow/ResetPasswordForm.tsx b/src/components/AuthenticationFlow/ResetPasswordForm.tsx new file mode 100644 index 000000000000..5e064ca29250 --- /dev/null +++ b/src/components/AuthenticationFlow/ResetPasswordForm.tsx @@ -0,0 +1,97 @@ +import { type FormEvent, useEffect, useState } from 'react'; +import { httpPost } from '../../lib/http'; +import Cookies from 'js-cookie'; +import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt'; + +export function ResetPasswordForm() { + const [code, setCode] = useState(''); + const [password, setPassword] = useState(''); + const [passwordConfirm, setPasswordConfirm] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + + if (!code) { + window.location.href = '/login'; + } else { + setCode(code); + } + }, []); + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + if (password !== passwordConfirm) { + setIsLoading(false); + setError('Passwords do not match.'); + return; + } + + const { response, error } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-reset-forgotten-password`, + { + newPassword: password, + confirmPassword: passwordConfirm, + code, + }, + ); + + if (error?.message) { + setIsLoading(false); + setError(error.message); + return; + } + + if (!response?.token) { + setIsLoading(false); + setError('Something went wrong. Please try again later.'); + return; + } + + const token = response.token; + setAuthToken(response.token); + window.location.href = '/'; + }; + + return ( +
+ setPassword((e.target as HTMLInputElement).value)} + /> + + + setPasswordConfirm((e.target as HTMLInputElement).value) + } + /> + + {error && ( +

{error}

+ )} + + +
+ ); +} diff --git a/src/components/AuthenticationFlow/TriggerVerifyAccount.tsx b/src/components/AuthenticationFlow/TriggerVerifyAccount.tsx new file mode 100644 index 000000000000..b97fb99e504d --- /dev/null +++ b/src/components/AuthenticationFlow/TriggerVerifyAccount.tsx @@ -0,0 +1,79 @@ +import { useEffect, useState } from 'react'; +import Cookies from 'js-cookie'; +import { httpPost } from '../../lib/http'; +import { + FIRST_LOGIN_PARAM, + TOKEN_COOKIE_NAME, + setAuthToken, +} from '../../lib/jwt'; +import { Spinner } from '../ReactIcons/Spinner'; +import { ErrorIcon2 } from '../ReactIcons/ErrorIcon2'; +import { triggerUtmRegistration } from '../../lib/browser.ts'; + +export function TriggerVerifyAccount() { + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(''); + + const triggerVerify = (code: string) => { + setIsLoading(true); + + httpPost<{ token: string; isNewUser: boolean }>( + `${import.meta.env.PUBLIC_API_URL}/v1-verify-account`, + { + code, + }, + ) + .then(({ response, error }) => { + if (!response?.token) { + setError(error?.message || 'Something went wrong. Please try again.'); + setIsLoading(false); + + return; + } + + triggerUtmRegistration(); + + setAuthToken(response.token); + + const url = new URL('/', window.location.origin); + url.searchParams.set( + FIRST_LOGIN_PARAM, + response?.isNewUser ? '1' : '0', + ); + window.location.href = url.toString(); + }) + .catch((err) => { + setIsLoading(false); + setError('Something went wrong. Please try again.'); + }); + }; + + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code')!; + + if (!code) { + setIsLoading(false); + setError('Something went wrong. Please try again later.'); + return; + } + + triggerVerify(code); + }, []); + + return ( +
+
+ {isLoading && } + {error && } +

+ Verifying your account +

+
+ {isLoading &&

Please wait while we verify your account..

} + {error &&

{error}

} +
+
+
+ ); +} diff --git a/src/components/AuthenticationFlow/TriggerVerifyEmail.tsx b/src/components/AuthenticationFlow/TriggerVerifyEmail.tsx new file mode 100644 index 000000000000..843c6875adca --- /dev/null +++ b/src/components/AuthenticationFlow/TriggerVerifyEmail.tsx @@ -0,0 +1,82 @@ +import { useEffect, useState } from 'react'; +import { httpPatch } from '../../lib/http'; +import { setAuthToken } from '../../lib/jwt'; +import { Spinner } from '../ReactIcons/Spinner'; +import { ErrorIcon2 } from '../ReactIcons/ErrorIcon2'; +import { getUrlParams } from '../../lib/browser'; +import { CheckIcon } from '../ReactIcons/CheckIcon'; + +export function TriggerVerifyEmail() { + const { code } = getUrlParams() as { code: string }; + + // const [isLoading, setIsLoading] = useState(true); + const [status, setStatus] = useState<'loading' | 'error' | 'success'>( + 'loading', + ); + const [error, setError] = useState(''); + + const triggerVerify = (code: string) => { + setStatus('loading'); + + httpPatch<{ token: string }>( + `${import.meta.env.PUBLIC_API_URL}/v1-verify-new-email/${code}`, + {}, + ) + .then(({ response, error }) => { + if (!response?.token) { + setError(error?.message || 'Something went wrong. Please try again.'); + setStatus('error'); + + return; + } + + setAuthToken(response.token); + setStatus('success'); + }) + .catch((err) => { + setStatus('error'); + setError('Something went wrong. Please try again.'); + }); + }; + + useEffect(() => { + if (!code) { + setStatus('error'); + setError('Something went wrong. Please try again later.'); + return; + } + + triggerVerify(code); + }, [code]); + + const isLoading = status === 'loading'; + if (status === 'success') { + return ( +
+ +

+ Email Update Successful +

+

+ Your email has been changed successfully. Happy learning! +

+
+ ); + } + + return ( +
+
+ {isLoading && } + {error && } +

+ Verifying your new Email +

+
+ {isLoading &&

Please wait while we verify your new Email.

} + {error &&

{error}

} +
+
+
+ ); +} diff --git a/src/components/AuthenticationFlow/VerificationEmailMessage.tsx b/src/components/AuthenticationFlow/VerificationEmailMessage.tsx new file mode 100644 index 000000000000..1774cd64ce7f --- /dev/null +++ b/src/components/AuthenticationFlow/VerificationEmailMessage.tsx @@ -0,0 +1,81 @@ +import { useEffect, useState } from 'react'; +import { httpPost } from '../../lib/http'; +import { VerifyLetterIcon } from '../ReactIcons/VerifyLetterIcon'; + +export function VerificationEmailMessage() { + const [email, setEmail] = useState('..'); + const [error, setError] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [isEmailResent, setIsEmailResent] = useState(false); + + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search); + + setEmail(urlParams.get('email')!); + }, []); + + const resendVerificationEmail = () => { + httpPost(`${import.meta.env.PUBLIC_API_URL}/v1-send-verification-email`, { + email, + }) + .then(({ response, error }) => { + if (error) { + setIsEmailResent(false); + setError(error?.message || 'Something went wrong.'); + setIsLoading(false); + return; + } + + setIsEmailResent(true); + }) + .catch(() => { + setIsEmailResent(false); + setIsLoading(false); + setError('Something went wrong. Please try again later.'); + }); + }; + + return ( +
+ +

+ Verify your email address +

+
+

+ We have sent you an email at{' '} + {email}. Please click the link to + verify your account. This link will expire shortly, so please verify + soon! +

+ +
+ + {!isEmailResent && ( + <> + {isLoading &&

Sending the email ..

} + {!isLoading && !error && ( +

+ Please make sure to check your spam folder. If you still don't + have the email click to{' '} + +

+ )} + + {error &&

{error}

} + + )} + + {isEmailResent && ( +

Verification email has been sent!

+ )} +
+
+ ); +} diff --git a/src/components/Authenticator/Authenticator.astro b/src/components/Authenticator/Authenticator.astro new file mode 100644 index 000000000000..c72f3e64c9e3 --- /dev/null +++ b/src/components/Authenticator/Authenticator.astro @@ -0,0 +1,4 @@ +--- +--- + + diff --git a/src/components/Authenticator/authenticator.ts b/src/components/Authenticator/authenticator.ts new file mode 100644 index 000000000000..03326a53bab8 --- /dev/null +++ b/src/components/Authenticator/authenticator.ts @@ -0,0 +1,107 @@ +import Cookies from 'js-cookie'; +import { TOKEN_COOKIE_NAME } from '../../lib/jwt'; +import { REDIRECT_PAGE_AFTER_AUTH } from '../../lib/auth'; + +function easeInElement(el: Element) { + el.classList.add('opacity-0', 'transition-opacity', 'duration-300'); + el.classList.remove('hidden', 'hidden!'); + setTimeout(() => { + el.classList.remove('opacity-0'); + }); +} + +function showHideAuthElements(hideOrShow: 'hide' | 'show' = 'hide') { + document.querySelectorAll('[data-auth-required]').forEach((el) => { + if (hideOrShow === 'hide') { + el.classList.add('hidden'); + } else { + easeInElement(el); + } + }); +} + +function showHideGuestElements(hideOrShow: 'hide' | 'show' = 'hide') { + document.querySelectorAll('[data-guest-required]').forEach((el) => { + if (hideOrShow === 'hide') { + el.classList.add('hidden'); + } else { + easeInElement(el); + } + }); +} + +// Prepares the UI for the user who is logged in +function handleGuest() { + const authenticatedRoutes = [ + '/account/update-profile', + '/account/notification', + '/account/update-password', + '/account/settings', + '/account/roadmaps', + '/account/road-card', + '/account/friends', + '/account', + '/team', + '/team/progress', + '/team/activity', + '/team/roadmaps', + '/team/new', + '/team/members', + '/team/member', + '/team/settings', + '/dashboard', + ]; + + showHideAuthElements('hide'); + showHideGuestElements('show'); + + // If the user is on an authenticated route, redirect them to the home page + if (authenticatedRoutes.includes(window.location.pathname)) { + localStorage.setItem(REDIRECT_PAGE_AFTER_AUTH, window.location.pathname); + window.location.href = '/login'; + } +} + +// Prepares the UI for the user who is logged out +function handleAuthenticated() { + const guestRoutes = [ + '/login', + '/signup', + '/verify-account', + '/verification-pending', + '/reset-password', + '/forgot-password', + ]; + + showHideGuestElements('hide'); + showHideAuthElements('show'); + + // If the user is on a guest route, redirect them to the home page + if (guestRoutes.includes(window.location.pathname)) { + const authRedirect = window.localStorage.getItem('authRedirect') || '/'; + window.localStorage.removeItem('authRedirect'); + + window.location.href = authRedirect; + } +} + +export function handleAuthRequired() { + const token = Cookies.get(TOKEN_COOKIE_NAME); + if (token) { + const pageAfterAuth = localStorage.getItem(REDIRECT_PAGE_AFTER_AUTH); + if (pageAfterAuth) { + localStorage.removeItem(REDIRECT_PAGE_AFTER_AUTH); + window.location.href = pageAfterAuth; + + return; + } + + handleAuthenticated(); + } else { + handleGuest(); + } +} + +window.setTimeout(() => { + handleAuthRequired(); +}, 0); diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx new file mode 100644 index 000000000000..ab3a370c44fa --- /dev/null +++ b/src/components/Badge.tsx @@ -0,0 +1,27 @@ +type BadgeProps = { + variant: 'blue' | 'green' | 'red' | 'yellow' | 'grey' | 'white'; + text: string; +}; + +export function Badge(type: BadgeProps) { + const { variant, text } = type; + + const colors = { + blue: 'bg-blue-100 text-blue-700 border-blue-200', + green: 'bg-green-100 text-green-700 border-green-200', + red: 'bg-red-100 text-red-700 border-red-200', + yellow: 'bg-yellow-100 text-yellow-700 border-yellow-200', + grey: 'bg-gray-100 text-gray-700 border-gray-200', + white: 'bg-white text-black border-gray-200', + teal: 'bg-teal-100 text-teal-700 border-teal-200', + black: 'bg-gray-500 text-white border-gray-500', + }; + + return ( + + {text} + + ); +} diff --git a/src/components/Befriend.tsx b/src/components/Befriend.tsx new file mode 100644 index 000000000000..807aec482f31 --- /dev/null +++ b/src/components/Befriend.tsx @@ -0,0 +1,368 @@ +import { useEffect, useState } from 'react'; +import { httpDelete, httpGet, httpPost } from '../lib/http'; +import { pageProgressMessage } from '../stores/page'; +import { isLoggedIn } from '../lib/jwt'; +import { showLoginPopup } from '../lib/popup'; +import { getUrlParams } from '../lib/browser'; +import { CheckIcon } from './ReactIcons/CheckIcon'; +import { DeleteUserIcon } from './ReactIcons/DeleteUserIcon'; +import { useToast } from '../hooks/use-toast'; +import { useAuth } from '../hooks/use-auth'; +import { AddedUserIcon } from './ReactIcons/AddedUserIcon'; +import { StopIcon } from './ReactIcons/StopIcon'; +import { ErrorIcon } from './ReactIcons/ErrorIcon'; + +export type FriendshipStatus = + | 'none' + | 'sent' + | 'received' + | 'accepted' + | 'rejected' + | 'got_rejected'; + +type UserResponse = { + id: string; + links: Record; + avatar: string; + name: string; + status: FriendshipStatus; +}; + +export function Befriend() { + const { u: inviteId } = getUrlParams(); + + const toast = useToast(); + const currentUser = useAuth(); + + const [isConfirming, setIsConfirming] = useState(false); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(''); + const [user, setUser] = useState(); + const isAuthenticated = isLoggedIn(); + + async function loadUser(userId: string) { + const { response, error } = await httpGet( + `${import.meta.env.PUBLIC_API_URL}/v1-get-friend/${userId}` + ); + if (error || !response) { + setError(error?.message || 'Something went wrong'); + return; + } + + if (response.status === 'accepted') { + window.location.href = '/account/friends?c=fa'; + return; + } + + setUser(response); + } + + useEffect(() => { + if (inviteId) { + loadUser(inviteId).finally(() => { + pageProgressMessage.set(''); + setIsLoading(false); + }); + } else { + setIsLoading(false); + setError('Missing invite ID in URL'); + pageProgressMessage.set(''); + } + }, [inviteId]); + + async function addFriend(userId: string, successMessage: string) { + pageProgressMessage.set('Please wait...'); + setError(''); + const { response, error } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-add-friend/${userId}`, + {} + ); + + if (error || !response) { + setError(error?.message || 'Something went wrong'); + return; + } + + if (response.status === 'accepted') { + window.location.href = '/account/friends?c=fa'; + return; + } + + setUser(response); + } + + async function deleteFriend(userId: string, successMessage: string) { + pageProgressMessage.set('Please wait...'); + setError(''); + const { response, error } = await httpDelete( + `${import.meta.env.PUBLIC_API_URL}/v1-delete-friend/${userId}`, + {} + ); + + if (error || !response) { + setError(error?.message || 'Something went wrong'); + return; + } + + setUser(response); + toast.success(successMessage); + } + + if (isLoading) { + return null; + } + + if (!user) { + return ( +
+ + +

Error

+

+ {error || 'There was a problem, please try again.'} +

+ + +
+ ); + } + + const userAvatar = user.avatar + ? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${user.avatar}` + : '/img/default-avatar.png'; + + const isMe = currentUser?.id === user.id; + + return ( +
+ {'join + +

{user.name}

+

+ After you add {user.name} as a friend, you will be able to view each + other's skills and progress. +

+ +
+
+ {user.status === 'none' && ( + + )} + + {user.status === 'sent' && ( + <> + + + Request Sent + + + {!isConfirming && ( + + )} + + {isConfirming && ( + + Are you sure?{' '} + {' '} + + + )} + + )} + + {user.status === 'accepted' && ( + <> + + + You are friends + + + {!isConfirming && ( + + )} + + {isConfirming && ( + + Are you sure?{' '} + {' '} + + + )} + + )} + + {user.status === 'rejected' && ( + <> + + + Request Rejected + + + + Changed your mind?{' '} + + + + )} + + {user.status === 'got_rejected' && ( + <> + + + Request Rejected + + + )} + + {user.status === 'received' && ( + <> + + + {!isConfirming && ( + + )} + + {isConfirming && ( + + Are you sure?{' '} + {' '} + + + )} + + )} +
+
+ + {error && ( +

{error}

+ )} +
+ ); +} diff --git a/src/components/BestPracticeHeader.astro b/src/components/BestPracticeHeader.astro new file mode 100644 index 000000000000..1452aa8e82ce --- /dev/null +++ b/src/components/BestPracticeHeader.astro @@ -0,0 +1,95 @@ +--- +import Icon from './AstroIcon.astro'; +import LoginPopup from './AuthenticationFlow/LoginPopup.astro'; +import BestPracticeHint from './BestPracticeHint.astro'; +import { MarkFavorite } from './FeaturedItems/MarkFavorite'; +import ProgressHelpPopup from './ProgressHelpPopup.astro'; + +export interface Props { + title: string; + description: string; + bestPracticeId: string; + isUpcoming?: boolean; +} + +const { title, description, bestPracticeId, isUpcoming = false } = Astro.props; +const isBestPracticeReady = !isUpcoming; +--- + + + + +
+
+
+

+ {title} + +

+

{description}

+
+ +
+
+ + ← + + + { + isBestPracticeReady && ( + + ) + } + + { + isBestPracticeReady && ( + + + + + ) + } +
+ + { + isBestPracticeReady && ( + + + + Suggest + + ) + } +
+ + +
+
diff --git a/src/components/BestPracticeHint.astro b/src/components/BestPracticeHint.astro new file mode 100644 index 000000000000..dcc40f328ad6 --- /dev/null +++ b/src/components/BestPracticeHint.astro @@ -0,0 +1,11 @@ +--- +import ResourceProgressStats from './ResourceProgressStats.astro'; +export interface Props { + bestPracticeId: string; +} +const { bestPracticeId } = Astro.props; +--- + +
+ +
diff --git a/src/components/Billing/BillingPage.tsx b/src/components/Billing/BillingPage.tsx new file mode 100644 index 000000000000..ffcc3155e384 --- /dev/null +++ b/src/components/Billing/BillingPage.tsx @@ -0,0 +1,300 @@ +import { useEffect, useState } from 'react'; +import { pageProgressMessage } from '../../stores/page'; +import { useToast } from '../../hooks/use-toast'; +import { useMutation, useQuery } from '@tanstack/react-query'; +import { + billingDetailsOptions, + USER_SUBSCRIPTION_PLAN_PRICES, +} from '../../queries/billing'; +import { queryClient } from '../../stores/query-client'; +import { httpPost } from '../../lib/query-http'; +import { UpgradeAccountModal } from './UpgradeAccountModal'; +import { getUrlParams } from '../../lib/browser'; +import { VerifyUpgrade } from './VerifyUpgrade'; +import { EmptyBillingScreen } from './EmptyBillingScreen'; +import { + Calendar, + RefreshCw, + Loader2, + CreditCard, + ArrowRightLeft, + CircleX, + AlertCircle, +} from 'lucide-react'; +import { BillingWarning } from './BillingWarning'; +import { cn } from '../../lib/classname'; + +export type CreateCustomerPortalBody = {}; + +export type CreateCustomerPortalResponse = { + url: string; +}; + +export function BillingPage() { + const toast = useToast(); + + const [showUpgradeModal, setShowUpgradeModal] = useState(false); + const [showVerifyUpgradeModal, setShowVerifyUpgradeModal] = useState(false); + + const { data: billingDetails, isPending: isLoadingBillingDetails } = useQuery( + billingDetailsOptions(), + queryClient, + ); + + const willBeCanceled = billingDetails?.cancelAtPeriodEnd; + const isCanceled = billingDetails?.status === 'canceled'; + + const isPastDue = billingDetails?.status === 'past_due'; + const isIncomplete = billingDetails?.status === 'incomplete'; + const isIncompleteExpired = billingDetails?.status === 'incomplete_expired'; + + const { + mutate: createCustomerPortal, + isSuccess: isCreatingCustomerPortalSuccess, + isPending: isCreatingCustomerPortal, + } = useMutation( + { + mutationFn: (body: CreateCustomerPortalBody) => { + return httpPost( + '/v1-create-customer-portal', + body, + ); + }, + onSuccess: (data) => { + window.location.href = data.url; + }, + onError: (error) => { + console.error(error); + toast.error(error?.message || 'Failed to Create Customer Portal'); + }, + }, + queryClient, + ); + + useEffect(() => { + if (isLoadingBillingDetails) { + return; + } + + pageProgressMessage.set(''); + const shouldVerifyUpgrade = getUrlParams()?.s === '1'; + if (shouldVerifyUpgrade) { + setShowVerifyUpgradeModal(true); + } + }, [isLoadingBillingDetails]); + + if (isLoadingBillingDetails || !billingDetails) { + return null; + } + + const selectedPlanDetails = USER_SUBSCRIPTION_PLAN_PRICES.find( + (plan) => plan.priceId === billingDetails?.priceId, + ); + const priceDetails = selectedPlanDetails; + + const formattedNextBillDate = new Date( + billingDetails?.currentPeriodEnd || '', + ).toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric', + }); + + const modals = ( + <> + {showUpgradeModal && ( + { + setShowUpgradeModal(false); + }} + /> + )} + + {showVerifyUpgradeModal && } + + ); + + if (billingDetails?.status === 'none' || isIncompleteExpired) { + return ( + <> + {modals} + setShowUpgradeModal(true)} /> + + ); + } + + if (isCanceled) { + return ( + <> + {modals} + { + if (willBeCanceled) { + createCustomerPortal({}); + } else { + setShowUpgradeModal(true); + } + }} + isLoading={ + isCreatingCustomerPortal || isCreatingCustomerPortalSuccess + } + /> + + setShowUpgradeModal(true)} /> + + ); + } + + if (isIncomplete) { + return ( + <> + {modals} + { + createCustomerPortal({}); + }} + isLoading={ + isCreatingCustomerPortal || isCreatingCustomerPortalSuccess + } + /> + + setShowUpgradeModal(true)} /> + + ); + } + + if (!priceDetails) { + return ( +
+

Uh oh!

+

+ We couldn't find your subscription details. Please contact support at + + info@roadmap.sh + + . +

+
+ ); + } + + return ( + <> + {modals} + +
+ {isPastDue && ( + { + createCustomerPortal({}); + }} + isLoading={ + isCreatingCustomerPortal || isCreatingCustomerPortalSuccess + } + /> + )} + + {willBeCanceled && ( + { + createCustomerPortal({}); + }} + isLoading={ + isCreatingCustomerPortal || isCreatingCustomerPortalSuccess + } + /> + )} + +

+ Current Subscription +

+ +

+ Thank you for being a pro member. Your plan details are below. +

+ +
+
+
+ +
+
+ + Payment + +

+ ${priceDetails.amount} + + / {priceDetails.interval} + +

+
+
+
+ +
+
+
+ +
+
+ + {willBeCanceled ? 'Expires On' : 'Renews On'} + +

+ {formattedNextBillDate} +

+
+
+ +
+ {!willBeCanceled && ( + + )} + +
+
+
+ + ); +} diff --git a/src/components/Billing/BillingWarning.tsx b/src/components/Billing/BillingWarning.tsx new file mode 100644 index 000000000000..f71cce994e19 --- /dev/null +++ b/src/components/Billing/BillingWarning.tsx @@ -0,0 +1,39 @@ +import { AlertTriangle, type LucideIcon } from 'lucide-react'; + +export type BillingWarningProps = { + icon?: LucideIcon; + message: string; + onButtonClick?: () => void; + buttonText?: string; + isLoading?: boolean; +}; + +export function BillingWarning(props: BillingWarningProps) { + const { + message, + onButtonClick, + buttonText, + isLoading, + icon: Icon = AlertTriangle, + } = props; + + return ( +
+ + + {message} + {buttonText && ( + + )} + +
+ ); +} diff --git a/src/components/Billing/CheckSubscriptionVerification.tsx b/src/components/Billing/CheckSubscriptionVerification.tsx new file mode 100644 index 000000000000..b5266546e3c5 --- /dev/null +++ b/src/components/Billing/CheckSubscriptionVerification.tsx @@ -0,0 +1,22 @@ +import { useEffect, useState } from 'react'; +import { getUrlParams } from '../../lib/browser'; +import { VerifyUpgrade } from "./VerifyUpgrade"; + +export function CheckSubscriptionVerification() { + const [shouldVerifyUpgrade, setShouldVerifyUpgrade] = useState(false); + + useEffect(() => { + const params = getUrlParams(); + if (params.s !== '1') { + return; + } + + setShouldVerifyUpgrade(true); + }, []); + + if (!shouldVerifyUpgrade) { + return null; + } + + return ; +} diff --git a/src/components/Billing/EmptyBillingScreen.tsx b/src/components/Billing/EmptyBillingScreen.tsx new file mode 100644 index 000000000000..c78222459770 --- /dev/null +++ b/src/components/Billing/EmptyBillingScreen.tsx @@ -0,0 +1,68 @@ +import { + CreditCard, + Ellipsis, + HeartHandshake, + MessageCircleIcon, + SparklesIcon, + Zap, +} from 'lucide-react'; + +type EmptyBillingScreenProps = { + onUpgrade: () => void; +}; + +const perks = [ + { + icon: Zap, + text: 'Unlimited AI course generations', + }, + { + icon: MessageCircleIcon, + text: 'Unlimited AI Chat feature usage', + }, + { + icon: SparklesIcon, + text: 'Early access to new features', + }, + { + icon: HeartHandshake, + text: 'Support the development of platform', + }, + { + icon: Ellipsis, + text: 'more perks coming soon!', + }, +]; + +export function EmptyBillingScreen(props: EmptyBillingScreenProps) { + const { onUpgrade } = props; + + return ( +
+ +

+ No Active Subscription +

+ +

+ Unlock pro benefits by upgrading to a subscription +

+ +
+ {perks.map((perk) => ( +

+ + {perk.text} +

+ ))} +
+ + +
+ ); +} diff --git a/src/components/Billing/GlobalUpgradeModal.tsx b/src/components/Billing/GlobalUpgradeModal.tsx new file mode 100644 index 000000000000..7ac08c43b39d --- /dev/null +++ b/src/components/Billing/GlobalUpgradeModal.tsx @@ -0,0 +1,16 @@ +import { useStore } from '@nanostores/react'; +import { + hideUpgradeModal, + isUpgradeModalOpen, +} from '../../stores/subscription'; +import { UpgradeAccountModal } from './UpgradeAccountModal'; + +export function GlobalUpgradeModal() { + const isOpen = useStore(isUpgradeModalOpen); + + if (!isOpen) { + return null; + } + + return ; +} diff --git a/src/components/Billing/UpdatePlanConfirmation.tsx b/src/components/Billing/UpdatePlanConfirmation.tsx new file mode 100644 index 000000000000..c14952f0459a --- /dev/null +++ b/src/components/Billing/UpdatePlanConfirmation.tsx @@ -0,0 +1,96 @@ +import { useMutation } from '@tanstack/react-query'; +import type { USER_SUBSCRIPTION_PLAN_PRICES } from '../../queries/billing'; +import { Modal } from '../Modal'; +import { queryClient } from '../../stores/query-client'; +import { useToast } from '../../hooks/use-toast'; +import { VerifyUpgrade } from './VerifyUpgrade'; +import { Loader2Icon } from 'lucide-react'; +import { httpPost } from '../../lib/query-http'; + +type UpdatePlanBody = { + priceId: string; +}; + +type UpdatePlanResponse = { + status: 'ok'; +}; + +type UpdatePlanConfirmationProps = { + planDetails: (typeof USER_SUBSCRIPTION_PLAN_PRICES)[number]; + onClose: () => void; + onCancel: () => void; +}; + +export function UpdatePlanConfirmation(props: UpdatePlanConfirmationProps) { + const { planDetails, onClose, onCancel } = props; + + const toast = useToast(); + const { + mutate: updatePlan, + isPending, + status, + } = useMutation( + { + mutationFn: (body: UpdatePlanBody) => { + return httpPost( + '/v1-update-subscription-plan', + body, + ); + }, + onError: (error) => { + console.error(error); + toast.error(error?.message || 'Failed to Create Customer Portal'); + }, + }, + queryClient, + ); + + if (!planDetails) { + return null; + } + + const selectedPrice = planDetails; + if (status === 'success') { + return ; + } + + return ( + {} : onClose} + bodyClassName="rounded-xl bg-white p-6" + > +

Subscription Update

+

+ Your plan will be updated to the{' '} + {planDetails.interval} plan, and will be + charged{' '} + + ${selectedPrice.amount}/{selectedPrice.interval} + + . +

+ +
+ + +
+
+ ); +} diff --git a/src/components/Billing/UpgradeAccountModal.tsx b/src/components/Billing/UpgradeAccountModal.tsx new file mode 100644 index 000000000000..4fdd291274a8 --- /dev/null +++ b/src/components/Billing/UpgradeAccountModal.tsx @@ -0,0 +1,368 @@ +import { useMutation, useQuery } from '@tanstack/react-query'; +import type { LucideIcon } from 'lucide-react'; +import { + Archive, + Crown, + Loader2, + Map, + MessageCircleIcon, + X, + Zap, +} from 'lucide-react'; +import { useEffect, useState } from 'react'; +import { useToast } from '../../hooks/use-toast'; +import { getUser } from '../../lib/jwt'; +import { httpPost } from '../../lib/query-http'; +import { + billingDetailsOptions, + USER_SUBSCRIPTION_PLAN_PRICES, + type AllowedSubscriptionInterval, +} from '../../queries/billing'; +import { queryClient } from '../../stores/query-client'; +import { Modal } from '../Modal'; +import { UpdatePlanConfirmation } from './UpdatePlanConfirmation'; + +type Perk = { + icon: LucideIcon; + title: string; + description: string; + highlight?: boolean; +}; + +const PREMIUM_PERKS: Perk[] = [ + { + icon: Zap, + title: 'Unlimited Courses and Guides', + description: 'No limits on number of courses, guides, and quizzes', + highlight: true, + }, + { + icon: MessageCircleIcon, + title: 'Extended Chat Limits', + description: 'Chat with AI Tutor and Roadmaps without limits', + }, + { + icon: Archive, + title: 'Chat History', + description: 'Access your AI Tutor and roadmap chats later', + }, + { + icon: Map, + title: 'Custom Roadmaps', + description: 'Create upto 100 custom roadmaps', + }, +]; + +type CreateSubscriptionCheckoutSessionBody = { + priceId: string; + success?: string; + cancel?: string; +}; + +type CreateSubscriptionCheckoutSessionResponse = { + checkoutUrl: string; +}; + +type UpgradeAccountModalProps = { + onClose: () => void; + success?: string; + cancel?: string; +}; + +export function UpgradeAccountModal(props: UpgradeAccountModalProps) { + const { onClose, success, cancel } = props; + + const [selectedPlan, setSelectedPlan] = + useState('year'); + const [isUpdatingPlan, setIsUpdatingPlan] = useState(false); + + const user = getUser(); + + const { + data: userBillingDetails, + isLoading, + error: billingError, + } = useQuery(billingDetailsOptions(), queryClient); + + const toast = useToast(); + + const { + mutate: createCheckoutSession, + isPending: isCreatingCheckoutSession, + } = useMutation( + { + mutationFn: (body: CreateSubscriptionCheckoutSessionBody) => { + return httpPost( + '/v1-create-subscription-checkout-session', + body, + ); + }, + onSuccess: (data) => { + window.location.href = data.checkoutUrl; + }, + onError: (error) => { + console.error(error); + toast.error(error?.message || 'Failed to create checkout session'); + }, + }, + queryClient, + ); + + const isCanceled = ['canceled', 'incomplete_expired'].includes( + userBillingDetails?.status || '', + ); + + const selectedPlanDetails = USER_SUBSCRIPTION_PLAN_PRICES.find( + (plan) => plan.interval === selectedPlan, + ); + const currentPlanPriceId = isCanceled ? null : userBillingDetails?.priceId; + const currentPlan = USER_SUBSCRIPTION_PLAN_PRICES.find( + (plan) => plan.priceId === currentPlanPriceId, + ); + + const monthlyPlan = USER_SUBSCRIPTION_PLAN_PRICES.find( + (p) => p.interval === 'month', + ); + const yearlyPlan = USER_SUBSCRIPTION_PLAN_PRICES.find( + (p) => p.interval === 'year', + ); + + useEffect(() => { + if (!currentPlan) { + return; + } + setSelectedPlan(currentPlan.interval); + }, [currentPlan]); + + useEffect(() => { + window?.fireEvent({ + action: 'tutor_pricing', + category: 'ai_tutor', + label: 'Clicked Upgrade to Pro', + }); + }, []); + + if (!user) { + return null; + } + + if (isLoading) { + return ( + +
+ +
+
+ ); + } + + if (billingError) { + return ( + +
+
+ +
+

Error

+

+ {billingError?.message || + 'An error occurred while loading billing details.'} +

+
+
+ ); + } + + if (isUpdatingPlan && selectedPlanDetails) { + return ( + setIsUpdatingPlan(false)} + onCancel={() => setIsUpdatingPlan(false)} + /> + ); + } + + const handlePlanSelect = (plan: typeof selectedPlanDetails) => { + if (!plan) return; + + setSelectedPlan(plan.interval); + + if (!currentPlanPriceId) { + const currentUrlPath = window.location.pathname; + const encodedCurrentUrlPath = encodeURIComponent(currentUrlPath); + const successPage = `/thank-you?next=${encodedCurrentUrlPath}&s=1`; + + window?.fireEvent({ + action: 'tutor_checkout', + category: 'ai_tutor', + label: 'Checkout Started', + }); + + createCheckoutSession( + { + priceId: plan.priceId, + success: success || successPage, + cancel: cancel || `${currentUrlPath}?s=0`, + }, + { + onSuccess: () => { + window?.fireEvent({ + action: `tutor_checkout_${plan.interval === 'month' ? 'mo' : 'an'}`, + category: 'ai_tutor', + label: `${plan.interval} Plan Checkout Started`, + }); + }, + }, + ); + return; + } + setIsUpdatingPlan(true); + }; + + return ( + +
+ {/* Close button */} + + + {/* Header */} +
+
+ +
+

+ Upgrade to Premium +

+

+ Unlock all features and supercharge your learning +

+
+ + {/* Features List */} +
+
+ {PREMIUM_PERKS.map((perk, index) => { + const Icon = perk.icon; + return ( +
+ +
+

+ {perk.title} +

+

{perk.description}

+
+
+ ); + })} +
+
+ + {/* Buttons */} +
+
+ {/* Yearly Button */} + {yearlyPlan && ( + + )} + + {/* Monthly Button */} + {monthlyPlan && ( + + )} +
+ + {/* Trust indicators */} +
+

+ By upgrading you agree to our{' '} + + terms and conditions + +

+
+
+
+
+ ); +} diff --git a/src/components/Billing/VerifyUpgrade.tsx b/src/components/Billing/VerifyUpgrade.tsx new file mode 100644 index 000000000000..85b0142abbbd --- /dev/null +++ b/src/components/Billing/VerifyUpgrade.tsx @@ -0,0 +1,105 @@ +import { useEffect } from 'react'; +import { Loader2, CheckCircle } from 'lucide-react'; +import { useQuery } from '@tanstack/react-query'; +import { billingDetailsOptions } from '../../queries/billing'; +import { queryClient } from '../../stores/query-client'; +import { Modal } from '../Modal'; +import { deleteUrlParam } from '../../lib/browser'; + +type VerifyUpgradeProps = { + newPriceId?: string; +}; + +export function VerifyUpgrade(props: VerifyUpgradeProps) { + const { newPriceId } = props; + + const { data: userBillingDetails } = useQuery( + { + ...billingDetailsOptions(), + refetchInterval: 1000, + }, + queryClient, + ); + + useEffect(() => { + if (!userBillingDetails) { + return; + } + + if ( + userBillingDetails.status === 'active' && + (newPriceId ? userBillingDetails.priceId === newPriceId : true) + ) { + if (!newPriceId) { + // it means that the user is subscribing for the first time + // not changing the plan + window?.fireEvent({ + action: `tutor_purchase_${userBillingDetails.interval === 'month' ? 'mo' : 'an'}`, + category: 'ai_tutor', + label: `${userBillingDetails.interval} Plan Purchased`, + }); + } + + deleteUrlParam('s'); + window.location.reload(); + } + }, [userBillingDetails]); + + useEffect(() => { + // it means that the user is changing the plan + // not subscribing for the first time + if (newPriceId) { + return; + } + + window?.fireEvent({ + action: 'tutor_purchase', + category: 'ai_tutor', + label: 'Subscription Activated', + }); + window?.fireEvent({ + action: 'tutor_ty', + category: 'ai_tutor', + label: 'Thank You Page Visited', + }); + }, [newPriceId]); + + return ( + {}} + bodyClassName="rounded-xl bg-white p-6" + > +
+ +

Subscription Activated

+
+ +

+ Your subscription has been activated successfully. +

+ +

+ It might take a minute for the changes to reflect. We will{' '} + reload the page for you. +

+ +
+ + Please wait... +
+ +

+ If it takes longer than expected, please email us at{' '} + + info@roadmap.sh + + . +

+
+ ); +} diff --git a/src/components/Changelog/ChangelogItem.astro b/src/components/Changelog/ChangelogItem.astro new file mode 100644 index 000000000000..cfd9b4187b83 --- /dev/null +++ b/src/components/Changelog/ChangelogItem.astro @@ -0,0 +1,46 @@ +--- +import { DateTime } from 'luxon'; +import ChangelogImages from '../ChangelogImages'; +import type { ChangelogDocument } from '../../queries/changelog'; + +interface Props { + changelog: ChangelogDocument; +} + +const { changelog } = Astro.props; + +const formattedDate = DateTime.fromISO(changelog.createdAt).toFormat( + 'dd LLL, yyyy', +); +--- + +
+ + +
+ + {formattedDate} + + + {changelog.title} + +
+ +
+ { + changelog.images && ( + + ) + } + +
+
+
diff --git a/src/components/Changelog/ChangelogLaunch.astro b/src/components/Changelog/ChangelogLaunch.astro new file mode 100644 index 000000000000..29af20b0f663 --- /dev/null +++ b/src/components/Changelog/ChangelogLaunch.astro @@ -0,0 +1,33 @@ +--- +import { DateTime } from 'luxon'; + +const formattedDate = DateTime.fromISO('2024-09-13').toFormat('dd LLL, yyyy'); +--- + +
+ + +
+ + {formattedDate} + + + Changelog page is launched + +
+ +
+ +

Changelog page is launched

+

+ We will be sharing a selected list of updates, improvements, and fixes made to + the website. Stay tuned! +

+
+
diff --git a/src/components/ChangelogBanner.astro b/src/components/ChangelogBanner.astro new file mode 100644 index 000000000000..3b927f7ab222 --- /dev/null +++ b/src/components/ChangelogBanner.astro @@ -0,0 +1,76 @@ +--- +import { listChangelog } from '../queries/changelog'; +import { DateTime } from 'luxon'; +import AstroIcon from './AstroIcon.astro'; + +const changelogs = await listChangelog({ limit: 10 }); +--- + +
+
+

+ + Actively Maintained +

+

+ We are always improving our content, adding new resources and adding + features to enhance your learning experience. +

+ +
+ + +
+
+ + View Full Changelog + + +
+
+
diff --git a/src/components/ChangelogImages.tsx b/src/components/ChangelogImages.tsx new file mode 100644 index 000000000000..1780c7a07360 --- /dev/null +++ b/src/components/ChangelogImages.tsx @@ -0,0 +1,109 @@ +import { ChevronLeft, ChevronRight } from 'lucide-react'; +import React, { useState, useEffect, useCallback } from 'react'; +import type { ChangelogImage } from '../queries/changelog'; + +interface ChangelogImagesProps { + images: ChangelogImage[]; +} + +const ChangelogImages: React.FC = ({ images }) => { + const [enlargedImage, setEnlargedImage] = useState(null); + const imageArray = images.map((image) => [image.title, image.url]); + + const handleImageClick = (src: string) => { + setEnlargedImage(src); + }; + + const handleCloseEnlarged = () => { + setEnlargedImage(null); + }; + + const handleNavigation = useCallback( + (direction: 'prev' | 'next') => { + if (!enlargedImage) return; + const currentIndex = imageArray.findIndex( + ([_, src]) => src === enlargedImage, + ); + let newIndex; + if (direction === 'prev') { + newIndex = currentIndex > 0 ? currentIndex - 1 : imageArray.length - 1; + } else { + newIndex = currentIndex < imageArray.length - 1 ? currentIndex + 1 : 0; + } + setEnlargedImage(imageArray[newIndex][1]); + }, + [enlargedImage, imageArray], + ); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + handleCloseEnlarged(); + } else if (event.key === 'ArrowLeft') { + handleNavigation('prev'); + } else if (event.key === 'ArrowRight') { + handleNavigation('next'); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [handleNavigation]); + + return ( + <> +
+ {imageArray.map(([title, src]) => ( +
handleImageClick(src)} + > + {title} + + +
+ {title} +
+
+ ))} +
+ {enlargedImage && ( +
+ Enlarged view + + +
+ )} + + ); +}; + +export default ChangelogImages; diff --git a/src/components/ChatEditor/ChatEditor.css b/src/components/ChatEditor/ChatEditor.css new file mode 100644 index 000000000000..d5ff8dca4fc7 --- /dev/null +++ b/src/components/ChatEditor/ChatEditor.css @@ -0,0 +1,25 @@ +.chat-editor .tiptap p.is-editor-empty:first-child::before { + color: #adb5bd; + content: attr(data-placeholder); + float: left; + height: 0; + pointer-events: none; +} + +.chat-editor .tiptap p:first-child.is-empty::before { + color: #adb5bd; + content: attr(data-placeholder); + float: left; + height: 0; + pointer-events: none; +} + +.chat-editor .tiptap [data-type='variable'] { + font-size: 12px; + font-weight: 500; + line-height: 1.5; + padding: 2px 4px; + border-radius: 8px; + background-color: #f0f5ff; + color: #2c5df1; +} diff --git a/src/components/ChatEditor/ChatEditor.tsx b/src/components/ChatEditor/ChatEditor.tsx new file mode 100644 index 000000000000..7361cb4c9577 --- /dev/null +++ b/src/components/ChatEditor/ChatEditor.tsx @@ -0,0 +1,122 @@ +import './ChatEditor.css'; + +import { + Editor, + EditorContent, + useEditor, + type JSONContent, +} from '@tiptap/react'; +import DocumentExtension from '@tiptap/extension-document'; +import ParagraphExtension from '@tiptap/extension-paragraph'; +import TextExtension from '@tiptap/extension-text'; +import Placeholder from '@tiptap/extension-placeholder'; +import { VariableExtension } from './VariableExtension/VariableExtension'; +import { variableSuggestion } from './VariableExtension/VariableSuggestion'; +import { queryClient } from '../../stores/query-client'; +import { roadmapTreeMappingOptions } from '../../queries/roadmap-tree'; +import { useQuery } from '@tanstack/react-query'; +import { useEffect, type RefObject } from 'react'; +import { roadmapDetailsOptions } from '../../queries/roadmap'; + +const extensions = [ + DocumentExtension, + ParagraphExtension, + TextExtension, + Placeholder.configure({ + placeholder: 'Ask AI anything about the roadmap...', + }), + VariableExtension.configure({ + suggestion: variableSuggestion(), + }), +]; + +const content = '

'; + +type ChatEditorProps = { + editorRef: RefObject; + roadmapId: string; + onSubmit: (content: JSONContent) => void; +}; + +export function ChatEditor(props: ChatEditorProps) { + const { roadmapId, onSubmit, editorRef } = props; + + const { data: roadmapTreeData } = useQuery( + roadmapTreeMappingOptions(roadmapId), + queryClient, + ); + + const { data: roadmapDetailsData } = useQuery( + roadmapDetailsOptions(roadmapId), + queryClient, + ); + + const editor = useEditor({ + extensions, + content, + editorProps: { + attributes: { + class: 'focus:outline-none w-full px-4 py-2 min-h-[40px]', + }, + handleKeyDown(_, event) { + if (!editor) { + return false; + } + + if (event.key === 'Enter' && !event.shiftKey) { + // check if the variable suggestion list is focused + // if it is, return false so the default behavior is not triggered + const variableSuggestionList = document.getElementById( + 'variable-suggestion-list', + ); + if (variableSuggestionList) { + return false; + } + + event.preventDefault(); + onSubmit(editor.getJSON()); + return true; + } + + if (event.key === 'Enter' && event.shiftKey) { + event.preventDefault(); + editor.commands.insertContent([ + { type: 'text', text: ' ' }, + { type: 'paragraph' }, + ]); + return true; + } + + return false; + }, + }, + onUpdate: ({ editor }) => { + editorRef.current = editor; + }, + onDestroy: () => { + editorRef.current = null; + }, + }); + + useEffect(() => { + if (!editor || !roadmapTreeData || !roadmapDetailsData) { + return; + } + + editor.storage.variable.variables = roadmapTreeData.map((mapping) => { + return { + id: mapping.nodeId, + // to remove the title of the roadmap + // and only keep the path + // e.g. "Roadmap > Topic > Subtopic" -> "Topic > Subtopic" + label: mapping.text.split(' > ').slice(1).join(' > '), + }; + }); + }, [editor, roadmapTreeData, roadmapDetailsData]); + + return ( +
+ +
+ ); +} diff --git a/src/components/ChatEditor/VariableExtension/VariableExtension.tsx b/src/components/ChatEditor/VariableExtension/VariableExtension.tsx new file mode 100644 index 000000000000..840b34be6fe2 --- /dev/null +++ b/src/components/ChatEditor/VariableExtension/VariableExtension.tsx @@ -0,0 +1,311 @@ +import { mergeAttributes, Node } from '@tiptap/core'; +import { type DOMOutputSpec, Node as ProseMirrorNode } from '@tiptap/pm/model'; +import { PluginKey } from '@tiptap/pm/state'; +import Suggestion, { type SuggestionOptions } from '@tiptap/suggestion'; + +// See `addAttributes` below +export interface VariableNodeAttrs { + /** + * The identifier for the selected item that was mentioned, stored as a `data-id` + * attribute. + */ + id: string | null; + /** + * The label to be rendered by the editor as the displayed text for this mentioned + * item, if provided. Stored as a `data-label` attribute. See `renderLabel`. + */ + label?: string | null; +} + +export type VariableOptions< + SuggestionItem = any, + Attrs extends Record = VariableNodeAttrs, +> = { + /** + * The HTML attributes for a mention node. + * @default {} + * @example { class: 'foo' } + */ + HTMLAttributes: Record; + + /** + * A function to render the label of a mention. + * @deprecated use renderText and renderHTML instead + * @param props The render props + * @returns The label + * @example ({ options, node }) => `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}` + */ + renderLabel?: (props: { + options: VariableOptions; + node: ProseMirrorNode; + }) => string; + + /** + * A function to render the text of a mention. + * @param props The render props + * @returns The text + * @example ({ options, node }) => `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}` + */ + renderText: (props: { + options: VariableOptions; + node: ProseMirrorNode; + }) => string; + + /** + * A function to render the HTML of a mention. + * @param props The render props + * @returns The HTML as a ProseMirror DOM Output Spec + * @example ({ options, node }) => ['span', { 'data-type': 'mention' }, `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`] + */ + renderHTML: (props: { + options: VariableOptions; + node: ProseMirrorNode; + }) => DOMOutputSpec; + + /** + * Whether to delete the trigger character with backspace. + * @default false + */ + deleteTriggerWithBackspace: boolean; + + /** + * The suggestion options. + * @default {} + * @example { char: '@', pluginKey: MentionPluginKey, command: ({ editor, range, props }) => { ... } } + */ + suggestion: Omit, 'editor'>; +}; + +export type VariableType = { + id: string; + label: string; +}; + +export type VariableStorage = { + variables: VariableType[]; +}; + +/** + * The plugin key for the variable plugin. + * @default 'variable' + */ +export const VariablePluginKey = new PluginKey('variable'); + +export const VariableExtension = Node.create({ + name: 'variable', + + priority: 101, + + addStorage() { + return { + variables: [], + }; + }, + + addOptions() { + return { + HTMLAttributes: {}, + renderText({ options, node }) { + return `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`; + }, + deleteTriggerWithBackspace: false, + renderHTML({ options, node }) { + return [ + 'span', + mergeAttributes(this.HTMLAttributes, options.HTMLAttributes), + `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`, + ]; + }, + suggestion: { + char: '@', + pluginKey: VariablePluginKey, + command: ({ editor, range, props }) => { + // increase range.to by one when the next node is of type "text" + // and starts with a space character + const nodeAfter = editor.view.state.selection.$to.nodeAfter; + const overrideSpace = nodeAfter?.text?.startsWith(' '); + + if (overrideSpace) { + range.to += 1; + } + + editor + .chain() + .focus() + .insertContentAt(range, [ + { + type: this.name, + attrs: props, + }, + { + type: 'text', + text: ' ', + }, + ]) + .run(); + + // get reference to `window` object from editor element, to support cross-frame JS usage + editor.view.dom.ownerDocument.defaultView + ?.getSelection() + ?.collapseToEnd(); + }, + allow: ({ state, range }) => { + const $from = state.doc.resolve(range.from); + const type = state.schema.nodes[this.name]; + const allow = !!$from.parent.type.contentMatch.matchType(type); + + return allow; + }, + }, + }; + }, + + group: 'inline', + + inline: true, + + selectable: false, + + atom: true, + + addAttributes() { + return { + id: { + default: null, + parseHTML: (element) => element.getAttribute('data-id'), + renderHTML: (attributes) => { + if (!attributes.id) { + return {}; + } + + return { + 'data-id': attributes.id, + }; + }, + }, + + label: { + default: null, + parseHTML: (element) => element.getAttribute('data-label'), + renderHTML: (attributes) => { + if (!attributes.label) { + return {}; + } + + return { + 'data-label': attributes.label, + }; + }, + }, + }; + }, + + parseHTML() { + return [ + { + tag: `span[data-type="${this.name}"]`, + }, + ]; + }, + + renderHTML({ node, HTMLAttributes }) { + if (this.options.renderLabel !== undefined) { + console.warn( + 'renderLabel is deprecated use renderText and renderHTML instead', + ); + return [ + 'span', + mergeAttributes( + { 'data-type': this.name }, + this.options.HTMLAttributes, + HTMLAttributes, + ), + this.options.renderLabel({ + options: this.options, + node, + }), + ]; + } + const mergedOptions = { ...this.options }; + + mergedOptions.HTMLAttributes = mergeAttributes( + { 'data-type': this.name }, + this.options.HTMLAttributes, + HTMLAttributes, + ); + const html = this.options.renderHTML({ + options: mergedOptions, + node, + }); + + if (typeof html === 'string') { + return [ + 'span', + mergeAttributes( + { 'data-type': this.name }, + this.options.HTMLAttributes, + HTMLAttributes, + ), + html, + ]; + } + return html; + }, + + renderText({ node }) { + if (this.options.renderLabel !== undefined) { + console.warn( + 'renderLabel is deprecated use renderText and renderHTML instead', + ); + return this.options.renderLabel({ + options: this.options, + node, + }); + } + return this.options.renderText({ + options: this.options, + node, + }); + }, + + addKeyboardShortcuts() { + return { + Backspace: () => + this.editor.commands.command(({ tr, state }) => { + let isVariable = false; + const { selection } = state; + const { empty, anchor } = selection; + + if (!empty) { + return false; + } + + state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => { + if (node.type.name === this.name) { + isVariable = true; + tr.insertText( + this.options.deleteTriggerWithBackspace + ? '' + : this.options.suggestion.char || '', + pos, + pos + node.nodeSize, + ); + + return false; + } + }); + + return isVariable; + }), + }; + }, + + addProseMirrorPlugins() { + return [ + Suggestion({ + editor: this.editor, + ...this.options.suggestion, + }), + ]; + }, +}); diff --git a/src/components/ChatEditor/VariableExtension/VariableSuggestion.tsx b/src/components/ChatEditor/VariableExtension/VariableSuggestion.tsx new file mode 100644 index 000000000000..ce3d1e43283c --- /dev/null +++ b/src/components/ChatEditor/VariableExtension/VariableSuggestion.tsx @@ -0,0 +1,175 @@ +import { ReactRenderer } from '@tiptap/react'; +import type { SuggestionOptions } from '@tiptap/suggestion'; +import tippy, { type GetReferenceClientRect } from 'tippy.js'; + +import { + forwardRef, + Fragment, + useEffect, + useImperativeHandle, + useState, +} from 'react'; +import { cn } from '../../../lib/classname'; +import type { VariableStorage, VariableType } from './VariableExtension'; +import { ChevronRight } from 'lucide-react'; + +export type VariableListProps = { + command: (variable: VariableType) => void; + items: VariableType[]; +} & SuggestionOptions; + +export const VariableList = forwardRef((props: VariableListProps, ref) => { + const { items, command } = props; + const [selectedIndex, setSelectedIndex] = useState(0); + + const selectItem = (index: number) => { + const item = props.items[index]; + + if (!item) { + return; + } + + command(item); + }; + + useEffect(() => { + setSelectedIndex(0); + }, [items]); + + useImperativeHandle(ref, () => ({ + onKeyDown: ({ event }: { event: KeyboardEvent }) => { + if (event.key === 'ArrowUp') { + setSelectedIndex((selectedIndex + items.length - 1) % items.length); + return true; + } + + if (event.key === 'ArrowDown') { + setSelectedIndex((selectedIndex + 1) % items.length); + return true; + } + + if (event.key === 'Enter') { + selectItem(selectedIndex); + return true; + } + + return false; + }, + })); + + return ( +
+ {items.length ? ( + items.map((item, index) => { + const labelParts = item?.label.split('>'); + + return ( + + ); + }) + ) : ( +
No result
+ )} +
+ ); +}); + +VariableList.displayName = 'VariableList'; + +export function variableSuggestion(): Omit { + return { + items: ({ editor, query }) => { + const storage = editor.storage.variable as VariableStorage; + + return storage.variables + .filter((variable) => + variable?.label?.toLowerCase().includes(query.toLowerCase()), + ) + .slice(0, 5); + }, + + render: () => { + let component: ReactRenderer; + let popup: InstanceType | null = null; + + return { + onStart: (props) => { + component = new ReactRenderer(VariableList, { + props, + editor: props.editor, + }); + + if (!props.clientRect) { + return; + } + + popup = tippy('body', { + getReferenceClientRect: props.clientRect as GetReferenceClientRect, + appendTo: () => document.body, + content: component.element, + showOnCreate: true, + interactive: true, + trigger: 'manual', + placement: 'top-start', + }); + }, + + onUpdate(props) { + component.updateProps(props); + + if (!props.clientRect) { + return; + } + + popup[0].setProps({ + getReferenceClientRect: props.clientRect, + }); + }, + + onKeyDown(props) { + if (props.event.key === 'Escape') { + popup[0].hide(); + + return true; + } + + return component.ref?.onKeyDown(props); + }, + + onExit() { + popup[0].destroy(); + component.destroy(); + }, + }; + }, + }; +} diff --git a/src/components/ChatMessages/AIChat.css b/src/components/ChatMessages/AIChat.css new file mode 100644 index 000000000000..545f86d407c0 --- /dev/null +++ b/src/components/ChatMessages/AIChat.css @@ -0,0 +1,131 @@ +.ai-chat { + .prose ul li > code, + .prose ol li > code, + p code, + a > code, + strong > code, + em > code, + h1 > code, + h2 > code, + h3 > code { + background: #ebebeb !important; + color: currentColor !important; + font-size: 14px; + font-weight: normal !important; + } + + .message-markdown.prose ul li > code, + .message-markdown.prose ol li > code, + .message-markdown.prose p code, + .message-markdown.prose a > code, + .message-markdown.prose strong > code, + .message-markdown.prose em > code, + .message-markdown.prose h1 > code, + .message-markdown.prose h2 > code, + .message-markdown.prose h3 > code { + font-size: 12px !important; + } + + .message-markdown pre { + -ms-overflow-style: none; + scrollbar-width: none; + } + + .message-markdown pre::-webkit-scrollbar { + display: none; + } + + .message-markdown pre, + .message-markdown pre { + overflow: scroll; + } + + .prose ul li > code:before, + p > code:before, + .prose ul li > code:after, + .prose ol li > code:before, + p > code:before, + .prose ol li > code:after, + .message-markdown h1 > code:after, + .message-markdown h1 > code:before, + .message-markdown h2 > code:after, + .message-markdown h2 > code:before, + .message-markdown h3 > code:after, + .message-markdown h3 > code:before, + .message-markdown h4 > code:after, + .message-markdown h4 > code:before, + p > code:after, + a > code:after, + a > code:before { + content: '' !important; + } + + .message-markdown.prose ul li > code, + .message-markdown.prose ol li > code, + .message-markdown p code, + .message-markdown a > code, + .message-markdown strong > code, + .message-markdown em > code, + .message-markdown h1 > code, + .message-markdown h2 > code, + .message-markdown h3 > code, + .message-markdown table code { + background: #f4f4f5 !important; + border: 1px solid #282a36 !important; + color: #282a36 !important; + padding: 2px 4px; + border-radius: 5px; + white-space: pre; + font-weight: normal; + } + + .message-markdown blockquote { + font-style: normal; + } + + .message-markdown.prose blockquote h1, + .message-markdown.prose blockquote h2, + .message-markdown.prose blockquote h3, + .message-markdown.prose blockquote h4 { + font-style: normal; + margin-bottom: 8px; + } + + .message-markdown.prose ul li > code:before, + .message-markdown p > code:before, + .message-markdown.prose ul li > code:after, + .message-markdown p > code:after, + .message-markdown h2 > code:after, + .message-markdown h2 > code:before, + .message-markdown table code:before, + .message-markdown table code:after, + .message-markdown a > code:after, + .message-markdown a > code:before, + .message-markdown h2 code:after, + .message-markdown h2 code:before, + .message-markdown h2 code:after, + .message-markdown h2 code:before { + content: '' !important; + } + + .message-markdown table { + border-collapse: collapse; + border: 1px solid black; + border-radius: 5px; + } + + .message-markdown table td, + .message-markdown table th { + padding: 5px 10px; + } + + .chat-variable { + font-size: 12px; + font-weight: 500; + line-height: 1.5; + padding: 2px 4px; + border-radius: 8px; + background-color: #f0f5ff; + color: #2c5df1; + } +} diff --git a/src/components/ChatMessages/RoadmapChatIntroMessage.tsx b/src/components/ChatMessages/RoadmapChatIntroMessage.tsx new file mode 100644 index 000000000000..08ec047aff2d --- /dev/null +++ b/src/components/ChatMessages/RoadmapChatIntroMessage.tsx @@ -0,0 +1,108 @@ +import { useQuery } from '@tanstack/react-query'; +import { officialRoadmapOptions } from '../../queries/official-roadmap'; +import { queryClient } from '../../stores/query-client'; + +type RoadmapChatIntroMessageProps = { + roadmapId: string; +}; + +export function RoadmapChatIntroMessage(props: RoadmapChatIntroMessageProps) { + const { roadmapId } = props; + + const { data: roadmapDetail } = useQuery( + officialRoadmapOptions(roadmapId), + queryClient, + ); + const topicNodes = roadmapDetail?.nodes?.filter( + (node) => node.type === 'topic', + ); + + const firstTopicNode = topicNodes?.[0]; + const firstTopicTitle = firstTopicNode?.data?.label || 'XYZ'; + + const secondTopicNode = topicNodes?.[1]; + const secondTopicTitle = secondTopicNode?.data?.label || 'XYZ'; + + const capabilities = [ + { + icon: '📚', + title: 'Learn concepts:', + description: 'Ask me about any topics on the roadmap', + examples: + '"Explain what React hooks are" or "How does async/await work?"', + }, + { + icon: '📊', + title: 'Track progress:', + description: 'Mark topics as done, learning, or skipped', + examples: `"Mark ${firstTopicTitle} as done" or "Show my overall progress"`, + }, + { + icon: '🎯', + title: 'Recommendations:', + description: 'Find what to learn next or explore other roadmaps', + examples: `"What should I learn next?" or "Recommend roadmaps for backend development"`, + }, + { + icon: '🔍', + title: 'Find resources:', + description: 'Get learning materials for specific topics', + examples: `"Show me resources for learning ${secondTopicTitle}"`, + }, + { + icon: '🔗', + title: 'Share progress:', + description: 'Get a link to share your learning progress', + examples: '"Give me my shareable progress link"', + }, + ]; + + return ( +
+
+
+

+ Hi! I'm your AI learning assistant 👋 +

+

+ I'm here to guide you through your learning journey on this roadmap. + I can help you understand concepts, track your progress, and provide + personalized learning advice. +

+
+
+ +
+

+ Here's what I can help you with: +

+ +
+ {capabilities.map((capability, index) => ( +
+ {capability.icon} +
+ + {capability.title} + {' '} + {capability.description} +
+ Try: {capability.examples} +
+
+
+ ))} +
+
+ +
+

+ Tip: I can see your current + progress on the roadmap, so my advice will be personalized to your + learning journey. Just ask me anything about the topics you see on the + roadmap! +

+
+
+ ); +} diff --git a/src/components/ChatMessages/RoadmapChatMessage.tsx b/src/components/ChatMessages/RoadmapChatMessage.tsx new file mode 100644 index 000000000000..aeb17cb9bfc2 --- /dev/null +++ b/src/components/ChatMessages/RoadmapChatMessage.tsx @@ -0,0 +1,148 @@ +import { Markdown } from '../Global/Markdown'; +import { BotIcon, User2Icon } from 'lucide-react'; +import type { UIMessage } from 'ai'; +import { parseMessageParts } from '../../lib/message-part'; +import { RoadmapChatUserProgressList } from './UserProgressList'; +import { + parseUserProgress, + UserProgressActionList, +} from './UserPrgressActionList'; +import { parseTopicList, RoadmapTopicList } from './RoadmapTopicList'; +import { ShareResourceLink } from './ShareResourceLink'; +import { + parseRoadmapSlugList, + RoadmapRecommendations, +} from './RoadmapRecommendations'; +import { cn } from '../../lib/classname'; + +type RoadmapMessageProps = { + roadmapId: string; + message: UIMessage; + isStreaming: boolean; + children?: React.ReactNode; + onTopicClick?: (topicId: string, topicTitle: string) => void; +}; + +export function RoadmapChatMessage(props: RoadmapMessageProps) { + const { roadmapId, message, isStreaming, children, onTopicClick } = props; + const { role } = message; + + return ( +
+
+
+ {role === 'user' ? ( + + ) : ( + + )} +
+ + {children || ( +
+ {message.parts.map((part) => { + const { type } = part; + + if (role === 'user' && type === 'text') { + return ( +
+ ); + } + + if (type === 'text') { + const text = part.text; + const parts = parseMessageParts(text, { + 'user-progress': () => { + return {}; + }, + 'update-progress': (opts) => { + return parseUserProgress(opts.content); + }, + 'roadmap-topics': (opts) => { + return parseTopicList(opts.content); + }, + 'resource-progress-link': () => { + return {}; + }, + 'roadmap-recommendations': (opts) => { + return parseRoadmapSlugList(opts.content); + }, + }); + + return parts.map((part, index) => { + const { type } = part; + const key = `message-${message.id}-part-${type}-${index}`; + + if (type === 'text') { + return ( + + {part.text ?? ''} + + ); + } else if (type === 'user-progress') { + return ( + + ); + } else if (type === 'update-progress') { + return ( + + ); + } else if (type === 'roadmap-topics') { + return ( + + ); + } else if (type === 'resource-progress-link') { + return ( + + ); + } else if (type === 'roadmap-recommendations') { + return ( + + ); + } + + return null; + }); + } + })} +
+ )} +
+
+ ); +} diff --git a/src/components/ChatMessages/RoadmapChatMessages.tsx b/src/components/ChatMessages/RoadmapChatMessages.tsx new file mode 100644 index 000000000000..dfd8764e391d --- /dev/null +++ b/src/components/ChatMessages/RoadmapChatMessages.tsx @@ -0,0 +1,110 @@ +import type { ChatStatus, UIMessage } from 'ai'; +import { memo } from 'react'; +import { RoadmapChatMessage } from './RoadmapChatMessage'; +import { useIsThinking } from '../../hooks/use-is-thinking'; + +type MessagesProps = { + messages: UIMessage[]; + status: ChatStatus; + roadmapId: string; + onTopicClick?: (topicId: string, topicTitle: string) => void; + defaultQuestions?: string[]; + onDefaultQuestionClick?: (question: string) => void; +}; + +function _RoadmapChatMessages(props: MessagesProps) { + const { + messages, + status, + roadmapId, + defaultQuestions, + onTopicClick, + onDefaultQuestionClick, + } = props; + + const isStreaming = status === 'streaming'; + const isThinking = useIsThinking(messages, status); + + return ( +
+
+
+ + + {messages.length === 0 && + defaultQuestions && + defaultQuestions.length > 0 && ( +
+

+ Some questions you might have about this roadmap: +

+
+ {defaultQuestions.map((question, index) => ( + + ))} +
+
+ )} + + {messages.map((message, index) => { + const isLastMessage = index === messages.length - 1; + + // otherwise it will add an extra space at the end of the message + // because the last message is not rendered + if (isThinking && isLastMessage && message.role === 'assistant') { + return null; + } + + return ( + + ); + })} + + {isThinking && ( + + )} +
+
+
+ ); +} + +export const RoadmapChatMessages = memo(_RoadmapChatMessages); diff --git a/src/components/ChatMessages/RoadmapRecommendations.tsx b/src/components/ChatMessages/RoadmapRecommendations.tsx new file mode 100644 index 000000000000..c08bc330d990 --- /dev/null +++ b/src/components/ChatMessages/RoadmapRecommendations.tsx @@ -0,0 +1,82 @@ +import { useQuery } from '@tanstack/react-query'; +import { useMemo } from 'react'; +import { Loader2Icon, SquareArrowOutUpRightIcon } from 'lucide-react'; +import { listBuiltInRoadmaps } from '../../queries/roadmap'; +import { queryClient } from '../../stores/query-client'; + +type RoadmapSlugListType = { + roadmapSlug: string; +}; + +export function parseRoadmapSlugList(content: string): RoadmapSlugListType[] { + const items: RoadmapSlugListType[] = []; + + const roadmapSlugListRegex = /.*?<\/roadmap-slug>/gs; + const roadmapSlugListItems = content.match(roadmapSlugListRegex); + if (!roadmapSlugListItems) { + return items; + } + + for (const roadmapSlugListItem of roadmapSlugListItems) { + const roadmapSlugRegex = /(.*?)<\/roadmap-slug>/; + const roadmapSlug = roadmapSlugListItem + .match(roadmapSlugRegex)?.[1] + ?.trim(); + if (!roadmapSlug) { + continue; + } + + items.push({ + roadmapSlug, + }); + } + + return items; +} + +type RoadmapRecommendationsProps = { + roadmapSlugs: RoadmapSlugListType[]; +}; + +export function RoadmapRecommendations(props: RoadmapRecommendationsProps) { + const { roadmapSlugs } = props; + + const { data: roadmaps, isLoading } = useQuery( + listBuiltInRoadmaps(), + queryClient, + ); + + const progressItemWithText = useMemo(() => { + return roadmapSlugs.map((item) => { + const roadmap = roadmaps?.find( + (mapping) => mapping.id === item.roadmapSlug, + ); + + return { + ...item, + title: roadmap?.title, + }; + }); + }, [roadmapSlugs, roadmaps]); + + return ( +
+ {progressItemWithText.map((item) => ( + + {item.title} + {isLoading && ( + + )} + {!isLoading && ( + + )} + + ))} +
+ ); +} diff --git a/src/components/ChatMessages/RoadmapTopicList.tsx b/src/components/ChatMessages/RoadmapTopicList.tsx new file mode 100644 index 000000000000..d1c3da39ea5c --- /dev/null +++ b/src/components/ChatMessages/RoadmapTopicList.tsx @@ -0,0 +1,106 @@ +import { useQuery } from '@tanstack/react-query'; +import { Fragment, useMemo } from 'react'; +import { ChevronRightIcon } from 'lucide-react'; +import { roadmapTreeMappingOptions } from '../../queries/roadmap-tree'; +import { queryClient } from '../../stores/query-client'; + +type TopicListType = { + topicId: string; +}; + +export function parseTopicList(content: string): TopicListType[] { + const items: TopicListType[] = []; + + const topicListRegex = /.*?<\/topic-id>/gs; + const topicListItems = content.match(topicListRegex); + if (!topicListItems) { + return items; + } + + for (const topicListItem of topicListItems) { + const topicIdRegex = /(.*?)<\/topic-id>/; + const topicId = topicListItem.match(topicIdRegex)?.[1]?.trim(); + if (!topicId) { + continue; + } + + items.push({ + topicId, + }); + } + + return items; +} + +type RoadmapTopicListProps = { + roadmapId: string; + onTopicClick?: (topicId: string, topicTitle: string) => void; + topics: TopicListType[]; +}; + +export function RoadmapTopicList(props: RoadmapTopicListProps) { + const { roadmapId, topics: topicListItems, onTopicClick } = props; + + const { data: roadmapTreeData } = useQuery( + roadmapTreeMappingOptions(roadmapId), + queryClient, + ); + + const progressItemWithText = useMemo(() => { + return topicListItems.map((item) => { + const roadmapTreeItem = roadmapTreeData?.find( + (mapping) => mapping.nodeId === item.topicId, + ); + + return { + ...item, + text: (roadmapTreeItem?.text || item.topicId) + ?.split(' > ') + .slice(1) + .join(' > '), + }; + }); + }, [topicListItems, roadmapTreeData]); + + return ( +
+ {progressItemWithText.map((item) => { + const labelParts = item.text.split(' > ').slice(-2); + const labelPartCount = labelParts.length; + + const title = item.text.split(' > ').pop(); + if (!title) { + return; + } + + return ( + + ); + })} +
+ ); +} diff --git a/src/components/ChatMessages/ShareResourceLink.tsx b/src/components/ChatMessages/ShareResourceLink.tsx new file mode 100644 index 000000000000..a0108398a07d --- /dev/null +++ b/src/components/ChatMessages/ShareResourceLink.tsx @@ -0,0 +1,47 @@ +import { ShareIcon } from 'lucide-react'; +import { useCopyText } from '../../hooks/use-copy-text'; +import { cn } from '../../lib/classname'; +import { useAuth } from '../../hooks/use-auth'; +import { CheckIcon } from '../ReactIcons/CheckIcon'; + +type ShareResourceLinkProps = { + roadmapId: string; +}; + +export function ShareResourceLink(props: ShareResourceLinkProps) { + const { roadmapId } = props; + + const currentUser = useAuth(); + const { copyText, isCopied } = useCopyText(); + + const handleShareResourceLink = () => { + const url = `${import.meta.env.VITE_ASTRO_APP_URL}/${roadmapId}?s=${currentUser?.id}`; + copyText(url); + }; + + return ( +
+ +
+ ); +} diff --git a/src/components/ChatMessages/TopicChatMessage.tsx b/src/components/ChatMessages/TopicChatMessage.tsx new file mode 100644 index 000000000000..b20e679b81cf --- /dev/null +++ b/src/components/ChatMessages/TopicChatMessage.tsx @@ -0,0 +1,63 @@ +import { cn } from '../../lib/classname'; +import { Markdown } from '../Global/Markdown'; +import { BotIcon, User2Icon } from 'lucide-react'; +import type { UIMessage } from 'ai'; +import { promptLabelMapping } from '../TopicDetail/PredefinedActions'; + +type TopicChatMessageProps = { + message: UIMessage; +}; + +export function TopicChatMessage(props: TopicChatMessageProps) { + const { message } = props; + const { role } = message; + + return ( +
+
+
+ {role === 'user' ? ( + + ) : ( + + )} +
+ +
+ {message.parts.map((part) => { + const { type } = part; + const key = `message-${message.id}-part-${type}`; + + if (type === 'text') { + let content = part.text; + if (role === 'user' && promptLabelMapping[content]) { + content = promptLabelMapping[content]; + } + + return ( + + {content} + + ); + } + })} +
+
+
+ ); +} diff --git a/src/components/ChatMessages/TopicChatMessages.tsx b/src/components/ChatMessages/TopicChatMessages.tsx new file mode 100644 index 000000000000..4cdc766e27ee --- /dev/null +++ b/src/components/ChatMessages/TopicChatMessages.tsx @@ -0,0 +1,57 @@ +import type { ChatStatus, UIMessage } from 'ai'; +import { TopicChatMessage } from './TopicChatMessage'; +import { useIsThinking } from '../../hooks/use-is-thinking'; + +type TopicChatMessagesProps = { + messages: UIMessage[]; + status: ChatStatus; +}; + +export function TopicChatMessages(props: TopicChatMessagesProps) { + const { messages, status } = props; + + const isThinking = useIsThinking(messages, status); + + return ( +
+
+
+ + + {messages.map((message, index) => { + const isLastMessage = index === messages.length - 1; + + // otherwise it will add an extra space at the end of the message + // because the last message is not rendered + if (isThinking && isLastMessage && message.role === 'assistant') { + return null; + } + + return ; + })} + + {isThinking && ( + + )} +
+
+
+ ); +} diff --git a/src/components/ChatMessages/UserPrgressActionList.tsx b/src/components/ChatMessages/UserPrgressActionList.tsx new file mode 100644 index 000000000000..f9d823fd2ca9 --- /dev/null +++ b/src/components/ChatMessages/UserPrgressActionList.tsx @@ -0,0 +1,330 @@ +import { useMutation, useQuery } from '@tanstack/react-query'; +import { ChevronRightIcon, Loader2Icon } from 'lucide-react'; +import { CheckIcon } from '../ReactIcons/CheckIcon'; +import { Fragment, useMemo, useState } from 'react'; +import { roadmapTreeMappingOptions } from '../../queries/roadmap-tree'; +import { queryClient } from '../../stores/query-client'; +import { httpPost } from '../../lib/query-http'; +import { + renderTopicProgress, + updateResourceProgress, + type ResourceProgressType, +} from '../../lib/resource-progress'; +import { userResourceProgressOptions } from '../../queries/resource-progress'; +import { useToast } from '../../hooks/use-toast'; +import { cn } from '../../lib/classname'; + +type UpdateUserProgress = { + id: string; + action: 'done' | 'learning' | 'skipped' | 'pending'; +}; + +export function parseUserProgress(content: string): UpdateUserProgress[] { + const items: UpdateUserProgress[] = []; + + const progressRegex = /.*?<\/update-progress-item>/gs; + const progressItems = content.match(progressRegex); + if (!progressItems) { + return items; + } + + for (const progressItem of progressItems) { + const progressItemRegex = /(.*?)<\/topic-id>/; + const topicId = progressItem.match(progressItemRegex)?.[1]?.trim(); + const topicActionRegex = /(.*?)<\/topic-action>/; + const topicAction = progressItem + .match(topicActionRegex)?.[1] + .trim() + ?.toLowerCase(); + + if (!topicId || !topicAction) { + continue; + } + + items.push({ + id: topicId, + action: topicAction as UpdateUserProgress['action'], + }); + } + + return items; +} + +type BulkUpdateResourceProgressBody = { + done: string[]; + learning: string[]; + skipped: string[]; + pending: string[]; +}; + +type BulkUpdateResourceProgressResponse = { + done: string[]; + learning: string[]; + skipped: string[]; +}; + +type UserProgressActionListProps = { + roadmapId: string; + isLoading?: boolean; + updateUserProgress: UpdateUserProgress[]; +}; + +export function UserProgressActionList(props: UserProgressActionListProps) { + const { roadmapId, updateUserProgress, isLoading = false } = props; + + const toast = useToast(); + const { data: roadmapTreeData } = useQuery( + roadmapTreeMappingOptions(roadmapId), + queryClient, + ); + + const { + mutate: bulkUpdateResourceProgress, + isPending: isBulkUpdating, + isSuccess: isBulkUpdateSuccess, + } = useMutation( + { + mutationFn: (body: BulkUpdateResourceProgressBody) => { + return httpPost( + `/v1-bulk-update-resource-progress/${roadmapId}`, + body, + ); + }, + onSuccess: () => { + updateUserProgress.forEach((item) => { + renderTopicProgress(item.id, item.action); + }); + + return queryClient.invalidateQueries( + userResourceProgressOptions('roadmap', roadmapId), + ); + }, + onError: (error) => { + toast.error( + error?.message ?? 'Something went wrong, please try again.', + ); + }, + }, + queryClient, + ); + + const progressItemWithText = useMemo(() => { + return updateUserProgress.map((item) => { + const roadmapTreeItem = roadmapTreeData?.find( + (mapping) => mapping.nodeId === item.id, + ); + + return { + ...item, + text: (roadmapTreeItem?.text || item.id) + ?.split(' > ') + .slice(1) + .join(' > '), + }; + }); + }, [updateUserProgress, roadmapTreeData]); + + const [showAll, setShowAll] = useState(false); + const itemCountToShow = 4; + const itemsToShow = showAll + ? progressItemWithText + : progressItemWithText.slice(0, itemCountToShow); + + const hasMoreItemsToShow = progressItemWithText.length > itemCountToShow; + + return ( +
+
+ {itemsToShow.map((item) => ( + + ))} + + {hasMoreItemsToShow && ( +
+ + + +
+ )} +
+
+ ); +} + +type ProgressItemProps = { + roadmapId: string; + topicId: string; + text: string; + action: UpdateUserProgress['action']; + isStreaming: boolean; + isBulkUpdating: boolean; + isBulkUpdateSuccess: boolean; +}; + +function ProgressItem(props: ProgressItemProps) { + const { + roadmapId, + topicId, + text, + action, + isStreaming, + isBulkUpdating, + isBulkUpdateSuccess, + } = props; + + const toast = useToast(); + const { + mutate: updateTopicStatus, + isSuccess, + isPending: isUpdating, + } = useMutation( + { + mutationFn: (action: ResourceProgressType) => { + return updateResourceProgress( + { + resourceId: roadmapId, + resourceType: 'roadmap', + topicId, + }, + action, + ); + }, + onMutate: () => {}, + onSuccess: () => { + renderTopicProgress(topicId, action); + }, + onError: () => { + toast.error('Something went wrong, please try again.'); + }, + onSettled: () => { + return queryClient.invalidateQueries( + userResourceProgressOptions('roadmap', roadmapId), + ); + }, + }, + queryClient, + ); + + const textParts = text.split(' > '); + const lastIndex = textParts.length - 1; + + return ( +
+ + {textParts.map((part, index) => { + return ( + + {part} + {index !== lastIndex && ( + + {' '} + + )} + + ); + })} + + {!isSuccess && !isBulkUpdateSuccess && ( + <> + {!isStreaming && ( + + )} + {isStreaming && ( + + + + )} + + )} + {(isSuccess || isBulkUpdateSuccess) && ( + + + + )} +
+ ); +} diff --git a/src/components/ChatMessages/UserProgressList.tsx b/src/components/ChatMessages/UserProgressList.tsx new file mode 100644 index 000000000000..b8bce593eed3 --- /dev/null +++ b/src/components/ChatMessages/UserProgressList.tsx @@ -0,0 +1,60 @@ +import { useQuery } from '@tanstack/react-query'; +import { getPercentage } from '../../lib/number'; +import { userResourceProgressOptions } from '../../queries/resource-progress'; +import { queryClient } from '../../stores/query-client'; + +type RoadmapChatUserProgressListProps = { + roadmapId: string; +}; + +export function RoadmapChatUserProgressList( + props: RoadmapChatUserProgressListProps, +) { + const { roadmapId } = props; + + const { data: userResourceProgressData } = useQuery( + userResourceProgressOptions('roadmap', roadmapId), + queryClient, + ); + + const doneCount = userResourceProgressData?.done?.length ?? 0; + const skippedCount = userResourceProgressData?.skipped?.length ?? 0; + + const totalTopicCount = userResourceProgressData?.totalTopicCount ?? 0; + const totalFinished = doneCount + skippedCount; + const progressPercentage = getPercentage(totalFinished, totalTopicCount); + + return ( +
+
+
+ Progress + + {progressPercentage}% + +
+ + {totalFinished} / {totalTopicCount} topics + +
+ +
+
+
+ +
+
+
+ Completed: {doneCount} +
+
+
+ Skipped: {skippedCount} +
+
+
+ ); +} diff --git a/src/components/CommandMenu/CommandMenu.tsx b/src/components/CommandMenu/CommandMenu.tsx new file mode 100644 index 000000000000..4e848d2ef078 --- /dev/null +++ b/src/components/CommandMenu/CommandMenu.tsx @@ -0,0 +1,266 @@ +import { + Fragment, + type ReactElement, + useEffect, + useRef, + useState, +} from 'react'; +import { useKeydown } from '../../hooks/use-keydown'; +import { useOutsideClick } from '../../hooks/use-outside-click'; +import { httpGet } from '../../lib/http'; +import { isLoggedIn } from '../../lib/jwt'; +import { BestPracticesIcon } from '../ReactIcons/BestPracticesIcon.tsx'; +import { UserIcon } from '../ReactIcons/UserIcon.tsx'; +import { GroupIcon } from '../ReactIcons/GroupIcon.tsx'; +import { RoadmapIcon } from '../ReactIcons/RoadmapIcon.tsx'; +import { ClipboardIcon } from '../ReactIcons/ClipboardIcon.tsx'; +import { GuideIcon } from '../ReactIcons/GuideIcon.tsx'; +import { HomeIcon } from '../ReactIcons/HomeIcon.tsx'; +import { VideoIcon } from '../ReactIcons/VideoIcon.tsx'; +import { cn } from '../../lib/classname.ts'; +import type { AllowedRoadmapRenderer } from '../../lib/roadmap.ts'; + +export type PageType = { + id: string; + url: string; + title: string; + group: string; + icon?: ReactElement; + isProtected?: boolean; + metadata?: Record; + renderer?: AllowedRoadmapRenderer; +}; + +const defaultPages: PageType[] = [ + { + id: 'home', + url: '/', + title: 'Home', + group: 'Pages', + icon: , + }, + { + id: 'account', + url: '/account', + title: 'Account', + group: 'Pages', + icon: , + isProtected: true, + }, + { + id: 'team', + url: '/team', + title: 'Teams', + group: 'Pages', + icon: , + isProtected: true, + }, + { + id: 'friends', + url: '/account/friends', + title: 'Friends', + group: 'Pages', + icon: , + isProtected: true, + }, + { + id: 'roadmaps', + url: '/roadmaps', + title: 'Roadmaps', + group: 'Pages', + icon: , + }, + { + id: 'account-roadmaps', + url: '/account/roadmaps', + title: 'Custom Roadmaps', + group: 'Pages', + icon: , + isProtected: true, + }, + { + id: 'questions', + url: '/questions', + title: 'Questions', + group: 'Pages', + icon: , + }, + { + id: 'guides', + url: '/guides', + title: 'Guides', + group: 'Pages', + icon: , + }, + { + id: 'videos', + url: '/videos', + title: 'Videos', + group: 'Pages', + icon: , + }, +]; + +function shouldShowPage(page: PageType) { + const isUser = isLoggedIn(); + + return !page.isProtected || isUser; +} + +export function CommandMenu() { + const inputRef = useRef(null); + const modalRef = useRef(null); + const [isActive, setIsActive] = useState(false); + const [allPages, setAllPages] = useState([]); + const [searchResults, setSearchResults] = useState(defaultPages); + const [searchedText, setSearchedText] = useState(''); + const [activeCounter, setActiveCounter] = useState(0); + + useKeydown('mod_k', () => { + setIsActive(true); + }); + + useOutsideClick(modalRef, () => { + setSearchedText(''); + setIsActive(false); + }); + + useEffect(() => { + function handleToggleTopic(e: any) { + setIsActive(true); + } + + getAllPages(); + window.addEventListener(`command.k`, handleToggleTopic); + return () => { + window.removeEventListener(`command.k`, handleToggleTopic); + }; + }, []); + + useEffect(() => { + if (!isActive || !inputRef.current) { + return; + } + + inputRef.current.focus(); + }, [isActive]); + + async function getAllPages() { + if (allPages.length > 0) { + return allPages; + } + const { error, response } = await httpGet(`/pages.json`); + if (!response) { + return defaultPages.filter(shouldShowPage); + } + + setAllPages([...defaultPages, ...response].filter(shouldShowPage)); + + return response; + } + + useEffect(() => { + if (!searchedText) { + setSearchResults(defaultPages.filter(shouldShowPage)); + return; + } + + const normalizedSearchText = searchedText.trim().toLowerCase(); + getAllPages().then((unfilteredPages = defaultPages) => { + const filteredPages = unfilteredPages + .filter((currPage: PageType) => { + return ( + currPage.title.toLowerCase().indexOf(normalizedSearchText) !== -1 + ); + }) + .slice(0, 10); + + setActiveCounter(0); + setSearchResults(filteredPages); + }); + }, [searchedText]); + + if (!isActive) { + return null; + } + + return ( +
+
+
+ { + const value = (e.target as HTMLInputElement).value.trim(); + setSearchedText(value); + }} + onKeyDown={(e) => { + if (e.key === 'ArrowDown') { + const canGoNext = activeCounter < searchResults.length - 1; + setActiveCounter(canGoNext ? activeCounter + 1 : 0); + } else if (e.key === 'ArrowUp') { + const canGoPrev = activeCounter > 0; + setActiveCounter( + canGoPrev ? activeCounter - 1 : searchResults.length - 1, + ); + } else if (e.key === 'Tab') { + e.preventDefault(); + } else if (e.key === 'Escape') { + setSearchedText(''); + setIsActive(false); + } else if (e.key === 'Enter') { + const activePage = searchResults[activeCounter]; + if (activePage) { + window.location.href = activePage.url; + } + } + }} + /> + +
+
+ {searchResults.length === 0 && ( +
+ No results found +
+ )} + + {searchResults.map((page: PageType, counter: number) => { + const prevPage = searchResults[counter - 1]; + const groupChanged = prevPage && prevPage.group !== page.group; + + return ( + + {groupChanged && ( +
+ )} + setActiveCounter(counter)} + href={page.url} + > + {!page.icon && ( + {page.group} + )} + {page.icon && page.icon} + {page.title} + +
+ ); + })} +
+
+
+
+
+ ); +} diff --git a/src/components/Confetti.tsx b/src/components/Confetti.tsx new file mode 100644 index 000000000000..c4b87fe0dc13 --- /dev/null +++ b/src/components/Confetti.tsx @@ -0,0 +1,69 @@ +import { useEffect, useState } from 'react'; +import ReactConfetti from 'react-confetti'; + +type ConfettiPosition = { + x: number; + y: number; + w: number; + h: number; +}; + +type ConfettiProps = { + pieces?: number; + element?: HTMLElement | null; + onDone?: () => void; +}; + +export function Confetti(props: ConfettiProps) { + const { element = document.body, onDone = () => null, pieces = 40 } = props; + + const [confettiPos, setConfettiPos] = useState< + undefined | ConfettiPosition + >(); + + function populateConfettiPosition(element: HTMLElement) { + const elRect = element.getBoundingClientRect(); + + // set confetti position, keeping in mind the scroll values + setConfettiPos({ + x: elRect?.x || 0, + y: (elRect?.y || 0) + window.scrollY, + w: elRect?.width || 0, + h: elRect?.height || 0, + }); + } + + useEffect(() => { + if (!element) { + setConfettiPos(undefined); + return; + } + + populateConfettiPosition(element); + }, [element]); + + if (!confettiPos) { + return null; + } + + return ( + { + setConfettiPos(undefined); + onDone(); + }} + initialVelocityX={4} + initialVelocityY={8} + tweenDuration={10} + confettiSource={{ + x: confettiPos.x, + y: confettiPos.y, + w: confettiPos.w, + h: confettiPos.h, + }} + /> + ); +} diff --git a/src/components/ContentGenerator/ContentGenerator.tsx b/src/components/ContentGenerator/ContentGenerator.tsx new file mode 100644 index 000000000000..e546f68f9e4a --- /dev/null +++ b/src/components/ContentGenerator/ContentGenerator.tsx @@ -0,0 +1,270 @@ +import { + BookOpenIcon, + FileTextIcon, + MapIcon, + SparklesIcon, + type LucideIcon, +} from 'lucide-react'; +import { useEffect, useId, useState } from 'react'; +import { FormatItem } from './FormatItem'; +import { isLoggedIn } from '../../lib/jwt'; +import { showLoginPopup } from '../../lib/popup'; +import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal'; +import { useIsPaidUser } from '../../queries/billing'; +import { + clearQuestionAnswerChatMessages, + storeQuestionAnswerChatMessages, +} from '../../lib/ai-questions'; +import { + QuestionAnswerChat, + type QuestionAnswerChatMessage, +} from './QuestionAnswerChat'; +import { useToast } from '../../hooks/use-toast'; +import { cn } from '../../lib/classname'; +import { getUrlParams, setUrlParams } from '../../lib/browser'; +import { useParams } from '../../hooks/use-params'; +import { useQuery } from '@tanstack/react-query'; +import { aiLimitOptions } from '../../queries/ai-course'; +import { queryClient } from '../../stores/query-client'; +import { showUpgradeModal } from '../../stores/subscription'; + +const allowedFormats = ['course', 'guide', 'roadmap'] as const; +export type AllowedFormat = (typeof allowedFormats)[number]; + +export function ContentGenerator() { + const [isUpgradeModalOpen, setIsUpgradeModalOpen] = useState(false); + const { isPaidUser, isLoading: isPaidUserLoading } = useIsPaidUser(); + const params = useParams<{ format: AllowedFormat }>(); + + const toast = useToast(); + const [title, setTitle] = useState(''); + const [selectedFormat, setSelectedFormat] = useState('course'); + + const { data: limits, isLoading: isLimitLoading } = useQuery( + aiLimitOptions(), + queryClient, + ); + + useEffect(() => { + const isValidFormat = allowedFormats.find( + (format) => format.value === params.format, + ); + + if (isValidFormat) { + setSelectedFormat(isValidFormat.value); + } else { + setSelectedFormat('course'); + } + }, [params.format]); + + const [showFineTuneOptions, setShowFineTuneOptions] = useState(false); + const [questionAnswerChatMessages, setQuestionAnswerChatMessages] = useState< + QuestionAnswerChatMessage[] + >([]); + + const titleFieldId = useId(); + const fineTuneOptionsId = useId(); + + useEffect(() => { + const params = getUrlParams(); + const format = params.format as AllowedFormat; + if (format && allowedFormats.find((f) => f.value === format)) { + setSelectedFormat(format); + } + }, []); + + const allowedFormats: { + label: string; + icon: LucideIcon; + value: AllowedFormat; + }[] = [ + { + label: 'Course', + icon: BookOpenIcon, + value: 'course', + }, + { + label: 'Guide', + icon: FileTextIcon, + value: 'guide', + }, + { + label: 'Roadmap', + icon: MapIcon, + value: 'roadmap', + }, + ]; + + const selectedLimit = limits?.[selectedFormat]; + const showLimitWarning = + !isPaidUser && !isPaidUserLoading && !isLimitLoading && isLoggedIn(); + + const handleSubmit = () => { + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + + if ( + !isPaidUser && + selectedLimit && + selectedLimit?.used >= selectedLimit?.limit + ) { + showUpgradeModal(); + return; + } + + let sessionId = ''; + if (showFineTuneOptions) { + clearQuestionAnswerChatMessages(); + sessionId = storeQuestionAnswerChatMessages(questionAnswerChatMessages); + } + + const trimmedTitle = title.trim(); + if (selectedFormat === 'course') { + window.location.href = `/ai/course?term=${encodeURIComponent(trimmedTitle)}&id=${sessionId}&format=${selectedFormat}`; + } else if (selectedFormat === 'guide') { + window.location.href = `/ai/guide?term=${encodeURIComponent(trimmedTitle)}&id=${sessionId}&format=${selectedFormat}`; + } else if (selectedFormat === 'roadmap') { + window.location.href = `/ai/roadmap?term=${encodeURIComponent(trimmedTitle)}&id=${sessionId}&format=${selectedFormat}`; + } + }; + + useEffect(() => { + window?.fireEvent({ + action: 'tutor_user', + category: 'ai_tutor', + label: 'Visited AI Course Page', + }); + }, []); + + const trimmedTitle = title.trim(); + const canGenerate = trimmedTitle && trimmedTitle.length >= 3; + + return ( +
+
+ {isUpgradeModalOpen && ( + setIsUpgradeModalOpen(false)} /> + )} + {showLimitWarning && ( +
+ {selectedLimit?.used} of {selectedLimit?.limit} {selectedFormat}s + +
+ )} + +

+ What can I help you learn? +

+

+ Enter a topic below to generate a personalized course for it +

+
+ +
{ + e.preventDefault(); + handleSubmit(); + }} + > +
+ + { + setTitle(e.target.value); + setShowFineTuneOptions(false); + }} + className="block w-full rounded-xl border border-gray-200 bg-white p-4 outline-none placeholder:text-gray-500 focus:border-gray-500" + required + minLength={3} + data-clarity-unmask="true" + /> +
+
+ +
+ {allowedFormats.map((format) => { + const isSelected = format.value === selectedFormat; + + return ( + { + setSelectedFormat(format.value); + setUrlParams({ format: format.value }); + }} + icon={format.icon} + isSelected={isSelected} + /> + ); + })} +
+
+ + + + {showFineTuneOptions && ( + + )} + + + +
+ ); +} diff --git a/src/components/ContentGenerator/FormatItem.tsx b/src/components/ContentGenerator/FormatItem.tsx new file mode 100644 index 000000000000..9797ac0c5623 --- /dev/null +++ b/src/components/ContentGenerator/FormatItem.tsx @@ -0,0 +1,29 @@ +import { type LucideIcon } from 'lucide-react'; +import { cn } from '../../lib/classname'; + +type FormatItemProps = { + label: string; + onClick: () => void; + icon: LucideIcon; + isSelected: boolean; +}; + +export function FormatItem(props: FormatItemProps) { + const { label, onClick, icon: Icon, isSelected } = props; + + return ( + + ); +} diff --git a/src/components/ContentGenerator/QuestionAnswerChat.tsx b/src/components/ContentGenerator/QuestionAnswerChat.tsx new file mode 100644 index 000000000000..148f4394c155 --- /dev/null +++ b/src/components/ContentGenerator/QuestionAnswerChat.tsx @@ -0,0 +1,361 @@ +import { useQuery } from '@tanstack/react-query'; +import { queryClient } from '../../stores/query-client'; +import { + aiQuestionSuggestionsOptions, + type AIQuestionSuggestionsResponse, +} from '../../queries/user-ai-session'; +import type { AllowedFormat } from './ContentGenerator'; +import { Loader2Icon, RefreshCcwIcon, SendIcon, Trash2 } from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; +import { cn } from '../../lib/classname'; +import { flushSync } from 'react-dom'; +import { CheckIcon } from '../ReactIcons/CheckIcon'; +import { Tooltip } from '../Tooltip'; + +export type QuestionAnswerChatMessage = + | { role: 'user'; answer: string } + | { + role: 'assistant'; + question: string; + possibleAnswers: string[]; + }; + +type QuestionAnswerChatProps = { + term: string; + format: AllowedFormat | (string & {}); + questionAnswerChatMessages: QuestionAnswerChatMessage[]; + setQuestionAnswerChatMessages: ( + messages: QuestionAnswerChatMessage[], + ) => void; + defaultQuestions?: AIQuestionSuggestionsResponse['questions']; + type?: 'create' | 'update'; + + from?: 'content' | 'quiz'; + + className?: string; +}; + +export function QuestionAnswerChat(props: QuestionAnswerChatProps) { + const { + term, + format, + defaultQuestions, + questionAnswerChatMessages, + setQuestionAnswerChatMessages, + type = 'create', + className = '', + from = 'content', + } = props; + + const [activeMessageIndex, setActiveMessageIndex] = useState( + defaultQuestions?.length ?? 0, + ); + const [message, setMessage] = useState(''); + const [status, setStatus] = useState<'answering' | 'done'>('answering'); + + const scrollAreaRef = useRef(null); + const inputRef = useRef(null); + + const { + data: aiQuestionSuggestions, + isLoading: isLoadingAiQuestionSuggestions, + } = useQuery( + aiQuestionSuggestionsOptions({ term, format, from }, defaultQuestions), + queryClient, + ); + + const activeMessage = aiQuestionSuggestions?.questions[activeMessageIndex]; + + const scrollToBottom = () => { + if (!scrollAreaRef.current) { + return; + } + + scrollAreaRef.current.scrollTo({ + top: scrollAreaRef.current.scrollHeight, + behavior: 'instant', + }); + }; + const handleAnswerSelect = (answer: string) => { + const trimmedAnswer = answer.trim(); + if (!activeMessage || !trimmedAnswer) { + return; + } + + const newMessages: QuestionAnswerChatMessage[] = [ + ...questionAnswerChatMessages, + { + role: 'assistant', + ...activeMessage, + }, + { + role: 'user', + answer: trimmedAnswer, + }, + ]; + + setQuestionAnswerChatMessages(newMessages); + setMessage(''); + + const hasMoreMessages = + activeMessageIndex < aiQuestionSuggestions.questions.length - 1; + if (!hasMoreMessages) { + setStatus('done'); + return; + } + + flushSync(() => { + setActiveMessageIndex(activeMessageIndex + 1); + setStatus('answering'); + + // focus the input + inputRef.current?.focus(); + }); + + scrollToBottom(); + }; + + const handleReset = () => { + setQuestionAnswerChatMessages([]); + setActiveMessageIndex(0); + setStatus('answering'); + }; + + const handleEditMessage = (messageIndex: number) => { + // Remove the assistant question and user answer pair + // Since user messages are at odd indices, we want to remove both + // the assistant message (at messageIndex - 1) and the user message (at messageIndex) + const assistantMessageIndex = messageIndex - 1; + const newMessages = questionAnswerChatMessages.slice( + 0, + assistantMessageIndex, + ); + setQuestionAnswerChatMessages(newMessages); + + // Calculate which question should be active + // Since we removed both assistant and user messages, the question index + // is simply assistantMessageIndex / 2 + const questionIndex = Math.floor(assistantMessageIndex / 2); + setActiveMessageIndex(questionIndex); + setStatus('answering'); + + setMessage(''); + setTimeout(() => { + inputRef.current?.focus(); + }, 0); + }; + + useEffect(() => { + scrollToBottom(); + }, [defaultQuestions, type]); + + return ( + <> +
+ {isLoadingAiQuestionSuggestions && ( +
+
+ + Generating personalized questions... +
+
+ )} + + {!isLoadingAiQuestionSuggestions && status === 'done' && ( +
+
+ +

Preferences saved

+

+ You can now start generating {format} +

+ + +
+
+ )} + + {!isLoadingAiQuestionSuggestions && status === 'answering' && ( + <> +
+
+
+
+ {questionAnswerChatMessages.map((message, index) => ( + handleEditMessage(index) + : undefined + } + /> + ))} + + {activeMessage && ( + + )} +
+
+
+ + {!activeMessage && type === 'update' && ( +
+ +
+ )} + + {activeMessage && ( +
+
+
+ setMessage(e.target.value)} + className="w-full bg-transparent text-sm focus:outline-none" + placeholder={ + activeMessage.possibleAnswers + ? 'Type your answer...' + : 'Or type your own answer...' + } + data-clarity-unmask="true" + autoFocus + onKeyDown={(e) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleAnswerSelect(message); + setMessage(''); + } + }} + /> + + +
+
+
+ )} +
+ + )} +
+ + ); +} + +type QuestionAnswerChatMessageProps = { + role: 'user' | 'assistant'; + question?: string; + answer?: string; + possibleAnswers?: string[]; + onAnswerSelect?: (answer: string) => void; + onEdit?: () => void; +}; + +function QuestionAnswerChatMessage(props: QuestionAnswerChatMessageProps) { + const { role, question, answer, possibleAnswers, onAnswerSelect, onEdit } = + props; + + const hasAnswers = possibleAnswers && possibleAnswers.length > 0; + + return ( +
+ {role === 'assistant' && ( +
+
{question}
+ {hasAnswers && onAnswerSelect && ( +
+
+ {possibleAnswers.map((answer) => ( + + ))} +
+
+ )} +
+ )} + {role === 'user' && ( +
+
{answer}
+ {onEdit && ( +
+ + + Reanswer after this point + +
+ )} +
+ )} +
+ ); +} diff --git a/src/components/CookieSettingsButton.tsx b/src/components/CookieSettingsButton.tsx new file mode 100644 index 000000000000..231e28f0450a --- /dev/null +++ b/src/components/CookieSettingsButton.tsx @@ -0,0 +1,31 @@ +import { cn } from '../lib/classname'; +import { Cookie } from 'lucide-react'; + +export function CookieSettingsButton() { + return ( +
+ +
+ ); +} diff --git a/src/components/CreateTeam/ContentConfirmationModal.tsx b/src/components/CreateTeam/ContentConfirmationModal.tsx new file mode 100644 index 000000000000..4d45a69e7a30 --- /dev/null +++ b/src/components/CreateTeam/ContentConfirmationModal.tsx @@ -0,0 +1,42 @@ +import { Modal } from '../Modal'; + +type ContentConfirmationModalProps = { + onClose: () => void; + onClick: (shouldCopy: boolean) => void; +}; + +export function ContentConfirmationModal(props: ContentConfirmationModalProps) { + const { onClose, onClick } = props; + + return ( + +
+

+ Copy Node Details and Resources? +

+

+ This will just copy the roadmap in your team. Would you like to copy + the resource links and node details as well? +

+
+ + +
+
+
+ ); +} diff --git a/src/components/CreateTeam/CreateTeamForm.tsx b/src/components/CreateTeam/CreateTeamForm.tsx new file mode 100644 index 000000000000..84fd33fae1f6 --- /dev/null +++ b/src/components/CreateTeam/CreateTeamForm.tsx @@ -0,0 +1,221 @@ +import { useEffect, useState } from 'react'; +import { Stepper } from '../Stepper'; +import { Step0, type ValidTeamType } from './Step0'; +import { Step1, type ValidTeamSize } from './Step1'; +import { Step2 } from './Step2'; +import { httpGet } from '../../lib/http'; +import { getUrlParams, setUrlParams } from '../../lib/browser'; +import { pageProgressMessage } from '../../stores/page'; +import type { TeamResourceConfig } from './RoadmapSelector'; +import { Step3 } from './Step3'; +import { Step4 } from './Step4'; +import { useToast } from '../../hooks/use-toast'; + +export interface TeamDocument { + _id?: string; + name: string; + avatar?: string; + creatorId: string; + links: { + website?: string; + github?: string; + linkedIn?: string; + }; + type: ValidTeamType; + personalProgressOnly?: boolean; + canMemberSendInvite: boolean; + teamSize?: ValidTeamSize; + createdAt: Date; + updatedAt: Date; +} + +export function CreateTeamForm() { + // Can't use hook `useParams` because it runs asynchronously + const { s: queryStepIndex, t: teamId } = getUrlParams(); + + const toast = useToast(); + const [team, setTeam] = useState(); + + const [loadingTeam, setLoadingTeam] = useState(!!teamId && !team?._id); + const [stepIndex, setStepIndex] = useState(0); + + async function loadTeam( + teamIdToFetch: string, + requiredStepIndex: number | string, + ) { + const { response, error } = await httpGet( + `${import.meta.env.PUBLIC_API_URL}/v1-get-team/${teamIdToFetch}`, + ); + + if (error || !response) { + toast.error(error?.message || 'Error loading team'); + window.location.href = '/account'; + return; + } + + const requiredStepIndexNumber = parseInt(requiredStepIndex as string, 10); + const completedSteps = Array(requiredStepIndexNumber) + .fill(1) + .map((_, counter) => counter); + + setTeam(response); + setSelectedTeamType(response.type); + setCompletedSteps(completedSteps); + setStepIndex(requiredStepIndexNumber); + + await loadTeamResourceConfig(teamIdToFetch); + } + + const [teamResourceConfig, setTeamResourceConfig] = + useState([]); + + async function loadTeamResourceConfig(teamId: string) { + const { error, response } = await httpGet( + `${import.meta.env.PUBLIC_API_URL}/v1-get-team-resource-config/${teamId}`, + ); + if (error || !Array.isArray(response)) { + console.error(error); + return; + } + + setTeamResourceConfig(response); + } + + useEffect(() => { + if (!teamId || !queryStepIndex || team) { + return; + } + + pageProgressMessage.set('Fetching team'); + setLoadingTeam(true); + loadTeam(teamId, queryStepIndex).finally(() => { + setLoadingTeam(false); + pageProgressMessage.set(''); + }); + + // fetch team and move to step + }, [teamId, queryStepIndex]); + + const [selectedTeamType, setSelectedTeamType] = useState( + team?.type || 'company', + ); + + const [completedSteps, setCompletedSteps] = useState([0]); + if (loadingTeam) { + return null; + } + + let stepForm = null; + if (stepIndex === 0) { + stepForm = ( + { + if (team?._id) { + setUrlParams({ t: team._id, s: '1' }); + } + + setCompletedSteps([0]); + setStepIndex(1); + }} + /> + ); + } else if (stepIndex === 1) { + stepForm = ( + { + if (team?._id) { + setUrlParams({ t: team._id, s: '0' }); + } + + setStepIndex(0); + }} + onStepComplete={(team: TeamDocument) => { + const createdTeamId = team._id!; + + setUrlParams({ t: createdTeamId, s: '2' }); + + setCompletedSteps([0, 1]); + setStepIndex(2); + setTeam(team); + }} + selectedTeamType={selectedTeamType} + /> + ); + } else if (stepIndex === 2) { + stepForm = ( + { + if (team) { + setUrlParams({ t: team._id!, s: '1' }); + } + + setStepIndex(1); + }} + onNext={() => { + setUrlParams({ t: teamId!, s: '3' }); + setCompletedSteps([0, 1, 2]); + setStepIndex(3); + }} + /> + ); + } else if (stepIndex === 3) { + stepForm = ( + { + if (team) { + setUrlParams({ t: team._id!, s: '2' }); + } + + setStepIndex(2); + }} + onNext={() => { + if (team) { + setUrlParams({ t: team._id!, s: '4' }); + } + + setCompletedSteps([0, 1, 2, 3]); + setStepIndex(4); + }} + /> + ); + } else if (stepIndex === 4) { + stepForm = ; + } + + return ( +
+
+

Create Team

+

+ Complete the steps below to create your team +

+
+
+ +
+ + {stepForm} +
+ ); +} diff --git a/src/components/CreateTeam/NextButton.tsx b/src/components/CreateTeam/NextButton.tsx new file mode 100644 index 000000000000..8d8e478366eb --- /dev/null +++ b/src/components/CreateTeam/NextButton.tsx @@ -0,0 +1,44 @@ +import { Spinner } from '../ReactIcons/Spinner'; + +type NextButtonProps = { + isLoading?: boolean; + loadingMessage?: string; + text: string; + hasNextArrow?: boolean; + onClick?: () => void; + type?: string; +}; + +export function NextButton(props: NextButtonProps) { + const { + isLoading = false, + text = 'Next Step', + type = 'button', + loadingMessage = 'Please wait ..', + onClick = () => null, + hasNextArrow = true, + } = props; + + return ( + + ); +} diff --git a/src/components/CreateTeam/RoadmapSelector.tsx b/src/components/CreateTeam/RoadmapSelector.tsx new file mode 100644 index 000000000000..748a8dae4794 --- /dev/null +++ b/src/components/CreateTeam/RoadmapSelector.tsx @@ -0,0 +1,381 @@ +import { useEffect, useState } from 'react'; +import { httpGet, httpPut } from '../../lib/http'; +import type { PageType } from '../CommandMenu/CommandMenu'; +import { pageProgressMessage } from '../../stores/page'; +import { UpdateTeamResourceModal } from './UpdateTeamResourceModal'; +import { SelectRoadmapModal } from './SelectRoadmapModal'; +import { Map, Shapes } from 'lucide-react'; +import type { + AllowedRoadmapVisibility, + RoadmapDocument, +} from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal'; +import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal'; +import { useToast } from '../../hooks/use-toast'; +import { ContentConfirmationModal } from './ContentConfirmationModal'; + +export type TeamResourceConfig = { + isCustomResource: boolean; + roadmapSlug?: string; + title: string; + description?: string; + visibility?: AllowedRoadmapVisibility; + resourceId: string; + resourceType: string; + removed: string[]; + topics?: number; + sharedTeamMemberIds: string[]; + sharedFriendIds: string[]; + defaultRoadmapId?: string; +}[]; + +type RoadmapSelectorProps = { + teamId: string; + teamResources: TeamResourceConfig; + setTeamResources: (config: TeamResourceConfig) => void; +}; + +export function RoadmapSelector(props: RoadmapSelectorProps) { + const { teamId, teamResources = [], setTeamResources } = props; + + const toast = useToast(); + const [removingRoadmapId, setRemovingRoadmapId] = useState(''); + const [showSelectRoadmapModal, setShowSelectRoadmapModal] = useState(false); + const [allRoadmaps, setAllRoadmaps] = useState([]); + const [changingRoadmapId, setChangingRoadmapId] = useState(''); + const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false); + + const [error, setError] = useState(''); + const [confirmationContentId, setConfirmationContentId] = useState(); + + async function loadAllRoadmaps() { + const { error, response } = await httpGet(`/pages.json`); + + if (error) { + toast.error(error.message || 'Something went wrong. Please try again!'); + setError(error.message || 'Something went wrong. Please try again!'); + return; + } + + if (!response) { + return []; + } + + const allRoadmaps = response + .filter((page) => page.group === 'Roadmaps') + .sort((a, b) => { + if (a.title === 'Android') return 1; + return a.title.localeCompare(b.title); + }); + + setAllRoadmaps(allRoadmaps); + return response; + } + + async function deleteResource(roadmapId: string) { + if (!teamId) { + return; + } + + pageProgressMessage.set(`Deleting resource`); + const { error, response } = await httpPut( + `${ + import.meta.env.PUBLIC_API_URL + }/v1-delete-team-resource-config/${teamId}`, + { + resourceId: roadmapId, + resourceType: 'roadmap', + }, + ); + + if (error || !response) { + setError(error?.message || 'Error deleting roadmap'); + return; + } + + setTeamResources(response); + } + + async function onRemove(resourceId: string) { + pageProgressMessage.set('Removing roadmap'); + + deleteResource(resourceId).finally(() => { + pageProgressMessage.set(''); + }); + } + + async function addTeamResource(roadmapId: string, shouldCopyContent = false) { + if (!teamId) { + return; + } + + pageProgressMessage.set(`Adding roadmap to team`); + const renderer = allRoadmaps.find((r) => r.id === roadmapId)?.renderer; + const { error, response } = await httpPut( + `${ + import.meta.env.PUBLIC_API_URL + }/v1-update-team-resource-config/${teamId}`, + { + teamId: teamId, + resourceId: roadmapId, + resourceType: 'roadmap', + removed: [], + renderer: renderer || 'balsamiq', + shouldCopyContent, + }, + ); + + if (error || !response) { + setError(error?.message || 'Error adding roadmap'); + return; + } + + setTeamResources(response); + if (renderer === 'editor') { + setShowSelectRoadmapModal(false); + } + } + + useEffect(() => { + loadAllRoadmaps().finally(() => {}); + }, []); + + function handleCustomRoadmapCreated(roadmap: RoadmapDocument) { + const { _id: roadmapId } = roadmap; + if (!roadmapId) { + return; + } + + loadAllRoadmaps().finally(() => {}); + addTeamResource(roadmapId).finally(() => { + pageProgressMessage.set(''); + }); + } + + const confirmationContentIdModal = confirmationContentId && ( + { + setConfirmationContentId(''); + }} + onClick={(shouldCopy) => { + addTeamResource(confirmationContentId, shouldCopy).finally(() => { + pageProgressMessage.set(''); + setConfirmationContentId(''); + }); + }} + /> + ); + + return ( +
+ {confirmationContentIdModal} + + {changingRoadmapId && ( + setChangingRoadmapId('')} + resourceId={changingRoadmapId} + resourceType={'roadmap'} + teamId={teamId} + setTeamResourceConfig={setTeamResources} + defaultRemovedItems={ + teamResources.find((c) => c.resourceId === changingRoadmapId) + ?.removed || [] + } + /> + )} + {showSelectRoadmapModal && ( + setShowSelectRoadmapModal(false)} + teamResourceConfig={teamResources.map((r) => r.resourceId)} + allRoadmaps={allRoadmaps.filter((r) => r.renderer === 'editor')} + teamId={teamId} + onRoadmapAdd={(roadmapId) => { + const isEditorRoadmap = allRoadmaps.find( + (r) => r.id === roadmapId && r.renderer === 'editor', + ); + + if (!isEditorRoadmap) { + addTeamResource(roadmapId).finally(() => { + pageProgressMessage.set(''); + }); + + return; + } + + setShowSelectRoadmapModal(false); + setConfirmationContentId(roadmapId); + }} + onRoadmapRemove={(roadmapId) => { + onRemove(roadmapId).finally(() => {}); + }} + /> + )} + +
+ {isCreatingRoadmap && ( + setIsCreatingRoadmap(false)} + onCreated={(roadmap: RoadmapDocument) => { + handleCustomRoadmapCreated(roadmap); + setIsCreatingRoadmap(false); + }} + /> + )} + + + + or + + +
+ + {!teamResources.length && ( +
+ +

No roadmaps selected.

+

+ Pick from{' '} + setShowSelectRoadmapModal(true)} + className="cursor-pointer underline" + > + our roadmaps + {' '} + or{' '} + { + setIsCreatingRoadmap(true); + }} + className="cursor-pointer underline" + > + create a new one + + . +

+
+ )} + + {teamResources.length > 0 && ( +
+ {teamResources.map( + ({ + isCustomResource, + title: roadmapTitle, + resourceId, + removed: removedTopics, + topics, + }) => { + return ( +
+
+ + {roadmapTitle} + + {removedTopics.length > 0 || (topics && topics > 0) ? ( + + {isCustomResource ? ( + <> + Custom · {topics} topic + {topics && topics > 1 ? 's' : ''} + + ) : ( + <> + {removedTopics.length} topic + {removedTopics.length > 1 ? 's' : ''} removed + + )} + + ) : ( + + {isCustomResource + ? 'Placeholder roadmap.' + : 'No changes made ..'} + + )} +
+ + {removingRoadmapId === resourceId && ( +
+ + Are you sure?{' '} + {' '} + + +
+ )} + {(!removingRoadmapId || removingRoadmapId !== resourceId) && ( +
+ + + +
+ )} +
+ ); + }, + )} +
+ )} +
+ ); +} diff --git a/src/components/CreateTeam/RoleDropdown.tsx b/src/components/CreateTeam/RoleDropdown.tsx new file mode 100644 index 000000000000..8d93da77cb26 --- /dev/null +++ b/src/components/CreateTeam/RoleDropdown.tsx @@ -0,0 +1,132 @@ +import { ChevronDownIcon } from '../ReactIcons/ChevronDownIcon'; +import { useRef, useState } from 'react'; +import { useOutsideClick } from '../../hooks/use-outside-click'; + +const allowedRoles = [ + { + name: 'Admin', + value: 'admin', + description: 'Can do everything', + }, + { + name: 'Manager', + value: 'manager', + description: 'Can manage team and skills', + }, + { + name: 'Member', + value: 'member', + description: 'Can view team and skills', + }, +] as const; + +export type AllowedRoles = (typeof allowedRoles)[number]['value']; + +type RoleDropdownProps = { + className?: string; + selectedRole: string; + setSelectedRole: (role: AllowedRoles) => void; +}; + +export function RoleDropdown(props: RoleDropdownProps) { + const { selectedRole, setSelectedRole, className = 'w-[120px]' } = props; + const dropdownRef = useRef(null); + + const [activeRoleIndex, setActiveRoleIndex] = useState(0); + const [isMenuOpen, setIsMenuOpen] = useState(false); + + useOutsideClick(dropdownRef, () => { + setIsMenuOpen(false); + }); + + return ( +
+ + + {isMenuOpen && ( +
+
+ {allowedRoles.map((allowedRole, roleCounter) => ( + + ))} +
+
+ )} +
+ ); +} diff --git a/src/components/CreateTeam/SelectRoadmapModal.tsx b/src/components/CreateTeam/SelectRoadmapModal.tsx new file mode 100644 index 000000000000..aa1433058587 --- /dev/null +++ b/src/components/CreateTeam/SelectRoadmapModal.tsx @@ -0,0 +1,161 @@ +import { useEffect, useRef, useState } from 'react'; +import { useKeydown } from '../../hooks/use-keydown'; +import { useOutsideClick } from '../../hooks/use-outside-click'; +import type { PageType } from '../CommandMenu/CommandMenu'; +import type { TeamResourceConfig } from './RoadmapSelector'; +import { SelectRoadmapModalItem } from './SelectRoadmapModalItem'; +import { XIcon } from 'lucide-react'; + +export type SelectRoadmapModalProps = { + teamId: string; + allRoadmaps: PageType[]; + onClose: () => void; + teamResourceConfig: string[]; + onRoadmapAdd: (roadmapId: string) => void; + onRoadmapRemove: (roadmapId: string) => void; +}; + +export function SelectRoadmapModal(props: SelectRoadmapModalProps) { + const { + onClose, + allRoadmaps, + onRoadmapAdd, + onRoadmapRemove, + teamResourceConfig, + } = props; + const popupBodyEl = useRef(null); + const searchInputEl = useRef(null); + + const [searchResults, setSearchResults] = useState(allRoadmaps); + const [searchText, setSearchText] = useState(''); + + useKeydown('Escape', () => { + onClose(); + }); + + useOutsideClick(popupBodyEl, () => { + onClose(); + }); + + useEffect(() => { + if (!searchInputEl.current) { + return; + } + + searchInputEl.current.focus(); + }, [searchInputEl]); + + useEffect(() => { + if (searchText.length === 0) { + setSearchResults(allRoadmaps); + return; + } + + const searchResults = allRoadmaps.filter((roadmap) => { + return ( + roadmap.title.toLowerCase().includes(searchText.toLowerCase()) || + roadmap.id.toLowerCase().includes(searchText.toLowerCase()) + ); + }); + setSearchResults(searchResults); + }, [searchText, allRoadmaps]); + + const roleBasedRoadmaps = searchResults.filter((roadmap) => + roadmap?.metadata?.tags?.includes('role-roadmap'), + ); + const skillBasedRoadmaps = searchResults.filter((roadmap) => + roadmap?.metadata?.tags?.includes('skill-roadmap'), + ); + + return ( +
+
+
+ + setSearchText((e.target as HTMLInputElement).value)} + /> +
+ + Role Based Roadmaps + + {roleBasedRoadmaps.length === 0 && ( +

+ )} + {roleBasedRoadmaps.length > 0 && ( +
+ {roleBasedRoadmaps.map((roadmap) => { + const isSelected = teamResourceConfig.includes(roadmap.id); + + return ( + { + if (isSelected) { + onRoadmapRemove(roadmap.id); + } else { + onRoadmapAdd(roadmap.id); + } + }} + /> + ); + })} +
+ )} + + Skill Based Roadmaps + +
+ {skillBasedRoadmaps.map((roadmap) => { + const isSelected = teamResourceConfig.includes(roadmap.id); + + return ( + { + if (isSelected) { + onRoadmapRemove(roadmap.id); + } else { + onRoadmapAdd(roadmap.id); + } + }} + /> + ); + })} +
+
+ +
+

+ More Official Roadmaps Coming Soon +

+

+ We are currently adding more of our official roadmaps to this + list. If you don't see the roadmap you are looking for, please + check back later. +

+
+
+
+
+ ); +} diff --git a/src/components/CreateTeam/SelectRoadmapModalItem.tsx b/src/components/CreateTeam/SelectRoadmapModalItem.tsx new file mode 100644 index 000000000000..e2a579e9460a --- /dev/null +++ b/src/components/CreateTeam/SelectRoadmapModalItem.tsx @@ -0,0 +1,34 @@ +import type { SelectRoadmapModalProps } from './SelectRoadmapModal'; + +type SelectRoadmapModalItemProps = { + title: string; + isSelected: boolean; + onClick: () => void; +}; + +export function SelectRoadmapModalItem(props: SelectRoadmapModalItemProps) { + const { isSelected, onClick, title } = props; + return ( + + ); +} diff --git a/src/components/CreateTeam/Step0.tsx b/src/components/CreateTeam/Step0.tsx new file mode 100644 index 000000000000..4143ff507554 --- /dev/null +++ b/src/components/CreateTeam/Step0.tsx @@ -0,0 +1,125 @@ +import type { TeamDocument } from './CreateTeamForm'; +import { httpPut } from '../../lib/http'; +import { useState } from 'react'; +import { NextButton } from './NextButton'; +import { BuildingIcon } from '../ReactIcons/BuildingIcon.tsx'; +import { UsersIcon } from '../ReactIcons/UsersIcon.tsx'; + +export const validTeamTypes = [ + { + value: 'company', + label: 'Company', + icon: BuildingIcon, + description: + 'Track the skills and learning progress of the tech team at your company', + }, + { + value: 'study_group', + label: 'Study Group', + icon: UsersIcon, + description: + 'Invite your friends or course-mates and track your learning progress together', + }, +] as const; + +export type ValidTeamType = (typeof validTeamTypes)[number]['value']; + +type Step0Props = { + team?: TeamDocument; + selectedTeamType: ValidTeamType; + setSelectedTeamType: (teamType: ValidTeamType) => void; + onStepComplete: () => void; +}; + +export function Step0(props: Step0Props) { + const { team, selectedTeamType, onStepComplete, setSelectedTeamType } = props; + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(); + + async function onNextClick() { + if (!team) { + onStepComplete(); + return; + } + + setIsLoading(true); + setError(''); + + const { response, error } = await httpPut( + `${import.meta.env.PUBLIC_API_URL}/v1-update-team/${team._id}`, + { + name: team.name, + website: team?.links?.website || undefined, + type: selectedTeamType, + gitHubUrl: team?.links?.github || undefined, + ...(selectedTeamType === 'company' && { + teamSize: team.teamSize, + linkedInUrl: team?.links?.linkedIn || undefined, + }), + }, + ); + + if (error || !response) { + setIsLoading(false); + setError(error?.message || 'Something went wrong'); + return; + } + + setIsLoading(false); + setError(''); + onStepComplete(); + } + + return ( + <> +
+ {validTeamTypes.map((validTeamType) => ( + + ))} +
+ + {/*Error message*/} + {error &&
{error}
} + + + + ); +} diff --git a/src/components/CreateTeam/Step1.tsx b/src/components/CreateTeam/Step1.tsx new file mode 100644 index 000000000000..5604e4a5e109 --- /dev/null +++ b/src/components/CreateTeam/Step1.tsx @@ -0,0 +1,266 @@ +import { type FormEvent, useEffect, useRef, useState } from 'react'; +import { type AppError, httpPost, httpPut } from '../../lib/http'; +import type { ValidTeamType } from './Step0'; +import type { TeamDocument } from './CreateTeamForm'; +import { NextButton } from './NextButton'; + +export const validTeamSizes = [ + '1-5', + '6-10', + '11-25', + '26-50', + '51-100', + '101-200', + '201-500', + '501-1000', + '1000+', +] as const; + +export type ValidTeamSize = (typeof validTeamSizes)[number]; + +type Step1Props = { + team?: TeamDocument; + selectedTeamType: ValidTeamType; + onStepComplete: (team: TeamDocument) => void; + onBack: () => void; +}; + +export function Step1(props: Step1Props) { + const { team, selectedTeamType, onBack, onStepComplete } = props; + const [error, setError] = useState(''); + + const nameRef = useRef(null); + + useEffect(() => { + if (!nameRef.current) { + return; + } + + nameRef.current.focus(); + }, [nameRef]); + + const [isLoading, setIsLoading] = useState(false); + + const [name, setName] = useState(team?.name || ''); + const [website, setWebsite] = useState(team?.links?.website || ''); + const [linkedInUrl, setLinkedInUrl] = useState(team?.links?.linkedIn || ''); + const [gitHubUrl, setGitHubUrl] = useState(team?.links?.github || ''); + const [teamSize, setTeamSize] = useState( + team?.teamSize || ('' as any), + ); + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + setIsLoading(true); + if (!name || !selectedTeamType) { + setIsLoading(false); + return; + } + + let response: TeamDocument | undefined; + let error: AppError | undefined; + + if (!team?._id) { + ({ response, error } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-create-team`, + { + name, + website: website || undefined, + type: selectedTeamType, + gitHubUrl: gitHubUrl || undefined, + ...(selectedTeamType === 'company' && { + teamSize, + linkedInUrl: linkedInUrl || undefined, + }), + roadmapIds: [], + bestPracticeIds: [], + }, + )); + + if (error || !response?._id) { + setError(error?.message || 'Something went wrong. Please try again.'); + setIsLoading(false); + return; + } + + onStepComplete(response as TeamDocument); + } else { + ({ response, error } = await httpPut( + `${import.meta.env.PUBLIC_API_URL}/v1-update-team/${team._id}`, + { + name, + website: website || undefined, + type: selectedTeamType, + gitHubUrl: gitHubUrl || undefined, + ...(selectedTeamType === 'company' && { + teamSize, + linkedInUrl: linkedInUrl || undefined, + }), + }, + )); + + if (error || (response as any)?.status !== 'ok') { + setError(error?.message || 'Something went wrong. Please try again.'); + setIsLoading(false); + return; + } + + onStepComplete({ + ...team, + name, + _id: team._id, + links: { + website: website || team?.links?.website, + linkedIn: linkedInUrl || team?.links?.linkedIn, + github: gitHubUrl || team?.links?.github, + }, + type: selectedTeamType, + teamSize: teamSize!, + }); + } + }; + + return ( +
+
+ + setName((e.target as HTMLInputElement).value)} + /> +
+ + {selectedTeamType === 'company' && ( +
+ + setWebsite((e.target as HTMLInputElement).value)} + /> +
+ )} + + {selectedTeamType === 'company' && ( +
+ + + setLinkedInUrl((e.target as HTMLInputElement).value) + } + /> +
+ )} + +
+ + setGitHubUrl((e.target as HTMLInputElement).value)} + /> +
+ + {selectedTeamType === 'company' && ( +
+ + +
+ )} + + {error && ( +
+ {error} +
+ )} + +
+ + +
+
+ ); +} diff --git a/src/components/CreateTeam/Step2.tsx b/src/components/CreateTeam/Step2.tsx new file mode 100644 index 000000000000..7cf981c48140 --- /dev/null +++ b/src/components/CreateTeam/Step2.tsx @@ -0,0 +1,73 @@ +import { RoadmapSelector, type TeamResourceConfig } from './RoadmapSelector'; +import type { TeamDocument } from './CreateTeamForm'; + +type Step2Props = { + team: TeamDocument; + teamResourceConfig: TeamResourceConfig; + setTeamResourceConfig: (config: TeamResourceConfig) => void; + onBack: () => void; + onNext: () => void; +}; + +export function Step2(props: Step2Props) { + const { team, onBack, onNext, teamResourceConfig, setTeamResourceConfig } = + props; + + return ( + <> +
+
+

+ Select Roadmaps +

+

+ You can always add and customize your roadmaps later. +

+
+ + +
+ +
+ + +
+ + +
+
+ + ); +} diff --git a/src/components/CreateTeam/Step3.tsx b/src/components/CreateTeam/Step3.tsx new file mode 100644 index 000000000000..b6a0085b61e5 --- /dev/null +++ b/src/components/CreateTeam/Step3.tsx @@ -0,0 +1,199 @@ +import type { TeamDocument } from './CreateTeamForm'; +import { NextButton } from './NextButton'; +import { TrashIcon } from '../ReactIcons/TrashIcon'; +import { type AllowedRoles, RoleDropdown } from './RoleDropdown'; +import { useEffect, useRef, useState } from 'react'; +import { httpPost } from '../../lib/http'; + +type Step3Props = { + team?: TeamDocument; + onNext: () => void; + onBack: () => void; +}; + +type InviteType = { + id: string; + email: string; + role: AllowedRoles; +}; + +function generateId() { + return `${new Date().getTime()}`; +} + +export function Step3(props: Step3Props) { + const { onNext, onBack, team } = props; + + const [error, setError] = useState(''); + const [invitingTeam, setInvitingTeam] = useState(false); + const emailInputRef = useRef(null); + + const [users, setUsers] = useState([ + { + id: generateId(), + email: '', + role: 'member', + }, + ]); + + async function inviteTeam() { + setInvitingTeam(true); + const { error, response } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-invite-team/${team?._id}`, + { + members: users, + } + ); + + if (error || !response) { + setError(error?.message || 'Something went wrong'); + setInvitingTeam(false); + + return; + } + + onNext(); + } + + function focusLastEmailInput() { + if (!emailInputRef.current) { + return; + } + + (emailInputRef.current as HTMLInputElement).focus(); + } + + function onSubmit(e: any) { + e.preventDefault(); + + inviteTeam().finally(() => null); + } + + useEffect(() => { + focusLastEmailInput(); + }, [users.length]); + + return ( +
+
+

Invite your Team

+

+ Use the form below to invite your team members to your team. You can + also invite them later. +

+
+
+ {users.map((user, userCounter) => { + return ( +
+ { + const newUsers = users.map((u) => { + if (u.id === user.id) { + return { + ...u, + email: (e.target as HTMLInputElement)?.value, + }; + } + + return u; + }); + + setUsers(newUsers); + }} + className="grow rounded-md border border-gray-200 bg-white px-4 py-2 text-gray-900" + /> + { + const newUsers = users.map((u) => { + if (u.id === user.id) { + return { + ...u, + role, + }; + } + + return u; + }); + + setUsers(newUsers); + }} + /> + +
+ ); + })} +
+ {users.length <= 30 && ( + + )} + + {error && ( +
+ {error} +
+ )} + +
+ +
+ + +
+
+
+ ); +} diff --git a/src/components/CreateTeam/Step4.tsx b/src/components/CreateTeam/Step4.tsx new file mode 100644 index 000000000000..1591703fb919 --- /dev/null +++ b/src/components/CreateTeam/Step4.tsx @@ -0,0 +1,26 @@ +import { CheckIcon } from '../ReactIcons/CheckIcon'; +import type { TeamDocument } from './CreateTeamForm'; + +type Step4Props = { + team: TeamDocument; +}; + +export function Step4({ team }: Step4Props) { + return ( +
+
+ +

Team Created

+

+ Your team has been created. Happy learning! +

+ + View Team + +
+
+ ); +} diff --git a/src/components/CreateTeam/UpdateTeamResourceModal.tsx b/src/components/CreateTeam/UpdateTeamResourceModal.tsx new file mode 100644 index 000000000000..253f621b7404 --- /dev/null +++ b/src/components/CreateTeam/UpdateTeamResourceModal.tsx @@ -0,0 +1,211 @@ +import { useEffect, useRef, useState } from 'react'; +import { wireframeJSONToSVG } from 'roadmap-renderer'; +import { Spinner } from '../ReactIcons/Spinner'; +import { httpPut } from '../../lib/http'; +import { renderTopicProgress } from '../../lib/resource-progress'; +import '../FrameRenderer/FrameRenderer.css'; +import { useOutsideClick } from '../../hooks/use-outside-click'; +import { useKeydown } from '../../hooks/use-keydown'; +import type { TeamResourceConfig } from './RoadmapSelector'; +import { useToast } from '../../hooks/use-toast'; +import {replaceChildren} from "../../lib/dom.ts"; + +export type ProgressMapProps = { + teamId: string; + resourceId: string; + resourceType: 'roadmap' | 'best-practice'; + defaultRemovedItems?: string[]; + setTeamResourceConfig: (config: TeamResourceConfig) => void; + onClose: () => void; +}; + +export function UpdateTeamResourceModal(props: ProgressMapProps) { + const { + defaultRemovedItems = [], + resourceId, + resourceType, + teamId, + setTeamResourceConfig, + onClose, + } = props; + + const containerEl = useRef(null); + const popupBodyEl = useRef(null); + + const toast = useToast(); + const [isLoading, setIsLoading] = useState(true); + const [isUpdating, setIsUpdating] = useState(false); + + const [removedItems, setRemovedItems] = + useState(defaultRemovedItems); + + useEffect(() => { + function onTopicClick(e: any) { + const groupEl = e.target.closest('.clickable-group'); + const groupId = groupEl?.dataset?.groupId; + + if (!groupId) { + return; + } + + const normalizedGroupId = groupId.replace(/^\d+-/, ''); + if (removedItems.includes(normalizedGroupId)) { + setRemovedItems((prev) => + prev.filter((id) => id !== normalizedGroupId) + ); + renderTopicProgress(normalizedGroupId, 'reset' as any); + } else { + setRemovedItems((prev) => [...prev, normalizedGroupId]); + renderTopicProgress(normalizedGroupId, 'removed'); + } + } + + document.addEventListener('click', onTopicClick); + return () => { + document.removeEventListener('click', onTopicClick); + }; + }, [removedItems]); + + let resourceJsonUrl = import.meta.env.DEV + ? 'http://localhost:3000' + : 'https://roadmap.sh'; + if (resourceType === 'roadmap') { + resourceJsonUrl += `/${resourceId}.json`; + } else { + resourceJsonUrl += `/best-practices/${resourceId}.json`; + } + + async function renderResource(jsonUrl: string) { + const res = await fetch(jsonUrl); + const json = await res.json(); + const svg = await wireframeJSONToSVG(json, { + fontURL: '/fonts/balsamiq.woff2', + }); + + replaceChildren(containerEl.current!, svg); + // containerEl.current?.replaceChildren(svg); + + // Render team configuration + removedItems.forEach((topicId: string) => { + renderTopicProgress(topicId, 'removed'); + }); + } + + useKeydown('Escape', () => { + onClose(); + }); + + useOutsideClick(popupBodyEl, () => { + onClose(); + }); + + async function onSaveChanges() { + if (removedItems.length === 0) { + return; + } + + setIsUpdating(true); + const { error, response } = await httpPut( + `${ + import.meta.env.PUBLIC_API_URL + }/v1-update-team-resource-config/${teamId}`, + { + teamId: teamId, + resourceId: resourceId, + resourceType: resourceType, + removed: removedItems, + } + ); + + if (error || !response) { + toast.error(error?.message || 'Error adding roadmap'); + return; + } + + setTeamResourceConfig(response); + onClose(); + } + + useEffect(() => { + if ( + !containerEl.current || + !resourceJsonUrl || + !resourceId || + !resourceType || + !teamId + ) { + return; + } + + renderResource(resourceJsonUrl) + .catch((err) => { + console.error(err); + toast.error('Something went wrong. Please try again!'); + }) + .finally(() => { + setIsLoading(false); + }); + }, []); + + return ( +
+
+
+
+

+ Click and select the items to remove from the roadmap. +

+
+ + +
+
+
+ + {isLoading && ( +
+ +
+ )} +
+
+
+ ); +} diff --git a/src/components/CustomRoadmap/CreateRoadmap/CreateRoadmapButton.tsx b/src/components/CustomRoadmap/CreateRoadmap/CreateRoadmapButton.tsx new file mode 100644 index 000000000000..f95c4a297370 --- /dev/null +++ b/src/components/CustomRoadmap/CreateRoadmap/CreateRoadmapButton.tsx @@ -0,0 +1,75 @@ +import { Plus } from 'lucide-react'; +import { isLoggedIn } from '../../../lib/jwt'; +import { showLoginPopup } from '../../../lib/popup'; +import { cn } from '../../../lib/classname'; +import { CreateRoadmapModal } from './CreateRoadmapModal'; +import { useState } from 'react'; +import { useIsPaidUser } from '../../../queries/billing'; +import { UpgradeAccountModal } from '../../Billing/UpgradeAccountModal'; +import { MAX_ROADMAP_LIMIT } from '../RoadmapListPage'; + +type CreateRoadmapButtonProps = { + className?: string; + existingRoadmapCount?: number; + text?: string; + teamId?: string; +}; + +export function CreateRoadmapButton(props: CreateRoadmapButtonProps) { + const { + teamId, + className, + text = 'Create your own Roadmap', + existingRoadmapCount = 0, + } = props; + + const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false); + const [showUpgradeModal, setShowUpgradeModal] = useState(false); + const { isPaidUser, isLoading: isPaidUserLoading } = useIsPaidUser(); + + function toggleCreateRoadmapHandler() { + if (!isLoggedIn()) { + return showLoginPopup(); + } + + const hasExceededLimit = + !isPaidUser && + existingRoadmapCount > 0 && + existingRoadmapCount >= MAX_ROADMAP_LIMIT; + + if (hasExceededLimit) { + setShowUpgradeModal(true); + return; + } + + setIsCreatingRoadmap(true); + } + + return ( + <> + {showUpgradeModal && ( + setShowUpgradeModal(false)} /> + )} + + {isCreatingRoadmap && ( + { + setIsCreatingRoadmap(false); + }} + /> + )} + + + + ); +} diff --git a/src/components/CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx b/src/components/CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx new file mode 100644 index 000000000000..43bd2324c956 --- /dev/null +++ b/src/components/CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx @@ -0,0 +1,278 @@ +import { + type FormEvent, + type MouseEvent, + useEffect, + useRef, + useState, +} from 'react'; +import { Loader2 } from 'lucide-react'; +import { Modal } from '../../Modal'; +import { useToast } from '../../../hooks/use-toast'; +import { httpPost } from '../../../lib/http'; +import { cn } from '../../../lib/classname'; + +export const allowedRoadmapVisibility = [ + 'me', + 'friends', + 'team', + 'public', +] as const; +export type AllowedRoadmapVisibility = + (typeof allowedRoadmapVisibility)[number]; +export const allowedCustomRoadmapType = ['role', 'skill'] as const; +export type AllowedCustomRoadmapType = + (typeof allowedCustomRoadmapType)[number]; + +export const allowedShowcaseStatus = [ + 'submitted', + 'approved', + 'rejected', + 'rejected_with_reason', +] as const; +export type AllowedShowcaseStatus = (typeof allowedShowcaseStatus)[number]; + +export interface RoadmapDocument { + _id: string; + title: string; + description?: string; + slug?: string; + creatorId: string; + aiRoadmapId?: string; + teamId?: string; + topicCount: number; + visibility: AllowedRoadmapVisibility; + sharedFriendIds?: string[]; + sharedTeamMemberIds?: string[]; + feedbacks?: { + userId: string; + email: string; + feedback: string; + }[]; + metadata?: { + originalRoadmapId?: string; + defaultRoadmapId?: string; + }; + nodes: any[]; + edges: any[]; + + isDiscoverable?: boolean; + ratings: { + average: number; + totalCount: number; + breakdown: { + [key: number]: number; + }; + }; + + showcaseStatus?: AllowedShowcaseStatus; + showcaseRejectedReason?: string; + showcaseRejectedAt?: Date; + showcaseSubmittedAt?: Date; + showcaseApprovedAt?: Date; + + hasMigratedContent?: boolean; + + createdAt: Date; + updatedAt: Date; +} + +interface CreateRoadmapModalProps { + onClose: () => void; + onCreated?: (roadmap: RoadmapDocument) => void; + teamId?: string; + visibility?: AllowedRoadmapVisibility; +} + +export function CreateRoadmapModal(props: CreateRoadmapModalProps) { + const { onClose, onCreated, teamId } = props; + + const titleRef = useRef(null); + const toast = useToast(); + + const [isLoading, setIsLoading] = useState(false); + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const isInvalidDescription = description?.trim().length > 80; + + async function handleSubmit( + e: FormEvent | MouseEvent, + redirect: boolean = true, + ) { + e.preventDefault(); + if (isLoading) { + return; + } + + if (title.trim() === '' || isInvalidDescription) { + toast.error('Please fill all the fields'); + return; + } + + setIsLoading(true); + const { response, error } = await httpPost( + `${import.meta.env.PUBLIC_API_URL}/v1-create-roadmap`, + { + title, + description, + ...(teamId && { + teamId, + }), + nodes: [], + edges: [], + }, + ); + + if (error) { + setIsLoading(false); + toast.error(error?.message || 'Something went wrong, please try again'); + return; + } + + toast.success('Roadmap created successfully'); + if (redirect) { + window.location.href = `${ + import.meta.env.PUBLIC_EDITOR_APP_URL + }/${response?._id}`; + return; + } + + if (onCreated) { + onCreated(response as RoadmapDocument); + return; + } + + onClose(); + + setTitle(''); + setDescription(''); + setIsLoading(false); + } + + useEffect(() => { + titleRef.current?.focus(); + }, []); + + return ( + +
+

Create Roadmap

+

+ Add a title and description to your roadmap. +

+
+
+
+ +
+ setTitle(e.target.value)} + /> +
+
+
+ +
+