diff --git a/.coderabbit.yaml b/.coderabbit.yaml
new file mode 100644
index 00000000..0449dbcc
--- /dev/null
+++ b/.coderabbit.yaml
@@ -0,0 +1,18 @@
+# yaml-language-server: $schema=https://storage.googleapis.com/coderabbit_public_assets/schema.v2.json
+enable_free_tier: true
+reviews:
+ review_status: true
+ poem: false
+ profile: chill
+ path_instructions:
+ - path: '**/*.*'
+ instructions: |
+ Do not correct spelling errors or grammar mistakes.
+ auto_review:
+ enabled: true
+ base_branches:
+ - main
+ - prod
+ tools:
+ languagetool:
+ enabled: false
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 6bfc1412..d91a92ad 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -8,6 +8,4 @@ updates:
- package-ecosystem: 'npm' # See documentation for possible values
directory: '/' # Location of package manifests
schedule:
- interval: 'daily'
- assignees:
- - Inglan
+ interval: 'weekly'
diff --git a/.github/workflows/production_deploy.yml b/.github/workflows/production_deploy.yml
new file mode 100644
index 00000000..5a4a54fc
--- /dev/null
+++ b/.github/workflows/production_deploy.yml
@@ -0,0 +1,32 @@
+name: 'Move Project Items to Production'
+
+on:
+ push:
+ branches:
+ - prod
+
+jobs:
+ move_to_production:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.13'
+ - uses: actions/create-github-app-token@v1
+ id: app-token
+ with:
+ app-id: ${{ secrets.GH_APP_ID }}
+ private-key: ${{ secrets.GH_PRIVATE_KEY }}
+ - name: Install dependencies
+ run: |
+ python -m venv venv
+ venv/bin/pip install requests
+ - name: Move items from Done to In Production
+ run: |
+ venv/bin/python ci/scripts/move_to_production.py \
+ -t ${{ steps.app-token.outputs.token }} \
+ -o EducationalTools \
+ -p 4
diff --git a/ci/README.md b/ci/README.md
new file mode 100644
index 00000000..89f743e4
--- /dev/null
+++ b/ci/README.md
@@ -0,0 +1,152 @@
+# CI/CD Automation Scripts
+
+This directory contains automation scripts for managing GitHub issues and project boards.
+
+## Scripts Overview
+
+### 1. `issue.py` - Issue Management
+
+Automatically processes GitHub issues, particularly game requests:
+
+- Detects issues with `[Gmae Request]` prefix
+- Searches for relevant links on GitHub Pages
+- Posts automated comments with search results
+
+### 2. `move_to_production.py` - Project Board Automation
+
+Moves project items from "Done" status to "In Production" status:
+
+- Queries GitHub Projects v2 API using GraphQL
+- Finds all items with status "Done"
+- Updates them to "In Production" status
+- Used for production deployment automation
+
+### 3. `test_production_move.py` - Testing Script
+
+Manual testing script for the production move operation:
+
+- Allows testing the move operation without triggering workflows
+- Supports dry-run mode (future enhancement)
+- Useful for debugging and validation
+
+## GitHub Workflows
+
+### Issue Management (`.github/workflows/issue.yml`)
+
+Triggers on:
+
+- Issue opened
+- Issue edited
+
+Actions:
+
+- Runs `issue.py` script
+- Posts automated comments for game requests
+
+### Production Deployment (`.github/workflows/production_deploy.yml`)
+
+Triggers on:
+
+- Push to `prod` branch
+
+Actions:
+
+- Runs `move_to_production.py` script
+- Moves all "Done" items to "In Production" in project #4
+
+## Setup Requirements
+
+### GitHub App Configuration
+
+Both workflows use a GitHub App for authentication:
+
+1. **Secrets Required:**
+
+ - `GH_APP_ID` - Your GitHub App ID
+ - `GH_PRIVATE_KEY` - Your GitHub App private key
+
+2. **App Permissions:**
+ - Issues: Read & Write (for issue comments)
+ - Projects: Read & Write (for project board updates)
+ - Repository: Read (for workflow access)
+
+### Project Configuration
+
+The production deployment script assumes:
+
+- Organization: `EducationalTools`
+- Project number: `4`
+- Status field with options: "Done" and "In Production"
+
+These can be customized by modifying the workflow or script parameters.
+
+## Usage
+
+### Automatic Usage
+
+The workflows run automatically based on their triggers:
+
+- Issue workflow: When issues are opened/edited
+- Production workflow: When code is pushed to `prod` branch
+
+### Manual Testing
+
+To test the production move operation manually:
+
+```bash
+# Install dependencies
+pip install requests
+
+# Test with your GitHub token
+python ci/scripts/test_production_move.py --token YOUR_GITHUB_TOKEN
+
+# Test with different organization/project
+python ci/scripts/test_production_move.py \
+ --token YOUR_TOKEN \
+ --org YourOrganization \
+ --project 5
+```
+
+### Direct Script Usage
+
+You can also run the scripts directly:
+
+```bash
+# Process a specific issue
+python ci/scripts/issue.py -n 123 -t YOUR_TOKEN
+
+# Move project items to production
+python ci/scripts/move_to_production.py -t YOUR_TOKEN -o EducationalTools -p 4
+```
+
+## Dependencies
+
+- `requests` - HTTP client for GitHub API calls
+- `googlesearch-python` - For searching game links (issue.py only)
+
+## Error Handling
+
+The scripts include error handling for common scenarios:
+
+- Invalid tokens or permissions
+- Missing projects or fields
+- Network issues
+- GraphQL API errors
+
+## GraphQL Queries
+
+The project automation uses GitHub's GraphQL API v4 for efficient data retrieval and mutations. Key operations:
+
+1. **Project Data Query** - Gets project ID and field information
+2. **Items Query** - Retrieves all project items with their status values
+3. **Update Mutation** - Changes item status from "Done" to "In Production"
+
+## Future Enhancements
+
+Potential improvements:
+
+- Dry-run mode for testing changes
+- Support for custom field names
+- Better error reporting and logging
+- Slack/Discord notifications
+- Rollback capabilities
diff --git a/ci/scripts/move_to_production.py b/ci/scripts/move_to_production.py
new file mode 100644
index 00000000..89e1e7ca
--- /dev/null
+++ b/ci/scripts/move_to_production.py
@@ -0,0 +1,224 @@
+# Vibecoded because I hate graphql
+
+import argparse
+import requests
+import json
+
+parser = argparse.ArgumentParser(description='Move project items from Done to In Production')
+parser.add_argument('-t', '--token', type=str, help='GitHub token', required=True)
+parser.add_argument('-o', '--org', type=str, help='Organization name', default='EducationalTools')
+parser.add_argument('-p', '--project', type=int, help='Project number', default=4)
+args = parser.parse_args()
+
+def graphql_request(query, variables=None):
+ """Make a GraphQL request to GitHub API"""
+ headers = {
+ "Authorization": f"Bearer {args.token}",
+ "Content-Type": "application/json"
+ }
+
+ data = {"query": query}
+ if variables:
+ data["variables"] = variables
+
+ response = requests.post("https://api.github.com/graphql",
+ headers=headers,
+ json=data)
+
+ if response.status_code != 200:
+ print(f"GraphQL request failed: {response.status_code}")
+ print(response.text)
+ exit(1)
+
+ return response.json()
+
+def get_project_data():
+ """Get project ID and field information"""
+ print(f"Getting project data for {args.org} project #{args.project}")
+
+ query = """
+ query($org: String!, $number: Int!) {
+ organization(login: $org) {
+ projectV2(number: $number) {
+ id
+ fields(first: 20) {
+ nodes {
+ ... on ProjectV2Field {
+ id
+ name
+ }
+ ... on ProjectV2SingleSelectField {
+ id
+ name
+ options {
+ id
+ name
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ """
+
+ variables = {
+ "org": args.org,
+ "number": args.project
+ }
+
+ result = graphql_request(query, variables)
+
+ if not result.get("data", {}).get("organization", {}).get("projectV2"):
+ print(f"Project {args.project} not found in organization {args.org}")
+ exit(1)
+
+ project_data = result["data"]["organization"]["projectV2"]
+ project_id = project_data["id"]
+
+ # Find Status field and its options
+ status_field_id = None
+ done_option_id = None
+ in_production_option_id = None
+
+ for field in project_data["fields"]["nodes"]:
+ if field["name"] == "Status" and "options" in field:
+ status_field_id = field["id"]
+ for option in field["options"]:
+ if option["name"] == "Done":
+ done_option_id = option["id"]
+ elif option["name"] == "In Production":
+ in_production_option_id = option["id"]
+ break
+
+ if not status_field_id:
+ print("Status field not found in project")
+ exit(1)
+
+ if not done_option_id:
+ print("'Done' status option not found")
+ exit(1)
+
+ if not in_production_option_id:
+ print("'In Production' status option not found")
+ exit(1)
+
+ return {
+ "project_id": project_id,
+ "status_field_id": status_field_id,
+ "done_option_id": done_option_id,
+ "in_production_option_id": in_production_option_id
+ }
+
+def get_done_items(project_id, status_field_id, done_option_id):
+ """Get all items with Status = Done"""
+ print("Finding items with status 'Done'")
+
+ query = """
+ query($project_id: ID!) {
+ node(id: $project_id) {
+ ... on ProjectV2 {
+ items(first: 100) {
+ nodes {
+ id
+ fieldValues(first: 20) {
+ nodes {
+ ... on ProjectV2ItemFieldSingleSelectValue {
+ field {
+ ... on ProjectV2SingleSelectField {
+ id
+ name
+ }
+ }
+ optionId
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ """
+
+ variables = {"project_id": project_id}
+ result = graphql_request(query, variables)
+
+ done_items = []
+ items = result["data"]["node"]["items"]["nodes"]
+
+ for item in items:
+ for field_value in item["fieldValues"]["nodes"]:
+ if (field_value.get("field", {}).get("id") == status_field_id and
+ field_value.get("optionId") == done_option_id):
+ done_items.append(item["id"])
+ break
+
+ print(f"Found {len(done_items)} items with status 'Done'")
+ return done_items
+
+def update_item_status(project_id, item_id, status_field_id, new_status_option_id):
+ """Update a single item's status"""
+ query = """
+ mutation($project_id: ID!, $item_id: ID!, $field_id: ID!, $option_id: String!) {
+ updateProjectV2ItemFieldValue(input: {
+ projectId: $project_id
+ itemId: $item_id
+ fieldId: $field_id
+ value: {
+ singleSelectOptionId: $option_id
+ }
+ }) {
+ projectV2Item {
+ id
+ }
+ }
+ }
+ """
+
+ variables = {
+ "project_id": project_id,
+ "item_id": item_id,
+ "field_id": status_field_id,
+ "option_id": new_status_option_id
+ }
+
+ result = graphql_request(query, variables)
+ return result["data"]["updateProjectV2ItemFieldValue"]["projectV2Item"]["id"]
+
+def main():
+ # Get project data and field IDs
+ project_data = get_project_data()
+
+ # Find all items with status "Done"
+ done_items = get_done_items(
+ project_data["project_id"],
+ project_data["status_field_id"],
+ project_data["done_option_id"]
+ )
+
+ if not done_items:
+ print("No items found with status 'Done'. Nothing to update.")
+ return
+
+ # Update each item to "In Production"
+ print(f"Updating {len(done_items)} items to 'In Production' status")
+
+ updated_count = 0
+ for item_id in done_items:
+ try:
+ update_item_status(
+ project_data["project_id"],
+ item_id,
+ project_data["status_field_id"],
+ project_data["in_production_option_id"]
+ )
+ updated_count += 1
+ print(f"Updated item {item_id}")
+ except Exception as e:
+ print(f"Failed to update item {item_id}: {e}")
+
+ print(f"Successfully updated {updated_count} items from 'Done' to 'In Production'")
+
+if __name__ == "__main__":
+ main()
diff --git a/ci/scripts/test_production_move.py b/ci/scripts/test_production_move.py
new file mode 100644
index 00000000..1a2a7b31
--- /dev/null
+++ b/ci/scripts/test_production_move.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+"""
+Test script to manually run the production move operation.
+This can be used to test the functionality before running it in the workflow.
+
+Usage:
+ python test_production_move.py --token YOUR_GITHUB_TOKEN
+
+You can also override the organization and project number:
+ python test_production_move.py --token YOUR_TOKEN --org YourOrg --project 5
+"""
+
+import argparse
+import sys
+import os
+
+# Add the current directory to the path so we can import move_to_production
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+from move_to_production import main as move_main, args as move_args
+
+def test_main():
+ parser = argparse.ArgumentParser(description='Test the production move operation')
+ parser.add_argument('-t', '--token', type=str, help='GitHub token', required=True)
+ parser.add_argument('-o', '--org', type=str, help='Organization name', default='EducationalTools')
+ parser.add_argument('-p', '--project', type=int, help='Project number', default=4)
+ parser.add_argument('--dry-run', action='store_true', help='Show what would be updated without making changes')
+
+ test_args = parser.parse_args()
+
+ # Override the global args in move_to_production module
+ move_args.token = test_args.token
+ move_args.org = test_args.org
+ move_args.project = test_args.project
+
+ print("=" * 60)
+ print("TESTING PRODUCTION MOVE OPERATION")
+ print("=" * 60)
+ print(f"Organization: {test_args.org}")
+ print(f"Project: #{test_args.project}")
+ print(f"Dry run: {test_args.dry_run}")
+ print("-" * 60)
+
+ if test_args.dry_run:
+ print("DRY RUN MODE - No actual changes will be made")
+ print("-" * 60)
+ # TODO: Implement dry run mode in move_to_production.py if needed
+
+ try:
+ move_main()
+ print("-" * 60)
+ print("✅ Test completed successfully!")
+ except Exception as e:
+ print("-" * 60)
+ print(f"❌ Test failed with error: {e}")
+ sys.exit(1)
+
+if __name__ == "__main__":
+ test_main()
\ No newline at end of file
diff --git a/components.json b/components.json
index dc58f0ae..d62f9959 100644
--- a/components.json
+++ b/components.json
@@ -1,8 +1,6 @@
{
"$schema": "https://next.shadcn-svelte.com/schema.json",
- "style": "default",
"tailwind": {
- "config": "tailwind.config.ts",
"css": "src/app.css",
"baseColor": "neutral"
},
@@ -10,8 +8,9 @@
"components": "$lib/components",
"utils": "$lib/utils",
"ui": "$lib/components/ui",
- "hooks": "$lib/hooks"
+ "hooks": "$lib/hooks",
+ "lib": "$lib"
},
"typescript": true,
- "registry": "https://next.shadcn-svelte.com/registry"
+ "registry": "https://tw3.shadcn-svelte.com/registry/default"
}
diff --git a/package.json b/package.json
index d402614c..0e37f2a7 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"lint": "prettier --check ."
},
"devDependencies": {
- "@lucide/svelte": "^0.508.0",
+ "@lucide/svelte": "^0.482.0",
"@sveltejs/adapter-auto": "^6.0.0",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.20.8",
@@ -22,15 +22,15 @@
"@tailwindcss/typography": "^0.5.16",
"@types/md5": "^2.3.5",
"autoprefixer": "^10.4.21",
- "bits-ui": "1.4.6",
+ "bits-ui": "1.8.0",
"clsx": "^2.1.1",
- "lucide-svelte": "^0.503.0",
- "mode-watcher": "^1.0.6",
+ "lucide-svelte": "^0.512.0",
+ "mode-watcher": "^1.0.7",
"prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11",
"svelte": "^5.28.2",
- "svelte-check": "^4.1.6",
+ "svelte-check": "^4.2.1",
"svelte-sonner": "^0.3.28",
"tailwind-merge": "^3.2.0",
"tailwind-variants": "^1.0.0",
@@ -43,6 +43,7 @@
"dependencies": {
"@friendofsvelte/tipex": "0.0.7",
"md5": "^2.3.0",
+ "posthog-js": "^1.249.4",
"svelte-persisted-store": "^0.12.0"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index de6592c0..bc889a74 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,13 +14,16 @@ importers:
md5:
specifier: ^2.3.0
version: 2.3.0
+ posthog-js:
+ specifier: ^1.249.4
+ version: 1.249.4
svelte-persisted-store:
specifier: ^0.12.0
version: 0.12.0(svelte@5.28.2)
devDependencies:
'@lucide/svelte':
- specifier: ^0.508.0
- version: 0.508.0(svelte@5.28.2)
+ specifier: ^0.482.0
+ version: 0.482.0(svelte@5.28.2)
'@sveltejs/adapter-auto':
specifier: ^6.0.0
version: 6.0.0(@sveltejs/kit@2.20.8(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.28.2)(vite@6.3.5(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.28.2)(vite@6.3.5(jiti@1.21.7)(yaml@2.7.0)))
@@ -43,17 +46,17 @@ importers:
specifier: ^10.4.21
version: 10.4.21(postcss@8.5.1)
bits-ui:
- specifier: 1.4.6
- version: 1.4.6(svelte@5.28.2)
+ specifier: 1.8.0
+ version: 1.8.0(svelte@5.28.2)
clsx:
specifier: ^2.1.1
version: 2.1.1
lucide-svelte:
- specifier: ^0.503.0
- version: 0.503.0(svelte@5.28.2)
+ specifier: ^0.512.0
+ version: 0.512.0(svelte@5.28.2)
mode-watcher:
- specifier: ^1.0.6
- version: 1.0.6(svelte@5.28.2)
+ specifier: ^1.0.7
+ version: 1.0.7(svelte@5.28.2)
prettier:
specifier: ^3.5.3
version: 3.5.3
@@ -67,8 +70,8 @@ importers:
specifier: ^5.28.2
version: 5.28.2
svelte-check:
- specifier: ^4.1.6
- version: 4.1.6(picomatch@4.0.2)(svelte@5.28.2)(typescript@5.8.3)
+ specifier: ^4.2.1
+ version: 4.2.1(picomatch@4.0.2)(svelte@5.28.2)(typescript@5.8.3)
svelte-sonner:
specifier: ^0.3.28
version: 0.3.28(svelte@5.28.2)
@@ -271,8 +274,8 @@ packages:
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
- '@internationalized/date@3.8.0':
- resolution: {integrity: sha512-J51AJ0fEL68hE4CwGPa6E0PO6JDaVLd8aln48xFCSy7CZkZc96dGEGmLs2OEEbBxcsVZtfrqkXJwI2/MSG8yKw==}
+ '@internationalized/date@3.8.1':
+ resolution: {integrity: sha512-PgVE6B6eIZtzf9Gu5HvJxRK3ufUFz9DhspELuhW/N0GuMGMTLvPQNRkHP2hTuP9lblOk+f+1xi96sPiPXANXAA==}
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
@@ -296,8 +299,8 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
- '@lucide/svelte@0.508.0':
- resolution: {integrity: sha512-yJZz7QMP4VvtyHlnjSIvM+DGyeCoZJlWMJJDm9K7op4Vf41Q5kguq25uXH8t9I5y0xT2aWpRlxbpvK9L0K1uRA==}
+ '@lucide/svelte@0.482.0':
+ resolution: {integrity: sha512-n2ycHU9cNcleRDwwpEHBJ6pYzVhHIaL3a+9dQa8kns9hB2g05bY+v2p2KP8v0pZwtNhYTHk/F2o2uZ1bVtQGhw==}
peerDependencies:
svelte: ^5
@@ -696,8 +699,8 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
- bits-ui@1.4.6:
- resolution: {integrity: sha512-EN2niBF9iBe03GzSJ64I369DA/pRdoC7sCKVAqIxMkxrk/ClfDurzNJkf4RMK6EFOxeqWzTVFJTGyPdmBAy6Lw==}
+ bits-ui@1.8.0:
+ resolution: {integrity: sha512-CXD6Orp7l8QevNDcRPLXc/b8iMVgxDWT2LyTwsdLzJKh9CxesOmPuNePSPqAxKoT59FIdU4aFPS1k7eBdbaCxg==}
engines: {node: '>=18', pnpm: '>=8.7.0'}
peerDependencies:
svelte: ^5.11.0
@@ -751,6 +754,9 @@ packages:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
+ core-js@3.42.0:
+ resolution: {integrity: sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==}
+
crelt@1.0.6:
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
@@ -761,6 +767,9 @@ packages:
crypt@0.0.2:
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
+ css.escape@1.5.1:
+ resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+
cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
@@ -833,14 +842,6 @@ packages:
fault@2.0.1:
resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==}
- fdir@6.4.3:
- resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==}
- peerDependencies:
- picomatch: ^3 || ^4
- peerDependenciesMeta:
- picomatch:
- optional: true
-
fdir@6.4.4:
resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
peerDependencies:
@@ -849,6 +850,9 @@ packages:
picomatch:
optional: true
+ fflate@0.4.8:
+ resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==}
+
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
@@ -976,8 +980,8 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
- lucide-svelte@0.503.0:
- resolution: {integrity: sha512-oT1idMbgJKCCLWI4U7bdUYUZqxS78fiTGJuKGZ5u0NJNyuiUErDu3G7sXkYpfDwwspeid7gZSjrlJbTINEfErw==}
+ lucide-svelte@0.512.0:
+ resolution: {integrity: sha512-uUWdklivKMCMAJPbLxsQrUKKvw5ZD1mhd7X8arBdHG7pFf2yc0LnSg/ATVoXjgNEpHLpoHuxY3hOp2pCSVunHw==}
peerDependencies:
svelte: ^3 || ^4 || ^5.0.0-next.42
@@ -1010,8 +1014,8 @@ packages:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
- mode-watcher@1.0.6:
- resolution: {integrity: sha512-6bG6KfPPaZoaw523rLR3z8dlCK/dskIBv7z7qdRPizD5b5BDYyCCLQ33FSCRTd7Ai3i7FWIBuXCZaF5IVVC3GQ==}
+ mode-watcher@1.0.7:
+ resolution: {integrity: sha512-ZGA7ZGdOvBJeTQkzdBOnXSgTkO6U6iIFWJoyGCTt6oHNg9XP9NBvS26De+V4W2aqI+B0yYXUskFG2VnEo3zyMQ==}
peerDependencies:
svelte: ^5.27.0
@@ -1143,6 +1147,20 @@ packages:
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
engines: {node: ^10 || ^12 || >=14}
+ posthog-js@1.249.4:
+ resolution: {integrity: sha512-Qq4cxDZ1P9BkwguuoVNTiLGQiET9vrzwjYWLS3DduKhRXqEzERLl9tOq2X8ZNPbo+D207+FILdWg/dTKUItfDg==}
+ peerDependencies:
+ '@rrweb/types': 2.0.0-alpha.17
+ rrweb-snapshot: 2.0.0-alpha.17
+ peerDependenciesMeta:
+ '@rrweb/types':
+ optional: true
+ rrweb-snapshot:
+ optional: true
+
+ preact@10.26.8:
+ resolution: {integrity: sha512-1nMfdFjucm5hKvq0IClqZwK4FJkGXhRrQstOQ3P4vp8HxKrJEMFcY6RdBRVTdfQS/UlnX6gfbPuTvaqx/bDoeQ==}
+
prettier-plugin-svelte@3.3.3:
resolution: {integrity: sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==}
peerDependencies:
@@ -1358,8 +1376,8 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
- style-to-object@1.0.8:
- resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==}
+ 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==}
@@ -1370,8 +1388,8 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
- svelte-check@4.1.6:
- resolution: {integrity: sha512-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg==}
+ svelte-check@4.2.1:
+ resolution: {integrity: sha512-e49SU1RStvQhoipkQ/aonDhHnG3qxHSBtNfBRb9pxVXoa+N7qybAo32KgA9wEb2PCYFNaDg7bZCdhLD1vHpdYA==}
engines: {node: '>= 18.0.0'}
hasBin: true
peerDependencies:
@@ -1526,6 +1544,9 @@ packages:
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
+ web-vitals@4.2.4:
+ resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==}
+
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -1661,7 +1682,7 @@ snapshots:
'@iconify/types@2.0.0': {}
- '@internationalized/date@3.8.0':
+ '@internationalized/date@3.8.1':
dependencies:
'@swc/helpers': 0.5.17
@@ -1691,7 +1712,7 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
- '@lucide/svelte@0.508.0(svelte@5.28.2)':
+ '@lucide/svelte@0.482.0(svelte@5.28.2)':
dependencies:
svelte: 5.28.2
@@ -2061,11 +2082,12 @@ snapshots:
binary-extensions@2.3.0: {}
- bits-ui@1.4.6(svelte@5.28.2):
+ bits-ui@1.8.0(svelte@5.28.2):
dependencies:
'@floating-ui/core': 1.7.0
'@floating-ui/dom': 1.7.0
- '@internationalized/date': 3.8.0
+ '@internationalized/date': 3.8.1
+ css.escape: 1.5.1
esm-env: 1.2.2
runed: 0.23.4(svelte@5.28.2)
svelte: 5.28.2
@@ -2121,6 +2143,8 @@ snapshots:
cookie@0.6.0: {}
+ core-js@3.42.0: {}
+
crelt@1.0.6: {}
cross-spawn@7.0.6:
@@ -2131,6 +2155,8 @@ snapshots:
crypt@0.0.2: {}
+ css.escape@1.5.1: {}
+
cssesc@3.0.0: {}
debug@4.4.0:
@@ -2209,14 +2235,12 @@ snapshots:
dependencies:
format: 0.2.2
- fdir@6.4.3(picomatch@4.0.2):
- optionalDependencies:
- picomatch: 4.0.2
-
fdir@6.4.4(picomatch@4.0.2):
optionalDependencies:
picomatch: 4.0.2
+ fflate@0.4.8: {}
+
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
@@ -2328,7 +2352,7 @@ snapshots:
lru-cache@10.4.3: {}
- lucide-svelte@0.503.0(svelte@5.28.2):
+ lucide-svelte@0.512.0(svelte@5.28.2):
dependencies:
svelte: 5.28.2
@@ -2366,7 +2390,7 @@ snapshots:
minipass@7.1.2: {}
- mode-watcher@1.0.6(svelte@5.28.2):
+ mode-watcher@1.0.7(svelte@5.28.2):
dependencies:
runed: 0.25.0(svelte@5.28.2)
svelte: 5.28.2
@@ -2469,6 +2493,15 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
+ posthog-js@1.249.4:
+ dependencies:
+ core-js: 3.42.0
+ fflate: 0.4.8
+ preact: 10.26.8
+ web-vitals: 4.2.4
+
+ preact@10.26.8: {}
+
prettier-plugin-svelte@3.3.3(prettier@3.5.3)(svelte@5.28.2):
dependencies:
prettier: 3.5.3
@@ -2691,7 +2724,7 @@ snapshots:
dependencies:
ansi-regex: 6.1.0
- style-to-object@1.0.8:
+ style-to-object@1.0.9:
dependencies:
inline-style-parser: 0.2.4
@@ -2707,11 +2740,11 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
- svelte-check@4.1.6(picomatch@4.0.2)(svelte@5.28.2)(typescript@5.8.3):
+ svelte-check@4.2.1(picomatch@4.0.2)(svelte@5.28.2)(typescript@5.8.3):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
chokidar: 4.0.3
- fdir: 6.4.3(picomatch@4.0.2)
+ fdir: 6.4.4(picomatch@4.0.2)
picocolors: 1.1.1
sade: 1.8.1
svelte: 5.28.2
@@ -2731,7 +2764,7 @@ snapshots:
dependencies:
clsx: 2.1.1
runed: 0.23.4(svelte@5.28.2)
- style-to-object: 1.0.8
+ style-to-object: 1.0.9
svelte: 5.28.2
svelte@5.28.2:
@@ -2857,6 +2890,8 @@ snapshots:
w3c-keyname@2.2.8: {}
+ web-vitals@4.2.4: {}
+
which@2.0.2:
dependencies:
isexe: 2.0.0
diff --git a/src/app.css b/src/app.css
index ce13eea5..d8feddc4 100644
--- a/src/app.css
+++ b/src/app.css
@@ -352,6 +352,7 @@
@layer base {
* {
@apply border-border;
+ --sidebar-width: 288px;
}
body {
@apply bg-background text-foreground;
diff --git a/src/hooks.client.ts b/src/hooks.client.ts
new file mode 100644
index 00000000..9803f880
--- /dev/null
+++ b/src/hooks.client.ts
@@ -0,0 +1,8 @@
+import posthog from 'posthog-js';
+import type { HandleClientError } from '@sveltejs/kit';
+
+export const handleError: HandleClientError = ({ error, status }) => {
+ if (status !== 404) {
+ posthog.captureException(error);
+ }
+};
diff --git a/src/lib/components/app-sidebar.svelte b/src/lib/components/app-sidebar.svelte
index 37a79771..3a491a4f 100644
--- a/src/lib/components/app-sidebar.svelte
+++ b/src/lib/components/app-sidebar.svelte
@@ -209,12 +209,19 @@
{item.title}
+
{/snippet}
diff --git a/src/lib/components/ui/dialog/dialog-content.svelte b/src/lib/components/ui/dialog/dialog-content.svelte
index 1fccd39d..e94126fd 100644
--- a/src/lib/components/ui/dialog/dialog-content.svelte
+++ b/src/lib/components/ui/dialog/dialog-content.svelte
@@ -1,6 +1,6 @@
f)return;l>h&&(h=l,r=u)}q=r;l=k[q];p=k[q+1
=(d-l.x)*(p.x-l.x)+(c-l.y)*(p.y-l.y)){if((d-l.x)*(d-l.x)+(c-l.y)*(c-l.y)>f*f)return;a.m_pointCount=1;a.m_type=2;a.m_localPlaneNormal.x=d-l.x;a.m_localPlaneNormal.y=c-l.y;a.m_localPlaneNormal.normalize();d=
+a.m_localPoint;d.x=l.x;d.y=l.y}else if(0>=h){if((d-p.x)*(d-p.x)+(c-p.y)*(c-p.y)>f*f)return;a.m_pointCount=1;a.m_type=2;a.m_localPlaneNormal.x=d-p.x;a.m_localPlaneNormal.y=c-p.y;a.m_localPlaneNormal.normalize();d=a.m_localPoint;d.x=p.x;d.y=p.y}else{r=.5*(l.x+p.x);l=.5*(l.y+p.y);h=(d-r)*b[q].x+(c-l)*b[q].y;if(h>f)return;a.m_pointCount=1;a.m_type=2;a.m_localPlaneNormal.x=b[q].x;a.m_localPlaneNormal.y=b[q].y;a.m_localPlaneNormal.normalize();d=a.m_localPoint;c=r;f=l;null==f&&(f=0);null==c&&(c=0);d.x=c;
+d.y=f}d=a.m_points[0].m_localPoint;c=e.m_p;d.x=c.x;d.y=c.y;a.m_points[0].m_id.set_key(0)};G.testOverlap=function(a,b){var d=b.lowerBound,e=a.upperBound,f=d.x-e.x,c=d.y-e.y;d=a.lowerBound;e=b.upperBound;a=d.y-e.y;return 0 k)e.setTileAt(c,g,null,!1);else{var u=n.tiles[k];if(null==u)e.setTileAt(c,g,null,!1);else if(e.setTileAt(c,g,u,!1),e.autotileData[c][g]=y,0<=u.collisionID&&l.setTile(g,c,!0),1=a?this.m_count=this.m_v1.a=1:(b=b.x*d.x+b.y*d.y,0>=b?(this.m_count=this.m_v2.a=1,this.m_v1.set(this.m_v2)):(d=1/(b+a),this.m_v1.a=b*d,this.m_v2.a=a*d,this.m_count=2))},solve3:function(){var a=this.m_v1.w,b=this.m_v2.w,d=this.m_v3.w,e=R.subtractVVPooled(b,
+a),f=R.dot(a,e),c=R.dot(b,e);f=-f;var l=R.subtractVVPooled(d,a),q=R.dot(a,l),y=R.dot(d,l);q=-q;var r=R.subtractVVPooled(d,b),h=R.dot(b,r);r=R.dot(d,r);h=-h;l=R.crossVV(e,l);e=l*R.crossVV(b,d);d=l*R.crossVV(d,a);a=l*R.crossVV(a,b);0>=f&&0>=q?this.m_count=this.m_v1.a=1:0
y||q
d&&(b=c,d=l)}return b},getSupportVertex:function(a){for(var b=0,d=this.m_vertices[0].x*a.x+this.m_vertices[0].y*a.y,e=1,f=this.m_vertexCount;e<
+f;){var c=e++,l=this.m_vertices[c].x*a.x+this.m_vertices[c].y*a.y;l>d&&(b=c,d=l)}return this.m_vertices[b]},validate:function(){return!1},reserve:function(a){for(var b=this.m_vertices.length;bb?a:b};Z.b2Assert=function(a){if(!a)throw J.thrown("Assertion Failed");};var Jh=function(a,b,d){this.col1=new Ve;this.col2=new Ve;this.col3=new Ve;null==a&&null==b&&null==d?(this.col1.setZero(),this.col2.setZero(),this.col3.setZero()):(this.col1.setV(a),this.col2.setV(b),this.col3.setV(d))};k["box2D.common.math.B2Mat33"]=Jh;
+Jh.__name__="box2D.common.math.B2Mat33";Jh.prototype={setVVV:function(a,b,d){this.col1.setV(a);this.col2.setV(b);this.col3.setV(d)},copy:function(){return new Jh(this.col1,this.col2,this.col3)},setM:function(a){this.col1.setV(a.col1);this.col2.setV(a.col2);this.col3.setV(a.col3)},addM:function(a){this.col1.x+=a.col1.x;this.col1.y+=a.col1.y;this.col1.z+=a.col1.z;this.col2.x+=a.col2.x;this.col2.y+=a.col2.y;this.col2.z+=a.col2.z;this.col3.x+=a.col3.x;this.col3.y+=a.col3.y;this.col3.z+=a.col3.z},setIdentity:function(){this.col1.x=
+1;this.col2.x=0;this.col3.x=0;this.col1.y=0;this.col2.y=1;this.col3.y=0;this.col1.z=0;this.col2.z=0;this.col3.z=1},setZero:function(){this.col1.x=0;this.col2.x=0;this.col3.x=0;this.col1.y=0;this.col2.y=0;this.col3.y=0;this.col1.z=0;this.col2.z=0;this.col3.z=0},solve22:function(a,b,d){var e=this.col1.x,f=this.col2.x,c=this.col1.y,l=this.col2.y,q=e*l-f*c;0!=q&&(q=1/q);a.x=q*(l*b-f*d);a.y=q*(e*d-c*b);return a},solve33:function(a,b,d,e){var f=this.col1.x,c=this.col1.y,l=this.col1.z,q=this.col2.x,y=this.col2.y,
+r=this.col2.z,h=this.col3.x,p=this.col3.y,k=this.col3.z,n=f*(y*k-r*p)+c*(r*h-q*k)+l*(q*p-y*h);0!=n&&(n=1/n);a.x=n*(b*(y*k-r*p)+d*(r*h-q*k)+e*(q*p-y*h));a.y=n*(f*(d*k-e*p)+c*(e*h-b*k)+l*(b*p-d*h));a.z=n*(f*(y*e-r*d)+c*(r*b-q*e)+l*(q*d-y*b));return a},col1:null,col2:null,col3:null,__class__:Jh};var R=function(){};k["box2D.common.math.B2Math"]=R;R.__name__="box2D.common.math.B2Math";R.__properties__={get_MIN_VALUE:"get_MIN_VALUE",get_MAX_VALUE:"get_MAX_VALUE"};R.isValid=function(a){return isNaN(a)||
+-Infinity==a||Infinity==a?!1:!0};R.dot=function(a,b){return a.x*b.x+a.y*b.y};R.crossVV=function(a,b){return a.x*b.y-a.y*b.x};R.crossVF=function(a,b,d){null==d&&(d=!1);if(d){d=P.getFromPool();var e=b*a.y;a=-b*a.x;null==a&&(a=0);null==e&&(e=0);d.x=e;d.y=a}else d=new P(b*a.y,-b*a.x);return d};R.crossFV=function(a,b,d){null==d&&(d=!1);if(d){d=P.getFromPool();var e=-a*b.y;a*=b.x;null==a&&(a=0);null==e&&(e=0);d.x=e;d.y=a}else d=new P(-a*b.y,a*b.x);return d};R.mulMV=function(a,b,d){null==d&&(d=!1);if(d){d=
+P.getFromPool();var e=a.col1.x*b.x+a.col2.x*b.y;a=a.col1.y*b.x+a.col2.y*b.y;null==a&&(a=0);null==e&&(e=0);d.x=e;d.y=a}else d=new P(a.col1.x*b.x+a.col2.x*b.y,a.col1.y*b.x+a.col2.y*b.y);return d};R.mulTMV=function(a,b,d){null==d&&(d=!1);if(d){d=P.getFromPool();var e=R.dot(b,a.col1);a=R.dot(b,a.col2);null==a&&(a=0);null==e&&(e=0);d.x=e;d.y=a}else d=new P(R.dot(b,a.col1),R.dot(b,a.col2));return d};R.mulX=function(a,b,d){null==d&&(d=!1);b=R.mulMV(a.R,b,d);b.x+=a.position.x;b.y+=a.position.y;return b};
+R.mulXT=function(a,b,d){b=R.subtractVVPooled(b,a.position);d=b.x*a.R.col1.x+b.y*a.R.col1.y;b.y=b.x*a.R.col2.x+b.y*a.R.col2.y;b.x=d;return b};R.addVV=function(a,b){return new P(a.x+b.x,a.y+b.y)};R.subtractVV=function(a,b){return new P(a.x-b.x,a.y-b.y)};R.subtractVVPooled=function(a,b){var d=P.getFromPool(),e=a.x-b.x;a=a.y-b.y;null==a&&(a=0);null==e&&(e=0);d.x=e;d.y=a;return d};R.distance=function(a,b){var d=a.x-b.x;a=a.y-b.y;return Math.sqrt(d*d+a*a)};R.distanceSquared=function(a,b){var d=a.x-b.x;
+a=a.y-b.y;return d*d+a*a};R.mulFV=function(a,b){return new P(a*b.x,a*b.y)};R.addMM=function(a,b){return yc.fromVV(R.addVV(a.col1,b.col1),R.addVV(a.col2,b.col2))};R.mulMM=function(a,b){return yc.fromVV(R.mulMV(a,b.col1),R.mulMV(a,b.col2))};R.mulTMM=function(a,b){var d=new P(R.dot(a.col1,b.col1),R.dot(a.col2,b.col1));a=new P(R.dot(a.col1,b.col2),R.dot(a.col2,b.col2));return yc.fromVV(d,a)};R.abs=function(a){return 0b?a:b};R.maxV=function(a,b){return new P(R.max(a.x,b.x),R.max(a.y,b.y))};R.clamp=function(a,b,d){return ad?d:a};R.clampV=function(a,b,d){return R.maxV(b,R.minV(a,d))};R.swap=function(a,b){var d=a[0];a[0]=b[0];b[0]=d};R.random=function(){return 2*Math.random()-1};R.randomRange=function(a,b){return(b-a)*Math.random()+a};R.nextPowerOfTwo=function(a){a|=
+a>>1&2147483647;a|=a>>2&1073741823;a|=a>>4&268435455;a|=a>>8&16777215;return(a|a>>16&65535)+1};R.isPowerOfTwo=function(a){return 0Number.MIN_VALUE){var b=(a-this.t0)/(1-this.t0);this.c0.x=(1-b)*this.c0.x+b*this.c.x;this.c0.y=(1-b)*this.c0.y+b*this.c.y;this.a0=(1-b)*this.a0+b*this.a;this.t0=a}},localCenter:null,c0:null,c:null,a0:null,a:null,t0:null,__class__:lh};var Ve=function(a,b,d){null==d&&(d=0);null==b&&(b=0);null==a&&(a=0);this.x=a;this.y=b;this.z=d};k["box2D.common.math.B2Vec3"]=Ve;Ve.__name__="box2D.common.math.B2Vec3";Ve.prototype=
+{setZero:function(){this.x=this.y=this.z=0},set:function(a,b,d){this.x=a;this.y=b;this.z=d},setV:function(a){this.x=a.x;this.y=a.y;this.z=a.z},getNegative:function(){return new Ve(-this.x,-this.y,-this.z)},negativeSelf:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z},copy:function(){return new Ve(this.x,this.y,this.z)},add:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z},subtract:function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z},multiply:function(a){this.x*=a;this.y*=a;this.z*=a},x:null,y:null,
+z:null,__class__:Ve};var va=function(a,b){this.m_xf=new Ue;this.m_sweep=new lh;this.m_linearVelocity=new P;this.m_force=new P;this.m_flags=0;a.bullet&&(this.m_flags|=va.e_bulletFlag);a.fixedRotation&&(this.m_flags|=va.e_fixedRotationFlag);a.allowSleep&&(this.m_flags|=va.e_allowSleepFlag);a.awake&&(this.m_flags|=va.e_awakeFlag);a.active&&(this.m_flags|=va.e_activeFlag);a.ignoreGravity&&(this.m_flags|=va.e_ignoreGravityFlag);this.m_world=b;b=this.m_xf.position;var d=a.position;b.x=d.x;b.y=d.y;this.m_xf.R.set(a.angle);
+b=this.m_sweep.localCenter;b.x=0;b.y=0;this.m_sweep.t0=1;this.m_sweep.a0=this.m_sweep.a=a.angle;b=this.m_xf.R;d=this.m_sweep.localCenter;this.m_sweep.c.x=b.col1.x*d.x+b.col2.x*d.y;this.m_sweep.c.y=b.col1.y*d.x+b.col2.y*d.y;this.m_sweep.c.x+=this.m_xf.position.x;this.m_sweep.c.y+=this.m_xf.position.y;b=this.m_sweep.c0;d=this.m_sweep.c;b.x=d.x;b.y=d.y;this.m_contactList=this.m_controllerList=this.m_jointList=null;this.m_controllerCount=0;this.m_next=this.m_prev=null;b=this.m_linearVelocity;d=a.linearVelocity;
+b.x=d.x;b.y=d.y;this.m_angularVelocity=a.angularVelocity;this.m_linearDamping=a.linearDamping;this.m_angularDamping=a.angularDamping;b=this.m_force;var e=d=0;null==e&&(e=0);null==d&&(d=0);b.x=d;b.y=e;this.m_sleepTime=this.m_torque=0;this.m_type=a.type;this.m_invMass=this.m_type==va.b2_dynamicBody?this.m_mass=1:this.m_mass=0;this.m_invI=this.m_I=0;this.m_inertiaScale=a.inertiaScale;this.m_userData=a.userData;this.m_fixtureList=null;this.m_fixtureCount=0;this.groupID=a.groupID;this.origin=new P;this.size=
+new P};k["box2D.dynamics.B2Body"]=va;va.__name__="box2D.dynamics.B2Body";va.prototype={connectEdges:function(a,b,d){var e=Math.atan2(b.getDirectionVector().y,b.getDirectionVector().x);d=R.mulFV(Math.tan(.5*(e-d)),b.getDirectionVector());d=R.subtractVV(d,b.getNormalVector());d=R.mulFV(Z.b2_toiSlop,d);d=R.addVV(d,b.getVertex1());var f=R.addVV(a.getDirectionVector(),b.getDirectionVector());f.normalize();var c=0
"+this.memStr+"
"+this.memMaxStr+"")):(this.fps++,this.ms=this.timer)},normalizeMem:function(a){return Math.min(50,Math.sqrt(Math.sqrt(5E3*a)))-2|0},__class__:Qg});var xg=function(){};k["com.nmefermmmtools.debug.Colors"]=xg;xg.__name__="com.nmefermmmtools.debug.Colors";var yg=function(){};k["com.stencyl.APIKeys"]=yg;yg.__name__="com.stencyl.APIKeys";var ba=function(){};k["com.stencyl.Config"]=ba;ba.__name__="com.stencyl.Config";
+ba.load=function(){var a=W.getConfigText("config/game-config.json");ba.loadFromString(a)};ba.loadMap=function(a,b){for(var d=0,e=aa.fields(a);d>16&255)/255,(d>>8&255)/255,(d&255)/255)):a.draw(f);f.removeTiles()},toARGB:function(a,b){return a+(b<<24)},getTextWidth:function(a,b,d){null==d&&(d=1);null==b&&(b=0);for(var e=0,c=0,g=a.length,l=0;l
=this.model.durations[this.currIndex]&&(this.currTime=0,this.currIndex++,this.currIndex>=this.frameCount&&(this.currIndex=0),this.bgChild instanceof Mf?(this.cacheIndex=this.currIndex,this.model.repeats&&this.model.drawRepeated(this,h.screenWidth*h.SCALE|0,h.screenHeight*h.SCALE|0),this.currIndex=this.cacheIndex,a=this.bgChild.image1,a.set_bitmapData(this.model.frames[this.currIndex]),this.model.repeats&&(a=this.bgChild.image2,a.set_bitmapData(this.model.frames[this.currIndex]),
+a=this.bgChild.image3,a.set_bitmapData(this.model.frames[this.currIndex]),a=this.bgChild.image4,a.set_bitmapData(this.model.frames[this.currIndex]),a=this.bgChild.image5,a.set_bitmapData(this.model.frames[this.currIndex]),a=this.bgChild.image6,a.set_bitmapData(this.model.frames[this.currIndex]),a=this.bgChild.image7,a.set_bitmapData(this.model.frames[this.currIndex]),a=this.bgChild.image8,a.set_bitmapData(this.model.frames[this.currIndex]),a=this.bgChild.image9,a.set_bitmapData(this.model.frames[this.currIndex]))):
+this.bitmap.set_bitmapData(this.model.frames[this.currIndex]))},updatePosition:function(a,b,d){this.bgChild instanceof Mf?w.__cast(this.bgChild,Mf).update(a,b,d):(this.set_x(-(a*this.scrollFactorX|0)),this.set_y(-(b*this.scrollFactorY|0)));this.isAnimated&&this.updateAnimation(d)},getBitmap:function(){return this.bgChild},__class__:Wd});var Oc=function(a,b,d,e){null==e&&(e=0);null==d&&(d=0);null==b&&(b=0);null==a&&(a=0);this.a=a;this.r=b;this.g=d;this.b=e};k["com.stencyl.utils.ARGB"]=Oc;Oc.__name__=
+"com.stencyl.utils.ARGB";Oc.setARGBi=function(a,b,d,e){return(a&255)<<24|(b&255)<<16|(d&255)<<8|e&255};Oc.setARGBf=function(a,b,d,e){a=255*(0>a?0:1b?0:1d?0:1
a||a>=this.cache.length)throw J.thrown("Invalid reference");return this.cache[a];case 115:a=
+this.readDigits();d=this.buf;if(58!=this.buf.charCodeAt(this.pos++)||this.length-this.pos>2)+(2<=f?f-1:0)));for(q=0;b